Servo + PING))) = pulseIn problem!

Hi everyone,

As my collegue Harm already posted in the software forum, we’re having problems getting a parallax PING))) sensor together with a standard (digital) servo: the whole program freezes for long periods, making the servo freeze, and stopping all serial communication: Bad! I’m trying to explain the situation a little more here, in hope someone can help:

I have so far nailed it down to
a) PING))) works fine on its own, with the shipped code example, and with this code
b) The servo runs fine on its own, with the standard Servo class, ServoTimer2 and the very basic no-classes-used-at-all solution you see below.
c) PulseIn has been determined as the source of the freezes: When this line is commented the ping)))'s results are unknown, but the servo runs normally.
d) When PulseIn gets a timeout of 500ms it almost always uses this completey. Without timeout we have the same, but then with the regular 1s timeout.

The code:

//sweep_ping zesbaans.nl 

#define MIN_PULSE   800
#define MAX_PULSE   2200
#define DELTA       10
#define pingPin     3
#define servoPin    2
#define ledPin      13

int pos = 850;
int delta = DELTA * -1;

boolean ledState = LOW;

void setup()
{
  Serial.begin(9600);
  pinMode(pingPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(servoPin, OUTPUT);
}

void loop()
{
  //this just makes the servo move up and down
  if (pos < MIN_PULSE) delta = DELTA;
  if (pos > MAX_PULSE) delta = -1 * DELTA;
  pos += delta;

  //Servo
  digitalWrite(servoPin, HIGH);  
  delayMicroseconds(pos);      
  digitalWrite(servoPin, LOW);    
  //Serial.println(pos);

  //Ping)))
  Serial.print(getDistance(), DEC);
  Serial.print(" - ");
  Serial.println(millis());
  delay(10);
}

byte getDistance(){
  
  digitalWrite(ledPin, HIGH); //switch led on to see start of getDistance cycle
  
  long duration=0;
  pinMode(pingPin, OUTPUT);
  digitalWrite(pingPin, LOW);
  delayMicroseconds(2);
  digitalWrite(pingPin, HIGH);
  delayMicroseconds(5);
  digitalWrite(pingPin, LOW);
  pinMode(pingPin, INPUT);
  duration = pulseIn(pingPin, HIGH, 500000);
  
  digitalWrite(ledPin, LOW); // switch led on to see end of getDistance cycle
  
  return duration / 29 / 2; // to centimeters
}

And the results this provides: notice the big amount of zeros, what could that mean? After the dash we have the millis() result to check how long we’ve been running. Of course this should just be in the range of 10 - 20 - 30, with a program delay of 10ms right?

81 - 9
0 - 562
80 - 587
0 - 1141
127 - 1171
126 - 1202
126 - 1232
126 - 1263
76 - 1290
0 - 1846
28 - 1869
0 - 2424
2 - 2444
0 - 3000
32 - 3023
0 - 3579
42 - 3604
0 - 4160
65 - 4186
0 - 4742
47 - 4766
0 - 5321
74 - 5347
0 - 5903
25 - 5926
0 - 6482
32 - 6506

Thanks in advance for any help you can provide!

are you saying that works ok if you run that code with these lines commented out?

  //Servo
  digitalWrite(servoPin, HIGH);  
  delayMicroseconds(pos);      
  digitalWrite(servoPin, LOW);

Yes, that is right. Commenting out either the servo control (whichever way we do that), or the pulsein makes the program run fine. We just cant get then to run in the same loop without pulsein causing gigantic delays…

Have you tried to run the sketch with the servo disconnected, perhaps the servo is drawing too much power.

[smiley=shocked.gif] of course, that was it. THANK YOU. It crossed my mind before, but just one simple servo without pulling any load yet drawing too much power seemed.. weird. However, with an external supply + reference-0 wire it works perfectly. crazy!

If I may, I would like to use your code. It is doing what i've been trying to figure out for a week. I am very new at this stuff, and I'm understanding most of what you're doing, but i don't see where to set the range of the sweeps? I'd like to go only, say, 45° or maybe 60° .

Other than that, it is working beautifully.

Thank you.

Hi Byron, no idea if you're still looking for an answer here, didn't check this page in a long time - sorry.

You can accomplish this by doing some simple calculation.

If a pulse of 800ms gives us a position of 0º, and 2200ms results in (about) 180º, then midway should be (2200-800=1400) / 2 + 800 = 1500ms. And a change of 45º needs a change in pulse of 1400/4 = 350ms.

Thus, a sweeping range of 45º around midpoint would have to be

define MIN_PULSE 1325

define MAX_PULSE 1675

Don't forget to change the starting int pos