e-techgarage.com — Larry's Workbench
Welcome to e-techgarage.com - Larry's Workbench

Battery Charger

Just a short article about the battery charger I just assembled.

Charging Ni-Cad Batteries

Ni-Cad batteries can be fairly easily charged using a constant current source.  For best results with this type of charger you should set the current no higher than C/10, where C is the Amp-Hour rating of the battery.  Here is a link to a site which discusses several methods of charging Ni-Cads.

This simple charger can be built with very few parts.

  • One 3-pin header (H1)
  • Voltage Regulator (U1)
  • Four 82 ohm resistors
  • One 2-pin cable connector (H2)

Here is the schematic:

BatteryCharger

I used four 82 ohm resistors simply because that is what I had on-hand.  The required resistor value can easily be calculated using Ohms Law:  R = E/I.  Our battery packs are either 1600 maH or 2200 maH so I chose to use 160 ma for the charger.  Therefore, the resistance needs to be 3.3 V/160 ma = 20.6 ohms.  Four 82 ohm resistors in parallel yield 20.5 ohms – close enough for government work!  There will also be the current required by the regulator (about 5 ma) but that is relatively insignificant relative to the total current.

Pictures of the unit

The first is a close-up  and you can see that it is built on a piece of breadboard material I cut  from a larger piece.  The second shows the connector assembly that mates to the connectors of the batteries we purchased.

battery_charger_close

The second shows the connector assembly that mates to the connectors of the batteries we purchased.

battery_charger_wide

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.