In previous navigation programs, our scripts only made the cyber:bot execute a list of movements predefined by you, the programmer. Now that you can write a script to make the cyber:bot monitor whisker switches and trigger action in response, you can also write a script that lets the cyber:bot drive and select its own maneuver if it bumps into something. This is an example of autonomous robot navigation.
The roaming_with_whiskers.py script makes the cyber:bot go forward while monitoring its whisker inputs, until it encounters an obstacle with one or both of them. As soon as the cyber:bot senses whisker electrical contact, it uses an if…elif…else statement to decide what to do. The decision code checks for various whisker pressed/not pressed combinations, and calls navigation functions to execute back-up-and-turn maneuvers. Then, the cyber:bot resumes forward motion until it bumps into another obstacle.
Let’s try the script first, and then take a closer look at how it works.
# roaming_with_whiskers from cyberbot import * def forward(): bot(18).servo_speed(75) bot(19).servo_speed(-75) def backwards(): bot(18).servo_speed(-75) bot(19).servo_speed(75) sleep(250) def right(): bot(18).servo_speed(75) bot(19).servo_speed(75) sleep(250) def left(): bot(18).servo_speed(-75) bot(19).servo_speed(-75) sleep(250) while True: whisker_left = bot(7).read_digital() whisker_right = bot(9).read_digital() if whisker_left == 0 and whisker_right == 0: backwards() right() elif whisker_left == 1 and whisker_right == 0: backwards() left() elif whisker_left == 0 and whisker_right == 1: backwards() right() else: forward()
The first part of roaming_with_whiskers defines the four navigation functions: forward, left, right, and backwards. Notice how the left, right, and backwards functions all have a sleep function. Every time each of these functions are called, the cyber:bot moves in that direction for a predetermined amount of time. 750 milliseconds is enough time to back up away from an obstacle, and 500 milliseconds makes about a 90 degree turn to the right or the left. The forward function does not have a sleep function call inside of it.
def forward(): bot(18).servo_speed(75) bot(19).servo_speed(-75) def backwards(): bot(18).servo_speed(-75) bot(19).servo_speed(75) sleep(750) def right(): bot(18).servo_speed(75) bot(19).servo_speed(75) sleep(500) def left(): bot(18).servo_speed(-75) bot(19).servo_speed(-75) sleep(500)
After the four navigation functions have been defined, the script enters into the while True: loop. Inside of this loop, we have a four-part if statement. The first thing it checks is if both whiskers are touching, that is, if both whisker_left and whisker_right are equal to 0. If this is true, then the program runs through the backwards and right functions making the cyber:bot backup and then turn right, presumably away from the obstacle.
if whisker_left == 0 and whisker_right == 0: backwards() right()
If whisker_right and whisker_left are not touching, then the program goes to the next part of the if statement which says else if (elif) the left whisker is not touching (whisker_left == 1) and the right whisker is touching (whisker_right == 0), then the program executes the backwards and left functions.
elif whisker_left == 1 and whisker_right == 0: backwards() left()
If the if statement has still not found a true condition, then it checks to see if the left whisker is touching (whisker_left == 0) and the right whisker is not touching (whisker_right == 1). If this it true, the program executes the functions backwards and right.
elif whisker_left == 0 and whisker_right == 1: backwards() right()
Finally, if all three of the above conditions are not met, the program executes the forward function and drives a little bit before once again checking to see if an obstacle is detected.
Compact Code — The script could have lastly checked:
elif whisker_left == 1 and whisker_right == 1:
...instead of using just else:, however, the only condition remaining at the end was that neither whisker was touching (whisker_right and whisker_left are both equal to 1). Although both of these would have worked, else: is used because it shortens the code.
Compact it More — To make the script even more compact, shorten the variable names used to define each maneuver and to store the whisker I/O pin states. This could help if want to combine whisker navigation with other sensor input or with piezospeaker sounds.