Servo breaks Ping Sensor??

Hi Guys

So first off: This code you see is a merge of the original Arduino Example Codes in Arduino IDE Called

  1. Servo → Sweep.ino
  2. Sensors → Ping.ino

So it’s very unlikely there’s something wrong with the code.

The Code itself does work seperately. Meaning:

If i just call the Ping() function, it works as it should (Ping and print values)

The Servo function without the Ping does work as well, and swipes 180° and back clean.

The problem comes when i mix them both together. The servo jumps a moves a few degrees, pings every time it moves, but then suddenly stops and does nothing for a few seconds.

It’s like the for-loop “freezes” for 2-3 seconds before it’s 180 degrees. Then it continues at the same point it stopped (so it does not reset to zero) and goes on a few intervals, until it freezes again.

Eventually it gets to 180 degrees and starts turning back, but wiht random freezes all the time.

The Servo, as well as The Ping-Sensor are connected to the 5v Output of the Arduino. Is that a problem?

If yes, how does a Parallax Boebot work with 3 Servos and a Ping Sensor directly connected to Arduino 5V output?

#include <Servo.h> 
 
Servo sweep; 
int pos = 0;
int increment = 1;

const int pingPin = 7;

long duration, cm;
  
void setup() {
  
  Serial.begin(9600);
  
  sweep.attach(6);
  
}

void loop(){
  

  for(pos = 0; pos <= 180; pos += 10)  
  {                                  
    ping();
    sweep.write(pos); 
    delay(55);    
  } 
  for(pos = 180; pos>=0; pos-=10)   
  {                                
    ping();
    sweep.write(pos); 
    delay(55);      
  } 

}

void ping(){

  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // convert the time into a distance
  cm = microsecondsToCentimeters(duration); 
 
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();  
  delay (20);
}


long microsecondsToCentimeters(long microseconds)
{
  return microseconds / 29 / 2;
}

I commented both For-Loops and and just wrote ping(); in the main loop - ping works Ok.

Then i did the opposite: Commented both Ping() in the For-Loops and it swiped OK.

It is the interaction of both functions that causes the problem.

Any ideas anyone?

The Servo, as well as The Ping-Sensor are connected to the 5v Output of the Arduino. Is that a problem?

Where does the 5V come from?

The USB Port mf my computer. I did hook up a battery pack - same issue.

What makes it so annoying is that both functions work perfectly fine on their own (meaning you comment the other one out). Put together, they 'freeze' every other second.

This is because your power supply is inadequate for the load it is being asked to run. That applies to both the USB and the battery pack.

So i broke it down. This line is causing it:

duration = pulseIn(pingPin, HIGH);

If I comment it out, stuff works as intended. Only problem: this is how the Ping-Values get read. :stuck_out_tongue:

@Grumpy_Mike: naah, I can run a pan/tilt with CMUCam without problems. I always take the power form Arduino. Never hooked up that much that it became a problem.

It sounds like pulseIn is timing-out

So this code works. Basically you have to put biiiig delays between servo movement and the ping. Then they don’t interfere with each other anymore.

#include <Servo.h> 

Servo sweeper;

const int pingPin = 7;

int pos = 0;

int delta;

long duration, cm;

void setup() {

  sweeper.attach(6);
  
  Serial.begin(9600);
}

void loop(){

  for(pos = 0; pos <= 180; pos += 5) 
  {                                 
    ping();
    delay(100);
    sweeper.write(pos);            
    delay(500);                     

  } 
  for(pos = 180; pos>=0; pos-=5)    
  {                                
    ping();
    delay(100);
    sweeper.write(pos);            
    delay(500);            
  } 

}  
  

  
void ping(){

  // The PING))) is triggered by a HIGH pulse of 2 or more microseconds.
  // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);

  // The same pin is used to read the signal from the PING))): a HIGH
  // pulse whose duration is the time (in microseconds) from the sending
  // of the ping to the reception of its echo off of an object.
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH);

  // convert the time into a distance
  cm = microsecondsToCentimeters(duration);

  Serial.print(cm);
  Serial.print("cm");
  Serial.println();

  delay(100);
  
}

long microsecondsToCentimeters(long microseconds)
{

  return microseconds / 29 / 2;
}

Thank you everyone for helping out!

Edit: if anyone can tell me why this solution works I’d be grateful. Is it the voltage that ‘recovers’ after servo movement?

I wonder if the Servo library and the ping() are incompatible - they may both be using the same Timer.

It may be worth trying the ServoTimer2 library.

...R

Is it the voltage that 'recovers' after servo movement?

Could be.