Help in getting servos and PNG to run in sync

I'm trying program my PNG and servos to properly operate in sync. My servos are not modified so I'm simply trying to move them forward and backward while the PNG provides the distance measured in inches. When distance < 8 a function (or is it called a method?) is called to turn on the RED LED.

The code works successfully when separated...i.e. PNG will work without servos and servos will work without PNG...but when integrating the code, I get some strange output:

Running the code as you see it pretty much locks up the robot with the red light coming on and nothing else except some slight servo movement at startup.

In trying to troubleshoot where the problem might, lie, I disabled all the code associated with the right servo. That gives better results with the left servo going through its correct range of motion for one iteration only. The PNG does not appear to be operating through its normal cycle because the LED is not flashing like it should be.

Oddly, when I open the serial monitor, the left servo will go through its range of motion and will do so each time I open the monitor after closing it.

Running with USB power. Does my code below suggest any conflict?

 #include <Servo.h> 
 
Servo leftservo;  // create servo object to control a servo 
Servo rightservo;

 // this constant won't change.  It's the pin number
 // of the sensor's output:
 const int pingPin = 7;
 const int avoidPin = 3;
 const int avoidInch = 8;

 int right=0;
 int left=90;
 
 
 void setup() 
 {
   // initialize serial communication:
   Serial.begin(9600);
 
   pinMode (avoidPin, OUTPUT);  //establishes LED pin for indication of within the set number of inches

 leftservo.attach(9);  // attaches the left servo on pin 9 to the servo object  
 delay (1000);
 rightservo.attach(8); // ditto for right servo on pin 8

 }

 void loop()
 {
   // establish variables for duration of the ping, 
   // and the distance result in inches and centimeters:
   long duration, inches;

   // 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
   inches = microsecondsToInches(duration);
   Serial.println(inches);
   delay (50);
   digitalWrite(avoidPin,LOW);
 
   //drive servos
  rightservo.write(right);                  // sets the servo position according to the scaled value 
  leftservo.write(left);
  right=right++;
  left=left--;                       //motors mounted in opposite configuration, thus values need to be inverse of each other
  if (right==90) right=0;
  if (left==0) left=90;  

   
 //    test to see if object is within 'avoidinch' distance
 //    if (inches < avoidInch)
 //  {
 //     avoidance();  //call avoidance method
 //   }

}

 long microsecondsToInches(long microseconds)
 {
   // According to Parallax's datasheet for the PING))), there are
   // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
   // second).  This gives the distance travelled by the ping, outbound
   // and return, so we divide by 2 to get the distance of the obstacle.
   // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
   return microseconds / 74 / 2;
 }

void avoidance()
   {
     //stop wheels from turning, flash red light
     
     digitalWrite (avoidPin, HIGH);
    // consider here storing the the last value, panning the robot to the right, taking new value
    // if new value is less than old value, pan in opposite direction
    // delay(10);       
   }

My servos are not modified

Not modified for what?
What's "PNG"?

leftservo.attach(9);  // attaches the left servo on pin 9 to the servo object  
 delay (1000);
 rightservo.attach(8); // ditto for right servo on pin 8

Why the delay?

I think the problem is caused by delayMicrosconds disabling interrupts. This is being fixed in the next Arduino release. The thread here has code that provides a modifed of the delay function named _delayMicroseconds that you can try:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1258374756/25#25

AWOL, PNG is an ultrasonic distance sensor that provides a pulse width proportional to distance.

PNG is an ultrasonic distance sensor

Is that different to a Parallax PING?

Here's a video to better show what I'm working with:

The servos aren't modified for continuous rotation so I just have them set up to go forward and backward a short distance as a test to see if they are working proper.

The PNG is the Parallax ultrasonic sensor.

I'll try that replacement for the delaymicroseconds. What is the difference in using delay() command and delaymicroseconds()?

Sorry about the confusion in me referencing it as the PNG...I see now that the proper spelling is PING...my blind ass couldn't see it too good on the Parallax web site and I thought it was PNG. LOL

What is the difference in using delay() command and delaymicroseconds()?

Three orders of magnitude?

linusb, try dropping this function in your sketch and changed the calls from delayMicroseconds to _delayMicroseconds.

 void _delayMicroseconds(unsigned int us)
{

#if F_CPU >= 16000000L
      if (--us == 0)
            return;
      us <<= 2;
      us -= 2;
#else
      if (--us == 0)
            return;
      if (--us == 0)
            return;
      us <<= 1;  
      us--;
#endif
      // busy wait
      __asm__ __volatile__ (
            "1: sbiw %0,1" "\n\t" // 2 cycles
            "brne 1b" : "=w" (us) : "0" (us) // 2 cycles
      );
}

Hey Mem...I appreciate the help. I gave that a try but am getting the same result.

As a bit of an update, the code (as in original form or with the custom _delayMicroseconds routine works...but the servos are turning very slow...incrementally...and when they get to their limit, reset in normal fashion and then begin the very slow turning. Turning about 1 increment every second or so.

Much easier to diagnose issues like this if we could peek over your shoulder, and see your code.

Sure thing! This is the code and the video here shows what is happening:

#include <Servo.h> 
 
Servo leftservo;  // create servo object to control a servo 
Servo rightservo;

 int r=0;
 int l=90;

const int pingPin = 4;


void setup() 
{ 
  Serial.begin(9600);
  leftservo.attach(3);  // attaches the servo on pin 3 to the servo object 
  rightservo.attach(2);
} 
  
void loop() 
{ 
  Serial.println(r);
  delay(5);
  rightservo.write(r);                  // sets the servo position according to the scaled value 
  delay(5);
  leftservo.write(l);
  delay(5);
  r=r++;
  l=l--;
  if (r==90)
     {
      r=0;
      l=90;
     }
  
   // establish variables for duration of the ping, 
   // and the distance result in inches and centimeters:
 long duration, inches;

   // 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
   //  inches = microsecondsToInches(duration);
 }

 long microsecondsToInches(long microseconds)
 {
   // According to Parallax's datasheet for the PING))), there are
   // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per
   // second).  This gives the distance travelled by the ping, outbound
   // and return, so we divide by 2 to get the distance of the obstacle.
   // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf
   return microseconds / 74 / 2;
 }


 void _delayMicroseconds(unsigned int us)
{

#if F_CPU >= 16000000L
      if (--us == 0)
            return;
      us <<= 2;
      us -= 2;
#else
      if (--us == 0)
            return;
      if (--us == 0)
            return;
      us <<= 1;  
      us--;
#endif
      // busy wait
      __asm__ __volatile__ (
            "1: sbiw %0,1" "\n\t" // 2 cycles
            "brne 1b" : "=w" (us) : "0" (us) // 2 cycles
      );
}

The delay for each pass through the loop appears to be caused by the pulseIn command. The default timeout for pulseIn is one second and that seems to be what your are seeing.

You should be able to verify this by commenting out the pulseIn statement and see loop repeat very frequently.

Why not temporarily remove the servo code (to keep things simple) and print the output from the ping sensor and see if the print statements in loop go any faster, and also view what your are getting from the sensor.

YES...that certainly has something to do with it. I did comment out that pulsein and the loop is now operating at the correct speed.

Without the servo code, the loop operates fine and the sensor provides the appropriate output in very fast succession.

Any idea why there is difficulty with the pulsein when the servos are also included?

Your sketch loops quickly on my Arduino with pulseIn commented out but the servo code and everything else as per your post.

You could try unplugging the servos to see if there is some kind of power issue affecting things.

Yes sir...it works with servos unplugged! Can I run a separate +9v to power the servos?

No, most servos are only rated for up to 5 or 6 volts. You will either need an external 5v power supply, or put a regulator (like a 7805) on the 9v supply to drop it down to 5 volts.

I powered up the servos with separate power from 4 AA's and it worked! Man...I really appreciate your help. In the back of my mind I was thinking maybe it was a power issue but thought "Nah..it's hooked up to the USB so it should have plenty of power for 2 servos and the Ping." ...I sure was wrong! Thank you so much...I've spent most of the day trying to debug my code. Not necessarily a bad thing since giving it that much scrutiny helped me to understand it more.

Oops...just read your reply about the extra voltage being a no-no. Will have to figure out something to remedy that. Glad I now know what the issue is!

4 aa cells are ok, thats around 6 volts. But most servos won't like much more than that