Go Down

Topic: Parallax Ping with Arduino Uno (Read 1 time) previous topic - next topic


Hey guys. I'm new to robotics and this is going to be my first robot. I am trying to make an obstacle avoiding robot, and as the title suggests, am using the parallax ping ultrasonic rangefinder. I get how to connect it, but what i don't get is how to read the data I receive. How would I set up a code for  the sensor? I don't get what I am supposed to do, and am utterly stuck.

This somewhere along the lines of what I want to do.
Like if the sensor senses something closer than 5 inches, pin 7 voltage go low or something like that.

You don't have to write a code, but can anyone out there show me and example of how I would set it up and what if statements I would give? Thank you very much and please reply asap!!!


Feb 03, 2012, 03:03 am Last Edit: Feb 03, 2012, 03:45 am by ebun91 Reason: 1
Thanks I like that. But now if I want to do something like if blablabla is the distance then do blablabla, how do I do that? What do I do for the if?

if ("distance" <= 2cm)
digitalWrite(ledPin, LOW)

something like that. thanks!


Feb 04, 2012, 07:04 am Last Edit: Feb 04, 2012, 07:06 am by rwagg Reason: 1
I'm doing something similar and have had success with the Ping class here.  

I create a PING object and it lets me encapsulate all of the effort around getting distance.  I also added an additional method, getInches() that fires the PING and returns the distance... That way it's only one call.

double Ping::getInches()
// This function will fire the ping and then return the distance all in one call.

  return this->inches();

I have one PING sensor mounted on a servo in the front of my bot.  The servo constantly pans the PING left (135 deg), center (90 deg) , right(45 deg), and back to center (90 deg) watching for obstacles.  I put the whole scanning action in an interrupt driven timer so it's constantly gathering data, my code just watches the distances posted in the array and takes action when I need to avoid something.

Here's some of my distance testing code...  dDistance is my array of the three distances LEFT, MIDDLE, and RIGHT.  TOOCLOSE is what I've defined as too close to an obstacle.  Once I come within the TOOCLOSE distance (for center 90 deg), or 1/2 of TOOCLOSE for the side angles (135 deg, or 45 deg) then I take action to turn away from the obstacle.  I define TOOCLOSE as 16".

 // If we are going to rub up against something, let's adjust our movement
 if ((dDistance[LOOKLEFT]   < (double)(TOOCLOSE/2)) &&
     (dDistance[LOOKMIDDLE] > (double)TOOCLOSE))
   // We are getting too close on the left, so let's move right
   bTurned = true;
 // If we are going to rub up against something on the right, let's agjust.
 if ((dDistance[LOOKRIGHT]  < (double)(TOOCLOSE/2)) &&
     (dDistance[LOOKMIDDLE] > (double)TOOCLOSE))
   bTurned = true;

I also check for what I call "STOPCLOSE" so that if the bot is too close (4" for me), then it doesn't have time to turn away, or my hand is in front of the sensor.  Either condition makes the bot just stop.

 if (((dDistance[LOOKMIDDLE] < (double) STOPCLOSE) && dDistance[LOOKMIDDLE] > 0.1))

I check to ensure my distance > 0.1 because sometimes the PING sensor returns a zero.  Instead of fighting with the random zeros, I put this check in to make sure I'm a real distance from an obstacle.  

Below is my scan code [scanAhead()].  Since I'm using Timer based on interrupts, my ISR needs to be on the "quicker side", so I take my distance reading and then move the servo to the next position making it ready to take a measurement the next time the ISR is called.

I use iScanPos to track the servo's angle and position in the array.  I've included it and my iDegrees array below, both are referenced in my scanAhead code below.  
const int iArrayPointer[12]       = {0,1,2,1,0,1,2,1,0,1,2,1};
const int iDegrees[]  = {135, 90, 45};

//scanAhead is my ISR

void scanAhead()
// const int iArrayPointer[12]       = {0,1,2,1,0,1,2,1,0,1,2,1};

 dDistance[iArrayPointer[iScanPos]] = pingSensor.getInches();
 // Just in case we get a zero, let's try again and take what we get
 if (dDistance[iArrayPointer[iScanPos]] == 0)
     dDistance[iArrayPointer[iScanPos]] = pingSensor.getInches();
 if (iScanPos >= iArrayPointerLen)
   iScanPos = 0;


 bDisplayed = false;    // This is a global variable that is checked showDiags()
                        //to make sure we only print the distances when there is actually a change

The last line, pingServer.write(...)  is where I move my servo controlling my PING sensor.  I then return from the ISR and count on the fact that the servo will complete the movement to the next stop before the ISR gets called again.  This way I don't have to code delays() to wait on the servo sensor to move.  I've found that anytime I code a delay(), I end up running into something before I can get another reading.  

I setup my ISR as one of the last things I do in setup().  I use the class Timer3 as my timer.  He's how I defined it in setup()


One last thing I learned, once I make a turn, my distances are now "out of whack" which is why I set the variable bTurned = true.  After my turn is complete, I run through this code:
 if (bTurned)
   delay(1500);      // get our new bearings.
   bTurned = false;

It stops the bot and waits 1 1/2 seconds.  This gives the bot time to do three scans and gather current distances before it starts driving again.
My goal was to keep the bot moving as much as possible, but this is one time when I just needed to stop the bot and look around.


Go Up