| Reflex Example 3: Wall-following | Index |
The Problem
Imagine a robot with a distance sensor on its right side and two motors, with each motor driving wheels on opposite sides of the robot. The robot can move forward by turning both motors on. It can turn left by turning the left motor off and right motor on. It can turn right by turning the right motor off and the left motor on. Now suppose the robot must follow a wall to its right.
The Simple Solution
Here is some logic to make the robot follow a wall:
The Details
This logic is fine, but does not convert easily into reflexes. We need to describe it in terms that can be directly translated into BrainStem commands. To do so, we need to know some specifics about our robot. Its distance sensor is a Sharp GP2D02. The GP2D02 reading increases as an object gets closer, so let 144 be the threshold for "too close" and 136 be the threshold for "too far". A measurement between 144 and 136 will be "just right". The motors on the robot are two modified servos. Setting a servo position to 120 makes it go forward. Setting a servo position to 60 makes it stop. Servo 0 is the left motor. Servo 1 is the right motor. We also need the help of a window comparator. The window comparator (see cmdWINDOW ) makes it easy to check if the distance measurement is too close, too far, or just right. With all these details defined, the commands to implement the wall-following logic are:
| Reflex 100 | Get byte (distance) from GP2D02 and issue Reflex 10 with that byte as input. |
| Reflex 10 | Apply measurement R as input to a window comparator. If "just right" ((R < 144) and (R > 136)) then issue Reflex 101. If "too far" (R < 144) then issue Reflex 102. If "too close" (R > 136) then issue Reflex 103. |
| Reflex 101 | Set position of servo 0 to 120. Set position of servo 1 to 120. Issue Reflex 100. |
| Reflex 102 | Set position of servo 0 to 120. Set position of servo 1 to 60. Issue Reflex 100. |
| Reflex 103 | Set position of servo 0 to 60. Set position of servo 1 to 120. Issue Reflex 100. |
Take a moment to examine the table. Start at Reflex 100 and try to follow the different paths. It is equivalent to the logic of the simple solution described earlier. At this point you may be wondering about the numbering of the reflexes. Reflexes 100-103 are free for general purpose use. Reflex 10 is activated when a GP2D02 reading is complete. The value 10 corresponds to the device ID for the GP2D02 input.
The Commands
In the reflexive routine described above, there are really only seven unique commands. These seven commands, complete with address byte and size byte, are listed below. They are numbered from 0 to 6. Note the (0) in command 1. It represents a byte that will be a modifiable parameter in the final reflexive routine. Also note how the four lines of logic for command 1 may be implemented with a single command. The reflex elements dramatically increase the power of reflexive routines.
| 0 | Get byte (distance) from GP2D02 and issue Reflex 10 with that byte as input. | 2 2 30 64 |
| 1 | Apply measurement R as input to a window comparator. If "just right" ((R < 144) and (R > 136)) then issue Reflex 101. If "too far" (R < 144) then issue Reflex 102. If "too close" (R > 136) then issue Reflex 103. | 2 5 48 101 (0) 144 136 |
| 2 | Set position of servo 0 to 120. | 2 3 33 0 120 |
| 3 | Set position of servo 0 to 60. | 2 3 33 0 60 |
| 4 | Set position of servo 1 to 120. | 2 3 33 1 120 |
| 5 | Set position of servo 1 to 60. | 2 3 33 1 60 |
| 6 | Issue Reflex 100. | 2 3 38 100 0 |
These commands go in reflex command slots 0-6. The series of cmdMSG_WR commands listed below will save the command data into the appropriate locations in the EEPROM. Note that Reflex Command 1 must be saved with two cmdMSG_WR commands because it is too long to be saved with a single command.
| Reflex CMD 0 | 2 12 128 0 2 2 30 64 |
| Reflex CMD 1 | 2 12 0 2 5 48 101 0 144 2 12 134 1 136 |
| Reflex CMD 2 | 2 12 128 2 2 3 33 0 120 |
| Reflex CMD 3 | 2 12 128 3 2 3 33 0 60 |
| Reflex CMD 4 | 2 12 128 4 2 3 33 1 120 |
| Reflex CMD 5 | 2 12 128 5 2 3 33 1 60 |
| Reflex CMD 6 | 2 12 128 6 2 3 38 100 0 |
The Vectors
Now that the reflex commands are in the EEPROM, we need to define the reflex vector data for reflexes 10, 100, 101, 102, and 103. A reflex vector is an array of up to eight 2-byte records. Each record contains a command index and control fields for executing that command. The vectors in this example have either one or three records per vector. The binary contents of each vector along with a description of what the contents mean is listed below:
| Reflex Vector 10 | Cmd 1, (last in vector), byte[4] = byte[4] + input | [ 1 | 0000001 ] [ 1 | 001 | 0100 ] | 129 148 |
| Reflex Vector 100 | Cmd 0, (last in vector) | [ 1 | 0000000 ] [ 1 | 000 | 0000 ] | 128 128 |
| Reflex Vector 101 | Cmd 2 Cmd 4 Cmd 6, (last in vector) | [ 0 | 0000010 ] [ 1 | 000 | 0000 ] [ 0 | 0000100 ] [ 1 | 000 | 0000 ] [ 1 | 0000110 ] [ 1 | 000 | 0000 ] | 2 128 4 128 134 128 |
| Reflex Vector 102 | Cmd 2 Cmd 5 Cmd 6, (last in vector) | [ 0 | 0000010 ] [ 1 | 000 | 0000 ] [ 0 | 0000101 ] [ 1 | 000 | 0000 ] [ 1 | 0000110 ] [ 1 | 000 | 0000 ] | 2 128 5 128 134 128 |
| Reflex Vector 103 | Cmd 3 Cmd 4 Cmd 6, (last in vector) | [ 0 | 0000011 ] [ 1 | 000 | 0000 ] [ 0 | 0000100 ] [ 1 | 000 | 0000 ] [ 1 | 0000110 ] [ 1 | 000 | 0000 ] | 3 128 4 128 134 128 |
This vector data goes into reflex vector slots 10, 100, 101, 102, and 103. The series of cmdVEC_WR commands listed below will save the vector data into the appropriate locations in the EEPROM. Note that vectors 101, 102, and 103 must be saved with two cmdMSG_WR commands because they are too long to be saved with a single command.
| Vector 10 | 2 11 128 10 129 148 |
| Vector 100 | 2 11 128 100 128 128 |
| Vector 101 | 2 11 0 2 128 4 128 134 128 2 11 134 101 |
| Vector 102 | 2 11 0 2 128 5 128 134 128 2 11 134 102 |
| Vector 103 | 2 11 0 3 128 4 128 134 128 2 11 134 103 |
The Results
The reflexive wall-hugging routine is now completely defined. A text batch file can store all the commands for downloading the reflex data. Copy and paste the following lines of numbers to a file called "wh.txt" in your "aUser" directory. The Console can download the file to the BrainStem. Just enter batch "wh.txt" at the prompt.
You do not need an actual robot to test the routine. Simply connect a GP2D02 and two modified servos. You can also use regular servos for testing. If using modified servos, you may want to "match" them using the procedure described in the BrainStem Modified Servo Example. Enter the following command to start the wall-following reflex:
Move your hand up and down over the GP2D02. If you are using modified servos, you should see the servos turn on and off as you move your hand through the "too close", "just right", and "too far" ranges. If you are using regular servos, they will change position in response to changing distance. To stop this reflexive routine, you will need to reset the BrainStem with the cmdRESET command, or turn off the power.
This reflexive wall-following routine is nearly identical to the one used by 1-BDI, a robot built at Acroname.
Here is a LEAF source file for the reflex routine in this example:
| ex3_wf.leaf |
![]() Download "ex3_wf.leaf" here |
| /* file: ex3_wf.leaf */ #include <aCmd.tea> #include <aGPReflexes.tea> /* assume the BrainStem has address 2 */ #define MODULE 2 /* message ids */ #define mREAD02 0 #define mWINDOW 1 #define mSRV0_120 2 #define mSRV0_60 3 #define mSRV1_120 4 #define mSRV1_60 5 #define mREPEAT 6 /* user-defined vectors */ #define vGO 100 #define vWINDOW0 101 #define vWINDOW1 102 #define vWINDOW2 103 module[MODULE] { /************* REFLEX COMMANDS *************/ /* read GP2D02 */ message[mREAD02] { MODULE, cmdIR02_RD, 0x40 } /* window comparator applied to GP2D02 reading */ message[mWINDOW] { MODULE, cmdWINDOW, vWINDOW0, 0, (unsigned char)144, (unsigned char)136 } /* servo 0 to position 120 */ message[mSRV0_120] { MODULE, cmdSRV_ABS, 0, 120 } /* servo 0 to position 60 */ message[mSRV0_60] { MODULE, cmdSRV_ABS, 0, 60 } /* servo 1 to position 120 */ message[mSRV1_120] { MODULE, cmdSRV_ABS, 1, 120 } /* servo 1 to position 60 */ message[mSRV1_60] { MODULE, cmdSRV_ABS, 1, 60 } /* servo 1 to position 60 */ message[mREPEAT] { MODULE, cmdRAW_INPUT, vGO, 0 } /************* REFLEX VECTORS *************/ /* measurement ready */ vector[aGP_RFX_GP2D02_0] { char + mWINDOW[4] } /* wall-hug straight */ vector[vWINDOW0] { mSRV0_120, mSRV1_120, mREPEAT } /* wall-hug */ vector[vWINDOW1] { mSRV0_120, mSRV1_60, mREPEAT } /* wall-hug */ vector[vWINDOW2] { mSRV0_60, mSRV1_120, mREPEAT } /* repeat */ vector[vGO] { mREAD02 } } |
Here is the BAG output from the LEAF compiler:
| ex3_wf.bag |
![]() Download "ex3_wf.bag" here |
// module 2 (7 messages, 5 vectors) // message 0 2 12 128 0 2 2 30 64 // message 1 2 12 0 2 5 48 101 0 144 2 12 134 1 136 // message 2 2 12 128 2 2 3 33 0 120 // message 3 2 12 128 3 2 3 33 0 60 // message 4 2 12 128 4 2 3 33 1 120 // message 5 2 12 128 5 2 3 33 1 60 // message 6 2 12 128 6 2 3 38 100 0 // vector 10 2 11 128 10 129 148 // vector 100 2 11 128 100 128 128 // vector 101 2 11 0 2 128 4 128 134 128 2 11 134 101 // vector 102 2 11 0 2 128 5 128 134 128 2 11 134 102 // vector 103 2 11 0 3 128 4 128 134 128 2 11 134 103 |
This batch file contains the same commands for downloading the reflex that were listed for the "wh.txt" file, but in a different order.