Ramping in Navigation

Ramping in Navigation

Ramping is a common term for making the servos speed up and slow down gradually, with no sudden starts, stops, or direction changes.  For hill-detection and climbing, it's crucial to have a reliable ramping routine for Boe-Bot navigation.  Without it, the Boe-Bot's abrupt motions cause acceleration measurements to get mixed in with the tilt measurements.  This in turn gives the Boe-Bot a false reading of the hill's steepness. 

The consequences of these false measurements can be pretty disabling for a hill-climbing Boe-Bot.  Depending on how the program is designed, the Boe-Bot can actually move one direction, get a wrong tilt measurement, and try to correct with a sudden change of motion.  This in turn leads to another wrong tilt measurement, in the opposite direction, which the Boe-Bot again tries yet again to correct with another abrupt change in motion.  In some cases, the Boe-Bot could even end up on a slope, paralyzed, sitting in one place and jittering.

EepromNavigationWithRamping.bs2

This next example demonstrates how ramping combined with EEPROM navigation smooths out the Boe-Bot's transitions between maneuvers. 

  • Enter, save, and run EepromNavigationWithRamping.bs2
  • Verify that the Boe-Bot starts out by moving forward.  Depending on your servos, it may curve to the left or the right a little, which is okay.

If the Boe-Bot starts out going backward instead of forward
Your servo cables may need to be swapped.  The cable connected to the Boe-Bot's left servo should be connected to the P13 servo port on the Board of Education.  The cable connected to the right servo should be connected to the P12 port.

  • Fine tune the distances so that they make your Boe-Bot travel in a rectangle.  The turn at the first corner should be left, 90°.  The second should be right, 270°, and the third should be another left at 90°.
' -----[ Title ]--------------------------------------------------------------
' EepromNavigationWithRamping.bs2
' Demonstrate how ramping routine smoothes out EEPROM navigation.
 
'{$STAMP BS2}
'{$PBASIC 2.5}
 
' -----[ EEPROM Data ]--------------------------------------------------------
' Two DATA directives store the following navigation instructions:
' Forward, left 90-degrees, forward, right 270-degrees forward,
' left 90-degrees, forward, stop.

Directions DATA "F", "L", "F", "R", "F", "L", "F", "Q"
Distances  DATA  70,  53,  80,  77,  90,  53,  80,  0
 
' -----[ Variables ]----------------------------------------------------------
 
counter        VAR     Byte                  ' FOR...NEXT loop counter
index          VAR     Byte                  ' Points to EEPROM instructions
instruction    VAR     Byte                  ' Stores navigation instruction
pulseCount     VAR     Byte                  ' Stores navigation distance
 
pulseLeft      VAR     Word                  ' Stores pulse to left servo
pulseLeftOld   VAR     Word                  ' Previous pulse to left servo
 
pulseRight     VAR     Word                  ' Stores pulse to right servo
pulseRightOld  VAR     Word                  ' Previous pulse to right servo
 
' -----[ Initialization ]-----------------------------------------------------
 
FREQOUT 4, 2000, 3000                        ' Beep to signify program start
 
pulseLeft     = 750                          ' Set all pulse values to center
pulseRight    = 750
pulseLeftOld  = 750
pulseRightOld = 750
 
' -----[ Main Routine ]-------------------------------------------------------
 
DO                                           ' Begin main routine
 
  ' Fetch EEPROM instruction.
  READ index + Directions, instruction       ' Get navigation character
  READ index + Distances, pulseCount         ' Get number of pulses
  index = index + 1
 
  ' This FOR...NEXT loop includes a navigation routine with ramping.
  FOR counter = 1 TO pulseCount              ' Repeat for number of pulses
 
    ' Navigation routine sets pulse width based on navigation character.
    SELECT instruction
      CASE "F"                               ' Pulse durations for forward
        pulseLeft = 850                     
        pulseRight = 650
      CASE "L"                               ' Pulse durations for left
        pulseleft = 650                     
        pulseRight = 650
      CASE "R"                               ' Pulse durations for Right
        pulseLeft = 850
        pulseRight = 850
      CASE "B"                               ' Pulse durations for backward
        pulseLeft = 650
        pulseRight = 850
      CASE "Q"                               ' End the program
        END
    ENDSELECT
 
    ' Increment/decrement routine only changes pulse durations by 2 at a time.
    IF pulseLeft > (pulseLeftOld  + 2) THEN pulseleft  = pulseLeftOld  + 2
    IF pulseLeft  < (pulseLeftOld  - 2) THEN pulseLeft  = pulseLeftOld  - 2
    IF pulseRight > (pulseRightOld + 2) THEN pulseRight = pulseRightOld + 2
    IF pulseRight < (pulseRightOld - 2) THEN pulseRight = pulseRightOld - 2
 
    pulseLeft  = pulseLeft  MIN 650 MAX 850  ' Keep 650 <= durations <= 850
    pulseRight = pulseRight MIN 650 MAX 850
 
    pulseLeftOld  = pulseLeft                ' Remember old values
    pulseRightOld = pulseRight
 
    PULSOUT 13, pulseLeft                    ' Send control pulses to servos
    PULSOUT 12, pulseRight
    PAUSE 20
 
  NEXT                                       ' Check FOR counter... condition
 
LOOP                                         ' Repeat main routine

How EepromNavigationWithRamping.bs2 Works

The Directions DATA directive stores a series of instructions that include "F" for forward, "L", for left, "R" for right, "B" for backward, and "Q" for quit.  Each character in the Directions DATA directive has a number of pulses stored in the Distances DATA directive.  The first "F" is delivered for 70 pulses, then the "L" delivers 53 pulses, and so on.  Since these values are stored in the BASIC Stamp microcontroller's EEPROM, the main routine must use READ commands to retrieve these instructions.

There are two READ commands in the main routine that fetch the instructions from the BASIC Stamp's EEPROM.  The first fetches the direction from the Directions DATA, and the second fetches the number of pulses from the Distances DATA.  The first time through the main routine, index starts at 0, so the first item in each of the two DATA directives is fetched.  Then, the value of index gets 1 added to it.  The next time through the main routine, index will be 1, so the second item from each DATA directive is fetched.  The third time through, index is 2, so the third item in the DATA directive is fetched, and so on.

The ramping occurs in a FOR...NEXT loop that repeats pulseCount times.  The code blocks in a SELECT...CASE statement set the target full speed values of the pulseLeft and pulseRight variables.  Next, a series of IF...THEN statements compare the target values to the previous values of pulseLeft and pulseRight.  These values were stored as pulseLeftOld and pulseRightOld near the end of the previous pass through the FOR...NEXT loop. 

The IF...THEN statements make sure that the pulse durations only increase by increments of 2. They do it by comparing pulseLeft and pulseRight to pulseLeftOld and pulseRightOld. Essentially, The IF...THEN statements make sure that the pulse that gets delivered this time through the FOR...NEXT loop is only 2 more (or less) than the pulse that was delivered previously.  MAX and MIN operators make sure that the pulse durations never increase above 850 or drop below 650.

 

Your Turn – Changing the Ramping Increments

Especially if the same value appears in several places in a program, it’s a good idea to replace it with a constant.

  • Try replacing all the 2’s in the IF...THEN statements with the name rampIncrement
  • Then, at the beginning of the program, add a constants section with this declaration:
rampIncrement  CON  2

This will make it a lot easier to experiment with different values for rampIncrement.

  • Try changing the values from 2 to 3 in the IF...THEN statements that set the pulse durations.  Also, try values like 1, 4, 5, and 6, 7, 8, and 10, and observe how the navigation changes. 
  • After each change to the pulse increment value, you will also have to update the values in the Durations DATA directive to get back to a good rectangular path for your Boe-Bot.

 

Ramping on a Ramp

UphillBoeBot.bs2 is the program that performs the hill climbing shown in Figure 8‑1.  This program is different from EepromNavigationWithRamping.bs2 in several ways.  First, instead of instructions stored in EEPROM, the program makes all its navigation decisions based on accelerometer measurements.  It uses IF...THEN statements to decide whether it needs to rotate to correct sideways (x-axis) tilt, or go forward or backward to respond to uphill/downhill (y-axis) tilt.  Ramping is used to smooth out the Boe-Bot's changes in direction, starts, and stops so that it doesn't get stuck reacting and overreacting to the incorrect readings that result from sudden starts, stops, and turns.

Example Program – UphillBoeBot.bs2

  • Find a convenient platform for controlling the slope your Boe-Bot is on.
  • Enter, save, and run UphillBoeBot.bs2
  • Use the platform's tilt to guide your Boe-Bot.  The program will make it always try to climb uphill.  As you tilt the platform and cause ‘uphill’ to be in a different direction, the Boe-Bot detects this change and adjusts to a new heading up the steepest path on the slope.
' -----[ Title ]--------------------------------------------------------------
' UphillBoeBot.bs2
' Boe-Bot detects and climbs the steepest slope it can find.
'{$STAMP BS2}
'{$PBASIC 2.5}
 
' -----[ Variables ]----------------------------------------------------------
 
x              VAR     Word                  ' Left/right tilt
y              VAR     Word                  ' Uphill/downhill tilt
 
pulseLeft      VAR     Word                  ' Current left pulse value
pulseLeftOld   VAR     Word                  ' Previous left pulse value
 
pulseRight     VAR     Word                  ' Current right pulse value
pulseRightOld  VAR     Word                  ' Previous right pulse value
 
' -----[ Initialization ]-----------------------------------------------------
 
FREQOUT 4, 2000, 3000                        ' Beep to signify program start
 
pulseLeft     = 750                          ' Start with all pulses centered
pulseRight    = 750
pulseLeftOld  = 750
pulseRightOld = 750
 
' -----[ Main Routine ]-------------------------------------------------------
 
DO                                           ' Begin main routine.
 
  PULSIN 6, 1, x                             ' Get tilt pulses.
  PULSIN 7, 1, y                            
 
  x = (x MIN 1875 MAX 3125) - 2500           ' -625 to 625 with 0 = no tilt
  y = (y MIN 1875 MAX 3125) - 2500
 
  ' Navigation decisions
  ' Remember, the x measurement indicates that the Boe-Bot is tilted left when
  ' it's negative, and right when it's positive.  The y measurement indicates
  ' that the Boe-Bot is tilted downhill when it's negative and uphill when
  ' it's positive.   
  IF ABS(x) > 40 THEN                        ' x < 40 --> turn right,
    pulseLeft = 750 - x                      ' x > 40 --> turn left
    pulseRight = 750 - x
  ELSEIF ABS(y) > 40 THEN                    ' y < 40 --> forward,
    pulseLeft = 750 - y                      ' y > 40 --> backward
    pulseRight = 750 + y
  ELSE                                       ' Stay still
    pulseLeft = 750
    pulseRight = 750
  ENDIF
 
  ' Increment/decrement routine only adjusts pulse durations by 8 at a time.
  IF pulseLeft  > (pulseLeftOld  + 8) THEN pulseleft  = pulseLeftOld  + 8
  IF pulseLeft  < (pulseLeftOld  - 8) THEN pulseLeft  = pulseLeftOld  - 8
  IF pulseRight > (pulseRightOld + 8) THEN pulseRight = pulseRightOld + 8
  IF pulseRight < (pulseRightOld - 8) THEN pulseRight = pulseRightOld - 8
 
  pulseLeft  = pulseLeft  MIN 650 MAX 850    ' Keep 650 <= durations <= 850
  pulseRight = pulseRight MIN 650 MAX 850
 
  pulseLeftOld  = pulseLeft                  ' Remember old values
  pulseRightOld = pulseRight
 
  PAUSE 20
  PULSOUT 13, pulseLeft                      ' Send control pulses to servos
  PULSOUT 12, pulseRight
 
LOOP                                         ' Repeat main routine.

How UphillBoeBot.bs2 Works

The first step for incline-based navigation is to get the x and y-axis tilt measurements from the accelerometer.

PULSIN 6, 1, x         
PULSIN 7, 1, y  

Next, the tilt measurements are adjusted for a scale of -625 to 625, where 0 is approximately level.  The result is that the x-axis measurement is negative when the Boe‑Bot is tilted to the left, and positive when it's tilted to the right.  Likewise, the y-axis measurement is negative when the Boe-Bot is pointing uphill and positive when it's pointing downhill.

x = (x MIN 1875 MAX 3125) – 2500
y = (y MIN 1875 MAX 3125) - 2500

Since zero is level on the x-axis, anything greater than or less than zero indicates some level of tilt.  The statement IF ABS(x) > 40 THEN... translates to "if the absolute value of x is greater than 40, then...".  That means that anything greater than 40 or less than -40 will make the first IF...THEN statement true.  The code block inside that IF...THEN statement simply subtracts the x measurement from both the pulseLeft and the pulseRight variables.  That's because when the Boe-Bot is tilting left, x will be negative.  A negative value subtracted from something is the same as adding that value, so x is actually added to 750 for both pulseLeft and pulseRight.  For example, if x is -100, then both pulseLeft and pulseRight will be set to 850, which are the pulse durations for full speed rotate-right.  The net result is a right turn, to point the front of the Boe-Bot uphill.  The same applies when x is greater than 40.  The Boe-Bot is tilting right, and both pulse values are 650, which causes the Boe-Bot to execute a left turn, again to point it uphill.

IF ABS(x) > 40 THEN                   ' x < 40 --> turn right,
  pulseLeft = 750 - x                 ' x > 40 --> turn left
  pulseRight = 750 - x

The same reasoning applies for the y-axis (uphill/downhill) measurement.  If the Boe-Bot is tilted so that y is more than 40 or less than -40, the Boe-Bot must be pointing downhill or uphill.  Let's say that the Boe-Bot is pointing uphill, and the y-axis measurement happens to be -100.  That makes pulseLeft 850 and pulseRight 650, which means full speed ahead.  If y happens to be 100, that would make pulseLeft 650 and pulseRight 850, which would cause the Boe-Bot to go full speed in reverse.

ELSEIF ABS(y) > 40 THEN               ' y < 40 --> forward,
  pulseLeft = 750 - y                 ' y > 40 --> backward
  pulseRight = 750 + y

These IF...THEN statements change the value of pulseLeft and pulseRight so that they only increase or decrease by 8.  This ensures that the servo speeds change gradually, either increasing or decreasing by 8 each time through the loop.

IF pulseLeft  > (pulseLeftOld  + 8) THEN pulseleft  = pulseLeftOld
IF pulseLeft  < (pulseLeftOld  - 8) THEN pulseLeft  = pulseLeftOld
IF pulseRight > (pulseRightOld + 8) THEN pulseRight = pulseRightOld
IF pulseRight < (pulseRightOld - 8) THEN pulseRight = pulseRightOld

The pulse durations to the servos should range from 650 for full speed clockwise to 850 for full speed counterclockwise.  The center pulse duration of 750, of course, keeps the centered servos at a standstill.  Thus far in the program, there's nothing to prevent 8 to be added to either pulseLeft or pulseRight even when it's already larger than 850.  There's also nothing preventing 8 from being subtracted from one or both of the variables when they are already 650 or less.  These two lines take care of that problem by setting the minimum values for both pulseLeft and pulseRight at 650, and the maximum at 850.

pulseLeft  = pulseLeft  MIN 650 MAX 850  
pulseRight = pulseRight MIN 650 MAX 850

The next time through the main routine's DO...LOOPpulseLeft and pulseRight will have new values because of new tilt measurements.  However, the previous values of pulseLeft and pulseRight have to be remembered so that 8 can either be added to r subtracted from each.  These two lines store the values of pulseLeft into pulseLeftOld, and pulseRight into pulseRightOld so that the current values are remembered the next time through the loop.

pulseLeftOld  = pulseLeft
pulseRightOld = pulseRight

Here are the familiar servo pulses.  After these, the LOOP command sends the program back up to DO, and the main routine repeats itself.

PULSOUT 13, pulseLeft
PULSOUT 12, pulseRight
PAUSE 20

 

Your Turn – Incline Sensitivity and Response Speed

You can make the Boe-Bot more or less sensitive to tilt by modifying the IF...ELSEIF...ELSE...ENDIF statement.  For example, IF ABS(y) > 60 will make it so that you have to tilt the Boe-Bot higher before it starts to move.  Changing the value of 8 in the IF...THEN statements that do the increment/decrement job will cause the Boe-Bot to ramp quicker or more slowly. 

  • Experiment with the ABS and increment/decrement values to get your Boe-Bot to perform the best it can on hills.