 |
Anastasia with the controller |
This is the fourth in a series of articles about Anastasia - a home-brew robot based on the micro:bit.
In
my previous post I shared the micropython code that runs on Anastasia's remote micro:bit controller.
The controller can send one of five commands to
Anastasia:
- stop applies a brake to the motors.
- left spins the robot anti-clockwise.
- right spins the robot clockwise.
- forward ( you guessed it1) drives the robot forwards.
- backward also does what you'd expect.
In this post I'll step through the code than implements these commands on Anastasia.
The code looks for incoming radio messages. It translates those messages into methods on a Driver class. These methods then send control signals to the Kitronik motor controller.
Here's Anastasia's code
The code starts with the necessary imports, and then begins the definition of the
Driver class.
from microbit import *
import radio
class Driver:
"""
Read incoming radio messages and send commands to the motor controller.
"""
def __init__(self, left_pins=(pin16, pin0), right_pins=(pin8, pin12)):
self.pins = left_pins+right_pins
radio.on()
self.commands = {
'stop' : self.stop,
'forward': self.go_forward,
'backward': self.go_backward,
'left': self.spin_left,
'right': self.spin_right,
}
The Driver's
__init__ method allows you to pass in the pins you use to control the motor, but has default values recommended by Kitronik in their
documentation for their Motor Controller.
The left and right motor pins are concatenated and stored in the
pins instance variable which is used later.
The
commands variable contains a dictionary which maps text commands to methods on the driver class.
Let's look at the definitions of the methods.
def stop(self):
self.set_control_pins(1, 1, 1, 1)
def go_forward(self):
self.set_control_pins(0, 1, 0, 1)
def go_backward(self):
self.set_control_pins(1, 0, 1, 0)
def spin_left(self):
self.set_control_pins(1, 0, 0, 1)
def spin_right(self):
self.set_control_pins(0, 1, 1, 0)
Each method uses the set_control_pins method to apply high (1) or low (0) voltages to the pins that are connected to Anastasia's two motors.
Here is the
set_control_pins method:
def set_control_pins(self, *pin_values):
for pin, pin_value in zip(self.pins, pin_values):
pin.write_digital(pin_value)
Handling commands
When Anastasia tries to read a command over the radio it will either get the next command as a text string, or
None if no command has been received.
The
obey method does nothing if its argument is
None. If a message
has been received
obey looks it up in the
commands dictionary. If it's an unknown command
obey ignores it.
If it's a known command
obey translates the command to the corresponding method. Then the method is executed.
def obey(self, message):
if message is None or message not in self.commands:
return
# execute the method if a valid message was received.
self.commands[message]()
The
run method loops forever, looking for a message to obey every 50 milliseconds.
def run(self):
while True:
self.obey(radio.receive())
sleep(50) # 50 ms
Finally, the script creates a
Driver instance and tells it to start running.
Driver().run()
That completes the second iteration of my Anastasia project. For the next step there are two possibilities.
- I could add a VL53L0X ToF (Time of Flight) LIDAR sensor.
- I could replace the micro:bit with the more powerful Adafruit Clue.
Let me know which you'd prefer to see next by posting a comment here or in the
micropython and micro:bit group on Facebook.