With your IR object sensors built and tested, you are ready to make your ActivityBot roam and avoid obstacles without bumping into them.
IR Roaming Code
The IR Roaming code example makes the ActivityBot go forward until it detects an obstacle. If it sees an obstacle on the left, it’ll turn right. Likewise, if it sees one on the right, it’ll turn left, and if it sees obstacles on both left and right, it’ll back up.
Not all obstacles are visible.
Many black objects will absorb infrared light instead of reflecting it. If in doubt, use your LED indicator program from the Build and Test the IR Detectors "Try This" section. The LEDs will show you if the object is visible to the IR object detectors.
- Click SimpleIDE’s Open Project button.
- Open IR Roaming from ...Documents\SimpleIDE\Learn\Examples\ActivityBot.
- Click the Load EEPROM & Run button.
- Let your robot loose on the floor, or in an obstacle course you have created and see how it does.
How it Works
This example is almost identical to Test IR Detectors.c from Build and Test the IR Sensor Circuits. The code changes are:
- A drive_setRampStep call was added to the initialization.
- The print statement was replaced by an if…else if…else if…else statement.
- The pause(100) was removed.
/* IR Roaming.c Use IR LEDs and IR receivers to detect obstacles while roaming. */ #include "simpletools.h" // Library includes #include "abdrive.h" int irLeft, irRight; // IR variables int main() // main function { low(26); // D/A0 & D/A1 to 0 V low(27); drive_setRampStep(12); // Max step 12 ticks/s every 20 ms while(1) { freqout(11, 1, 38000); // Check left & right objects irLeft = input(10); freqout(1, 1, 38000); irRight = input(2); if(irRight == 1 && irLeft == 1) // No obstacles? drive_rampStep(128, 128); // ...full speed ahead else if(irLeft == 0 && irRight == 0) // Left & right obstacles? drive_rampStep(-128, -128); // ...full speed reverse else if(irRight == 0) // Just right obstacle? drive_rampStep(-128, 128); // ...rotate left else if(irLeft == 0) // Just left obstacle? drive_rampStep(128, -128); // ...rotate right } }
The drive_rampStep function is designed to be used in loops. After our call to drive_setRampStep(12), if a loop calls drive_rampStep(128, 128) it will increase speed 12 ticks/second at a time toward a final 128 ticks per second every time it’s called. If it’s calling 50 times per second (20 ms pauses), it will take 11 repeated calls (11/50ths of a second) to get to full speed. After the ActivityBot reaches full speed, repeated calls to drive_rampStep(128, 128) don’t change the speed any because it’s already there. If the loop then starts repeating drive_rampStep(-128, -128) calls, it’ll take 22/50ths of a second (getting close to half a second) to ramp from full speed forward to full speed reverse.
The if…else if…else if…else statement is what uses the irLeft and irRight detection result values for navigation. For example, if(irRight == 1 && irLeft == 1) it means that no objects are detected, so drive_rampStep(128, 128) sends the ActivityBot a 12 ticks/second step toward 128 ticks per second if it both wheels aren’t already running at that speed. If the ActivityBot sees an obstacle on it’s right, the else if(irRight == 0) condition becomes true, so each time through the loop, it takes 12 ticks/second steps toward rotating left in place every 50th of a second. Rotating in in place is achieved with the left wheel turning at full speed backwards at -128 ticks/second and the right turning at 128 ticks/second forward.
As the ActivityBot rotates left to avoid the right obstacle, the obstacle will disappear from the right detector’s view. At that point, the detection states will go back to irLeft == 1 and irRight == 1, which will make the first if statement true again, and drive_rampStep(128, 128) will start ramping back to full speed forward.
A pause between while(1) loop repetitions is not needed because the drive_rampStep function delays 1/50th of a second before returning.
Did You Know?
drive_setRampStep — This function sets the maximum change in speed that drive_rampStep can cause every 1/50 of a second. The abdrive library defaults to 4, which means that the largest change in speed allowed is 4 ticks/second every 50th of a second. Although that default makes drive_ramp and drive_rampStep maneuvers nice and smooth, it’s not enough change in a small amount of time to detect and avoid obstacles at full speed. So, drive_setRampStep(12) triples the speed change allowed every 50th of a second. Not quite as smooth, but responsive enough to avoid the obstacles.
Try This
You can reduce the roaming speeds by changing the 128's in the program to lower values.
- Use the Save Project As button to save a copy of your project in …Documents\SimpleIDE\My Projects.
- Try changing all the 128 values in your program to 64. Make sure to leave all the negative signs in place.
- Run the modified program and let the ActivityBot roam at half speed.
Your Turn
Increasing the value used in the drive_setRampStep function call to a higher value will make the robot more responsive, but also more twitchy. Reducing the value will make it smoother, but at some point, it won’t respond quickly enough and it will run into obstacles.
- Re-open the original, unmodified IR Roaming example from ...Documents\SimpleIDE\Learn\Examples\ActivityBot.
- Click the Save Project As button to save another copy and give it a new name.
- Experiment with increasing and decreasing the drive_setRampStep parameter.
- How low can you go before it starts running into the same obstacles it used to be able to see and avoid.
- How large can you make it before the ActivityBot’s behavior becomes noticeably twitchy?