Shop OBEX P1 Docs P2 Docs Learn Events
Ping sensors on arduino uno board running Servo2Timer library — Parallax Forums

Ping sensors on arduino uno board running Servo2Timer library

cap_jackcap_jack Posts: 9
edited 2012-07-30 09:06 in Accessories
Hello! I am using a ping sensor with an arduino uno board. I bought the kit withping sensor, servo and mount. I am trying to sweep the servo back and forth ~180 deg. and ping between moves. I have tried two approaches with strange output. The sketch is very small so I will post the whole thing.
//   sketch to move servo and ping a distance//   two different ways with different results


#include <ServoTimer2.h>  
const int pin6 = 6;   //attaches servo to pin 6 
const int ping1 = 7;  //attaches ping sensor to pin 7 


long duration1;   // used in ping function
long cm1;             // distance value
int num1;              // direction value out of servo1
int dir;               // var for switch to sweep servo back & forth in move


ServoTimer2 servo1;    // declare objects for servos


void setup() {
  Serial.begin(9600);      // initialize serial communication:
  servo1.attach(pin6);     // attach pins to the servos 
  dir = 0;             // set direction of servos to zero
  int num1 = 0;            // initialize direction of servo movement
  duration1 = 0;
}  


long ping()   //function to drive the ping sensors
{
  pinMode(ping1, OUTPUT);    
  digitalWrite(ping1, LOW);
  delayMicroseconds(4);  //was 2
  digitalWrite(ping1, HIGH);
  delayMicroseconds(10);   //was 5 
  digitalWrite(ping1, LOW);
  pinMode(ping1, INPUT);
  duration1 = pulseIn(ping1, HIGH);
  cm1 = microsecondsToCentimeters(duration1);
  return cm1;
}  


long microsecondsToCentimeters(long microseconds)
{
  // The speed of sound is 340 m/s or 29 microseconds per centimeter.
  // The ping travels out and back, so to find the distance of the
  // object we take half of the distance travelled.
  return microseconds / 29 / 2;
}  // end of ping


long out()           //function to print distances
{
  Serial.print(cm1);
  Serial.println("  cm1  ");
}


int move_another(){     // this gets good distance values from i = 45 down to i = 12 then bad distance
  int count = 0;
  int i;
  for ( i = 1; i != 60; i++){     // servo starts in the middle so for the first loop it hangs from i = 30  until i = 60
    if ( i <= 30 ){                  // then it sweeps back and forth ~180 deg correctly
      num1 = (servo1.read() - 50);
      delay(5);      
      servo1.write(num1);
      delay(400);
      ping();
      out();
      count = count + 1;
      Serial.print(i);
      Serial.println("  i < 15  ");
    }
    else{
      num1 = (servo1.read() + 50);
      delay(5);
      servo1.write(num1);
      delay(400); 
      ping();
      out();
      count = count + 1;
      Serial.print(i);
      Serial.println("  i > 15  ");
    }
  }
}


int move(){        // This one gets 29 good distances  then 29 bad ones ( always 15 cm)
  switch (dir) {
  case 0:
    ping();
    out();
    num1 = (servo1.read() + 50);
    delay(5);      
    servo1.write(num1);
    delay(250);     
    if (num1 >= 2250){ 
      dir = 1;
    }
    break;
  case 1:
    ping();
    out();
    num1 = (servo1.read() - 50);
    delay(5);
    servo1.write(num1);
    delay(250); 
    if (num1 <= 800){
      dir = 0;
    }
    break;  
  }
}


void loop()
{
  move();
//  move_another();  
}



I have tried time delays in various amounts and places in the code. I have written many variations but these two seem the most promising, if I can get them to work;-) Thanking you in advance for any help you may offer.

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-07-22 13:05
    Does the servo move as expected?
    Does the Ping work when you're not using the servo?
    What does "strange output" mean?
  • cap_jackcap_jack Posts: 9
    edited 2012-07-23 05:24
    Hello Duane,

    The servos move as expected, back and forth for ~180 deg. The ping sensors work when the servo is off. The strange output is described in my comments.

    the function int move_another(){ // this gets good distance values from i = 45 down to i = 12 then bad distance
    Now a good distance is the maximum range- 350 cm and the bad distance is 15 cm. Oddly enough, if I hold
    my hand in front of the bad reading, it gives me a good reading under 15 cm.

    The function int move(){ // This one gets 29 good distances then 29 bad ones ( always 15 cm)
    This measures good values, i.e 350 cm, which I can influence with my hand to give accurate values. The bad values start
    in the middle of a sweep, i.e. num1 < 1550 go down to 750 and back up to 1650 then get good again.

    I wrote another function which has good and bad readings and a few dodgy reading, i.e. 120 cm when it should be 350.
    I am trying to keep the sketch as simple as possible in order to understand why ping works sometimes and not others.
    I thought perhaps the servo motor gives an interference sound and I tested another servo motor with the same result.
    I also tested another ping sensor with the same results.

    Thanks for having a look. Any suggestions are welcome!

    Regards,
    Cappy
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-07-23 07:00
    I've used AVR chips with AVR Studio but I haven't used the Arduino programming environment.

    I'm just grasping at straws here, but how many bits are in an "int" variable? When things work with some numbers and not others, I wonder if it could be because some vairable has rolled over. I couldn't see anything in your code that would cause this problem though.

    There are a few Arduinno users around here and you're very welcome to ask questions here, but you might get better help at an Arduino or AVR forum.
  • GordonMcCombGordonMcComb Posts: 3,366
    edited 2012-07-23 07:47
    I'm not familiar with the servo library you're using, but have you tried a simpler test using the standard Servo library and the Sweep example that's on the Arduino Web site? Put the Ping reads between each sweep movement. You can alter the code to vary the granularity of the sweeps.

    You might also try a much higher baud rate for the Serial connection for debugging in case there's an issue with the Arduino fumbling a Ping reading while sending data to the Serial Monitor window.

    -- Gordon
  • cap_jackcap_jack Posts: 9
    edited 2012-07-24 01:28
    Thanks, Gordon, for the suggestion. I cannot use the servo library because I have an Adafruit wav shield. It uses the only 16 bit timer which conflicts with the servo library using it too. I am using the Servo2Timer because it uses another interrupt. I am posting on the Arduino Forum also and have been chasing threads of similiar conflicts. person says the PulseIn command is flaky unless you use another power supply to drive the servo. I will try it. Another person has developed a library for the Ping sensor. I just found it but it appears to want to use the same timer the wav shield needs. I am going to ping the author about an earlier version which may not be interrupt driven. I haven't pinged the AVR Freaks yet. Thanks, again. I am wondering if Parallax has a successful solution of using their ping sensors with an Arduino Uno??
  • cap_jackcap_jack Posts: 9
    edited 2012-07-24 01:33
    Thanks, Duane, for the reply. Here is Arduino's definition of an int, "Integers are your primary datatype for number storage, and store a 2 byte value. This yields a range of -32,768 to 32,767 (minimum value of -2^15 and a maximum value of (2^15) - 1). " I do not think my loops go anywhere near these limits. I watch them with print statements. I have bumped into memory issues and have learned how to PROGMEM them out of the way. Thanks, again.
  • GordonMcCombGordonMcComb Posts: 3,366
    edited 2012-07-24 08:08
    I think a systematic approach to these issues is the best. Temporarily remove the Wave Shield and use the regular Servo library. The page here:

    http://learn.parallax.com/KickStart/28015

    shows proven Ping code using the Arduino Uno.

    Try first without your servo even connected. Then when that part works, add the servo and instantiate its object, but don't move it yet (yes, it does matter). Still working? Then write simple sweep code -- left, center, right, center -- and take Ping readings. Finally, create your sweep.

    Power supply glitches can indeed cause problems, so as a matter of course add a 47-470 uF cap across the power supply for the servo, and a smaller one across the Ping's supply just as an added measure.

    I've used the Ping with servo sweeps successfully on a number of Uno-based projects without a problem, but I've only used the standard Servo library. You will absolutely need an interrupt-based approach for running your servo, as once you add in the Wave Shield code your Arduino will have precious little time to "manually" update servo pulses. At even 22k sampling there's a lot of data that's getting shuttled first from the SD card, then to the DAC.

    -- Gordon
  • cap_jackcap_jack Posts: 9
    edited 2012-07-25 04:09
    Thanks, Gordon, for the suggestions. I wrote a sketch with the servo library and the basic ping code. When the servo is out, ping reports accurately. When I run with the servo I get errors. I am going to try the capacitor suggestion next. But why such a spread of values in your suggestion? And what value is a smaller one for the ping sensor? Please, I am not an EE and really don't know how to put the cap on the power supply without explicit directions. I believe I wire it on the + side of the power supply with the power going thru it i.e. putting the power on both leads.

    Thanks!
  • GordonMcCombGordonMcComb Posts: 3,366
    edited 2012-07-25 07:58
    You need to wire the capacitor "across" the power terminals. That means it simply drops over the power pins in parallel: the + of the capacitor goes to V+, and the - goes to Gnd. Note that with tantalum electrolytic capacitors, they mark the + terminal; with aluminum electrolytic, they mark the - terminal. Align the polarity as needed. If you put it in backwards the cap will blow out. You can usually smell it!

    The the value it doesn't matter too greatly, but is for experimenting anyway. The capacitor is used for soaking up ripples and spikes in the power supply. Find the smallest one that works.

    -- Gordon
  • cap_jackcap_jack Posts: 9
    edited 2012-07-27 04:57
    Thanks, Gordon, I put a 470mf cap across the servos and a 33mf across the ping sensors. I put the servos on another 5vdc power supply. I wrote a sketch using the librarys for servo and ping. I am stumped by the results.

    I get a low reading (15 cm) in the middle of the sweep for 9 moves then good ones. I can get the low readings to measure smaller distances so it appears that the ping is working. If I take the servo out of the sketch I get the same thing by turning the servo by hand. Just in the middle of the servo sweep the readings are consistently 15 cm. I have 2 servos and 2 ping sensors so I activated the servo that has the disconnected ping and pinged with the other one on the other disconnected servo. Same thing. Even on the disconnected servo, the center of the sweep is reading low. The other servo can run and not effect the ping readings. I have permutated through delays and when the delays take place but I always have low readings somewhere.

    Here is the sketch-
    // Sweep




    // by BARRAGAN <http://barraganstudio.com&gt;
    // This example code is in the public domain.
    #include <Servo.h>
    const int ping1 = 7;
    const int ping2 = 9;
    int cm;
    Servo myservo; // create servo object to control a servo
    // a maximum of eight servo objects can be created


    int pos = 0; // variable to store the servo position


    void setup() {
    // initialize serial communication:
    Serial.begin(115200);
    myservo.attach(8); // attaches the servo on pin 9 to the servo object
    }


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


    // 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);
    cm = microsecondsToCentimeters(duration);


    return cm;
    }


    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;
    }
    long microsecondsToCentimeters(long microseconds)
    {
    // The speed of sound is 340 m/s or 29 microseconds per centimeter.
    // The ping travels out and back, so to find the distance of the
    // object we take half of the distance travelled.
    return microseconds / 29 / 2;
    }


    void loop()
    {
    for(pos = 0; pos < 180; pos += 10) // goes from 0 degrees to 180 degrees
    { // in steps of 1 degree
    myservo.write(pos); // tell servo to go to position in variable 'pos'
    delay(50);
    ping(ping1);
    Serial.print(cm);
    Serial.println(" cm up");
    delay(50);
    ping(ping2);
    }
    for(pos = 180; pos>=1; pos-=10) // goes from 180 degrees to 0 degrees
    {
    myservo.write(pos); // tell servo to go to position in variable 'pos'
    delay(50); // waits 15ms for the servo to reach the position
    ping(ping1);
    Serial.print(cm);
    Serial.println(" cm down");
    delay(50);
    ping(ping2);
    }
    }

    I am wondering if my pin selection, 7 & 9 for pings and 6 & 8 for servos, has anything to do with this? I am hoping there is a solution for this. Any suggestions are welcome! Thanks, again.

    Regards,
    Cappy Jack
  • GordonMcCombGordonMcComb Posts: 3,366
    edited 2012-07-27 10:48
    If it were me I'd test only one Ping at a time in case there are some odd reflections and microphonic effects going on. I don't want to second guess your physical setup, so suffice it to say, 50 ms delays between pings may or may not be sufficient.

    Also be sure there are no surfaces above, below, or to the sides of the sensor that may be causing early echo reflections. The fact that you can get correct shorter distances suggest this may be an issue.

    As I recommended above I think you should test a simpler sweep. Just write code to look left, center, right, center, repeat. Put in delays long enough for the servo to transit there, PLUS time for any vibration to stop settling. You can't reliably take ultrasonic readings while a servo is transiting the sensor, or you could get errors from Doppler effects.

    Write your code with some constants

    const int servoDelay = 200; // just an example

    so that you can easily change the delay amounts. Again, be sure the delay is long enough for the servo transit, plus maybe 25-50ms for any settling. Start with values much higher than you think you need to see if those work, and if they do reduce as needed.

    -- Gordon
  • cap_jackcap_jack Posts: 9
    edited 2012-07-28 03:47
    Thanks, Gordon, for replying. I have reduced every variable I can to no avail. The sketch is simply the ping and servo libraries supplied by Arduino. The fact remains that there is a dead spot on either servo where the distance is reported wrong. I take the servo code completely out of the sketch and the ping distance is reported as 15 cm when it should be max. distance when I turn the servo by hand to the sweet spot. I have put delays of all sizes and in all the places I could think of with and the ping sensor still gives a 15 cm reading. The direction I point the sensor does not effect this phenomena. I am going to send an email to Parallax support. Thanks, again, for giving suggestions!

    Regards,
    Cappy Jack
  • FranklinFranklin Posts: 4,747
    edited 2012-07-29 20:58
    Make sure there is nothing reflecting the sound wave from the ping. If you take the ping off the servo does the servo position still make a difference?
  • cap_jackcap_jack Posts: 9
    edited 2012-07-30 05:29
    The Arduino Uno ( with Adafruit wav shield) is outputting noise which the ping hears. I had placed the computer within 5 and 10 cm of the sensors for my project. When I moved the sensors 20 cm away and separated by a piece of wood the noise stopped spoofing the pings. What is interesting is that the noise is directional. If it had effected the sensors all the time I am sure I would have found it sooner. Thanks everyone for the suggestions!
  • GordonMcCombGordonMcComb Posts: 3,366
    edited 2012-07-30 09:06
    If it's the Arduino causing the noise it's a manufacturing defect, such as a bad solder joint or lifted trace. Might be worth it to return that one for another. If it's the Wave Shield, those come as a kit so it could be your soldering. It could also be something in the design of the board. You could try dropping by the Adafruit forums and asking if anyone else has had the issue. (I've never used my Wave Shield with an ultrasonic sensor, so I've not experienced the same situation.)

    Anyway, this is why a systematic approach to development and troubleshooting is so important. Recall that I earlier suggested you temporarily remove the Wave Shield. It's not possible to electrically disconnect a shield from the Arduino unless you physically remove it. The shield interacts even when there's no prgramming to drive it. It will still consume current, contribute to electrical noise, etc. For this reason it's always best to test one thing at a time.

    For every project I do I always build from smaller blocks, making sure each sub-system works. I then add components and test along the way. When a problem arises -- and it always seems to with these things -- I then backtrack to determine the root cause.

    By its nature, high frequency sound tends to be directional, so it's not surprising that simply by moving off-axis the problem is reduced or eliminated.

    On fixing the problem, I'd test with and without the Wave Shield. If it's the Wave Shield, some soldering rework might be called for. Inspect all the solder joints to make sure they're perfecto -- no cold or "peaked" joints.

    -- Gordon
Sign In or Register to comment.