e-techgarage.com — Larry's Workbench
Archive for the "Rover" Category

Collision Avoidance Algorithm

Collision Avoidance Algorithm

The Obstacle Triangle

As it turns out, stopping Rover before he hits an obstacle is not too difficult with the SONAR sensor we are using.  The hardest part was to determine what the stopping distance should be based on the angle at which the obstacle is detected.  I think the method we have in place is adequate for the time being.  It basically creates a triangle in front of Rover, the apex of which is at a point directly in from of Rover that is calculated based on how fast he is going.  The base of the triangle is the SONAR turret.  The width of the base is defined by the distance between the SONAR unit and the outside of the front tires plus a little extra.

The really hard part of the algorithm is determining where to go after Rover stops!  This effort has made up the bulk of my “Rover” time for the past month.  While Rover is traveling, the SONAR turret is swiveling back and forth over a range of +/- 80 degrees.  Once an obstacle is detected that falls within the “Stop” triangle, Rover is told to stop.  Here is the logic that I have finally (maybe) settled on once a collision has been detected:

Stop the sweep, get the angles and distances in 10 degree increments for a span of +/-90 degrees

Algorithm Pseudo Code

Note: the following code is in a loop that will execute a maximum of 4 times:

If the obstacle is “too close”

Back up a little

Get the angles and distances in 10 degree increments for a span of +/-90 degrees

If the angle of the obstacle is too close to straight ahead

Set the turn angle to the angle with the longest path

Else

Set the turn angle to turn away from the obstacle by a fixed amount

EndIf

ElseIf the distance of the longest path is short

Turn away from the obstacle by 90 degrees

Else

If the angle to the object is not too close to the angle of the longest path,

Set the turn angle to the angle with the longest path

Else

Set the turn angle to the angle with the longest path + a fixed amount

Endif

If turn angle is opposite to previous turns

Backup a little

Get the angles and distances in 10 degree increments for a span of +/-90 degrees

If the angle of the obstacle is too close to straight ahead

Set the turn angle to the angle with the longest path

Else

Set the turn angle to turn away from the obstacle by a fixed amount

EndIf

EndIf

EndIf

Turn Rover by the calculated turn angle

Get the angles and distances in 10 degree increments for a span of +/-90 degrees

Exit the loop if the distance ahead is greater than the Collision distance

Something you should note about the algorithm is that it takes a new set of reading after EVERY time the position of Rover is changed.  This is very important.  Rover cannot make good decisions unless he has the latest data!

Another note of interest: Puck and I have been testing Rover in the “cube farm” within our office area.  There are a number of cube walls that the SONAR we have does not detect.  These walls seem to absorb the SONAR signal which essentially tells Rover that there is an open path where there is actually a wall!  Obviously this is not a good situation.  This particular phenomenon is what has caused me the most difficulty in developing the algorithm.  I have another SONAR sensor on order that we will try just to see what happens.

Updated Collision Avoidence Algorithm

This updated algorithm is somewhat more robust than the previous post.  I thought that this time I would write the description using pseudo-code.  An important feature to remember for all of our discussions about angles is that 0 (zero) degrees is ALWAYS straight ahead of Rover.

Note: The Forward Motion Counter is initialized to 0 (zero) at the beginning of the program.  This value is used to count the number of times sequentially that the Rover has traveled forward less than a predefined number seconds.

Start of CAv code

Start SONAR turret sweeping with low resolution (45 degrees per sample)

Wait enough time for the turret to do a complete 180 degree sweep

Start forward motion timer.

Loop: (Travel forward until obstacle detection occurs)

Tell Rover to go forward until SONAR detects an obstacle within the stopping distance

NOTE: there is an algorithm that scales the stopping distance based on the angle and the specified minimum obstacle distance. See Puck’s blog for details.

Loop End

Tell Rover to Stop

Calculate time Rover has been moving forward

If the forward time > than a predefined threshold

set the Forward Motion Counter to 0 (zero)

Else

increment the Forward Motion Counter

If the Forward Motion Counter < the predefined threshold  (Rover has not gotten stuck)

Set SONAR turret to more sensitive sweep  (9 degrees per sample)

Backup a little

Loop: (Sweep the entire forward field at fine resolution)

Wait for complete sweep

If longest path is > 36 inches – exit loop

Turn Rover 90 degrees and wait for turn to complete

Loop End

Turn Rover to angle with longest path > 36 inches and wait for turn to complete

Else Forward Motion Counter >= the predefined threshold (Rover has gotten stuck )

Set SONAR turret to more sensitive sweep (9 degrees per sample)

Wait for complete sweep

Initialize distance values and loop counter

Loop while distance < 30 inches and loop counter < Threshold:

Increment loop counter

Find angle of longest distance

Wait for complete sweep

Find angle of longest distance – again

If both distances are > 36 inches set angle to average of the two readings

Otherwise set angle to 45 degrees

Turn Rover to the specified angle

Wait for complete sweep

Loop End

Set Forward Motion Counter to 0 for next time  CAv routine is entered

End of test of Forward Motion Counter

End of CAv code

Collision Avoidance Algorithm

One of the major design goals for Rover has been autonomous behavior that avoids collisions.  Basically, turn him on, watch him go and NOT run into anything.  Here I will describe the main program and the Collision Avoidance (CAV) function.

The entire main program:

#define FIRST_STOP_DX    24

main ()

{

Rover_SetUp();                            // all of the initialization code, set up and enable the ISRs

TurretAngle(0);                           // initialize Rovers eyes to straight ahead

MsDelay(2000);                          // give Rover some time to settle

while (1)                                          // main loop

{

Rover_CAV ( FIRST_STOP_DX, 30 );      // mover Rover forward until he detects an obstacle (<24″) at 30% of full speed

MsDelay(2000);                                               // some time to think

Rover_Go ( ROVER_REVERSE, 15, 15 ); // backup a little

Wait4Motors();                                                 // wait for the motors to stop

Rover_Search();                                               // get distance for each of three angles:  -45,  0,  +45

if ( Obstacles[0] > Obstacles[2] ) Rover_Static_Turn ( -45, 50 ); // turn 45° away from the obstacle

else Rover_Static_Turn ( 45, 50 );

Wait4Motors();                                                 // wait for the motors to stop

MsDelay(1000);                                               // Rover is thinking again!

} // main loop

}

Now for the Collision Avoidance function:

void Rover_CAV ( int Stop_Dx, int Speed )

{      int distance,  DirFlag,  int i;

CurrentAngle = 0;                                  // current turret angle

DirFlag = 1;                                                // 1 = CW,     -1 = CCW

while (1)                                                      // stay in loop until obstacle is detected

{

Rover_Go ( ROVER_FORWARD, Speed, 15 ); // go forward for about 1 second (15 pulses)

while ( Motor_Status )                  // while motors are running

{

for ( i=-1;   i<=1;   i++ )       // for each scan angle

{       CurrentAngle = i*SEARCH_ANGLE*DirFlag;

TurretAngle(CurrentAngle);  // turn the turret

for ( SRF05ICdone=0; SRF05ICdone<5; )

/* The SRF05 is triggered once every 50msec.  Its output is a pulse proportional to the object distance.  The pulse is measured by the Input Capture system

of the Rabbit.  An interrupt is generated by Input Capture the end of each measurement of the SRF05 sonic sensor.  The variable SRF05ICdone is

incremented with each of the interrupts.  This for loop has the effect of causing a delay until 5 SARF05 readings have completed. */

{         if ( (distance=GetDistance()) < Stop_Dx ) // if obstacle

{         Rover_Stop(0);

return;

} // if obstacle

} // 50msec per count

} // for each scan angle

DirFlag *= -1;                          // reverse the scan direction

} // while motors are running

// stay in loop until obstacle is detected

} // Rover_CAV

Rover’s Eyes are now on a rotating neck!

Puck and I have always known we would have to allow Rovers “eyes” to, well, rove. We have now mounted his eyes on a small turret that can be rotated using a Futaba S3004 RC servo.

Rover with Servo-Driven SONAR Turret

Rover with Servo-Driven SONAR Turret

This is a relatively small servo which mounts nicely in an existing cutout of Rover’s top plate. The servo specifies that it requires 4.8V to 6V in order to operate but we are supplying it with 3.3V and it seems to be quite happy about it. The control signal is PWM which is typical of RC servos. The PWM signal does not actually drive the motor within the servo but is simply used as a comparison value.

I wrote a simple test program to see what pulse width is required for the various rotation positions. With a 0.5msec pulse width the servo rotates pretty close to its full CW (Clock-Wise) position. It takes about 1.38msec to be centered. The function I wrote uses this formula to calculate the required pulse in milliseconds to achieve the requested angle:

Pulse Width Formula: msec = 0.5 + 0.88*((float)Angle + 90.0)/90.0;

The reason for the “+90″ factor is because I want the caller to use a range of -90 degrees to +90 degrees. Here is a picture of what I am talking about:

Specific Pulse widths = Specific Servo Positions

Specific Pulse widths = Specific Servo Positions

Most RC systems are set up to control up to 8 servos. The systems operate such that each servo is basically “assigned” a 2.5msec time slot within a 20msec interval. The pulse width required for each servo is between 0.5msec and 2.5msec with 1.5msec being relatively close to centered. In order for the Rabbit processor’s PWM system to achieve a low pulse rate with high resolution it is necessary to utilize the feature which removes, or swallows, X pulses out of every Y pulses. To get the 50Hz (20msec period) signal I wanted I calculated the base PWM frequency to be 200Hz. I then programmed the PWM system to swallow 3 of every 4 pulses. This creates a PWM signal with a 50Hz rate but still leaves me with the full 10 bit resolution capability of the PWM system. The following diagram may help:

Shows Pulse Swallowing

Shows Pulse Swallowing

The PWM setup calculations also derive a value which is the number of input clock pulses required to generate a 1msec pulse width (pulses per millisecond). Using the Pulse Width Formula to calculate the required number of milliseconds and then multiplying that result by the pulses per millisecond I get the number of clock pulses to generate the requested angle.

Rover Additions

Puck and I have added a few features to Rover:SMODE Switch

  • SMODE Switch – The Rabbit processors have four bootstrap modes.  Usually, when you connect a programming cable, the SMODE pins are pulled high and the Rabbit wants to communicate with its development environment.  Resetting the Rabbit with the cable off causes the Rabbit to start executing its program.  In the case of the RCM5600W, there is a manual jumper that needs to be removed when you want the Rabbit to boot into its Run mode.  The jumper needs to be inserted when you want to program it.  In our case, we got tired of inserting and removing that jumper so I installed a toggle switch on the back of Rover and wire-wrapped the connections to the jumper posts.

Power Switch

  • Power Switch – We added a switch so we can connect and disconnect the battery.  We still need to work with the screw terminals to switch between an external pow er supply and the battery.  Eventually, I hope to insert some kind of connector.

The latest software now supports the SRF05 Ultra-Sonic Ranger.  This will be used to tell Rover some information about his surroundings – at least what is in front of him.  The software enables the SRF05 to continuously inform Rover of the distance to the nearest object within the beam pattern.  As we said in an earlier post, we will be mounting the SRF05 on a mast that turns ±90° so we can also look side-to-side.  We did some initial testing this morning and, so far, it is looking pretty good.

Here is a picture of the unit just sitting on my bench connected to an RCM4100 and prototype board.  The same code works in both the Rabbit 4000 and Rabbit 5000 processors.

SRF05 bench

And here is a movie of Puck and me testing the unit showing the SRF05 Trigger pulse and Echo pulse.