In this lesson you create a simple Line Follower program for Codebot. It builds on the knowledge of
botservices and event-driven programming you gained in the last two lessons.
When you get this code running, your CodeBot will be acting intelligently based on its senses!
1. Tracking the Line Sensors¶
First step is to try out the
BotServices.on_line event. Your callback function will run whenever there
is a change detected on any of CodeBot’s 5 Line Sensors.
This callback function has one parameter: a list of the sensor states with a boolean value for each of the 5 sensors. For example,
[True, False, False, False, False]would mean that only sensor 0 is detecting a line.
Look at your ‘Bot, and notice how the line sensors are numbered across its front edge. Above each number is an LED which can be used to show line-detection. But this does not happen automatically. You have to code it!
Type in the code below, and test that the LEDs light up as you pass something reflective beneath each sensor:
# Import everything from botcore module. Provides leds, motors, and other stuff we may need. from botcore import * # Import the BotServices event loop code, so we can do "event-driven" robot control! from botservices import BotServices # Set up BotServices so we can hook our event-handler functions into it. bot = BotServices() # ---- First define some functions to do the work ---- # "Callback" function to handle changes in Line Sensor readings def handle_line(sensors): # Light the LS LEDs corresponding to the new LS Sensor readings leds.ls(sensors) # Conveniently this function accepts a list of bools! # ---- Now initialize stuff and kick this thing off! ---- # Hook our "callback" functions into BotServices bot.on_line(handle_line) # Start the event-loop! It runs forever, calling our "callback" functions when needed! bot.loop()
2. Adapting the Sensors to Your Lines¶
CodeBot’s Line Sensors work by shining a small infrared LED on the surface below, and checking for a reflection of that light. The reflection is read as an analog value from each sensor, in the range 0-4095 with 0 being the brightest reflection and 4095 being the least reflection.
- A common problem with Line Followers is that there are different types of lines, with different reflectivity characteristics.
- Do you have black lines against a white background, or the other way around?
- How much contrast is there between the “light” and “dark” your Line Sensors will be checking against?
BotServices.config_ls() function lets you calibrate the Line Sensors to accommodate your situation like so:
# Configure for a threshold of 2000 and a black line (reflective_line = False) # With this configuration, any reading over 2000 will be considered a line detected! bot.config_ls(2000, False)
Add the code snippet above to your test program, on the next line after
bot = BotServices(). Experiment to verify it
works with black lines against a white background, then change the
bool parameter to
True and make sure it
detects white lines against a dark background too (that’s the default behavior).
Now set up your own line course! Nothing too fancy yet, just some gradual bends or gentle turns to get started.
config_ls() parameters and test that the green LS LEDs show your ‘bot is detecting your line properly.
3. A first simple line follower program¶
With 5 line sensors, CodeBot is capable of very sophisticated line following! But to start with, we will use a simple algorithm that uses 3 sensors:
- Do nothing until a Line Sensor changes.
- If middle sensor sees the line, go straight.
- If left sensor sees the line, go left.
- If right sensor sees the line, go right.
Notice that the left and right logic above assumes that those sensors are normally straddling the line, on either side of it. So when the ‘Bot is veering left, the right sensor will touch the line first.
Read through the code below one-line-at-a-time. Type it in and see if it works the way you expected:
"""Line follower - version 1 """ # Import everything from botcore module. Provides leds, motors, and other stuff we may need. from botcore import * # Import the BotServices event loop code, so we can do "event-driven" robot control! from botservices import BotServices # Give names to the Line Sensors we'll use LS_LEFT = 0 LS_MIDDLE = 2 LS_RIGHT = 4 # Variable we use below to toggle motor enable on button press. enable_run = False # Set up BotServices so we can hook our event-handler functions into it. bot = BotServices() # Configure for a threshold of 2000 and a black line (reflective_line = False) bot.config_ls(2000, False) # Define some functions to drive the motors. def go_left(): motors.run(LEFT, 25) motors.run(RIGHT, 50) def go_right(): motors.run(LEFT, 50) motors.run(RIGHT, 25) def go_straight(): motors.run(LEFT, 50) motors.run(RIGHT, 50) # "Callback" function to handle changes in Line Sensor readings def handle_line(sensors): # Light the LS LEDs corresponding to the new LS Sensor readings leds.ls(sensors) if sensors[LS_LEFT]: # Left sensor hit line. Turn left! go_left() elif sensors[LS_RIGHT]: # Left sensor hit line. Turn right! go_right() elif sensors[LS_MIDDLE]: # Middle sensor hit line. Go straight! go_straight() # "Callback" function to handle button presses def handle_button(buttons): global enable_run # Let BTN-0 turn motors on/off if buttons: enable_run = not enable_run motors.enable(enable_run) # ---- Now initialize stuff and kick this thing off! ---- # Hook our "callback" functions into BotServices bot.on_line(handle_line) bot.on_button(handle_button) # Start the event-loop! It runs forever, calling our "callback" functions when needed! bot.loop()
Now that you have your basic Line Follower working, experiment with some of the values above.
- Are the turns too tight, or too gradual?
- How does it handle different kinds of curves and turns in the line?
- Can you speed the ‘Bot up?
You can probably think of lots of improvements to this algorithm. Imagine if you could write code to have the ‘Bot zip around a line course at full speed! What’s stopping you!?