Pages

Wednesday, 11 March 2020

Driving Anastasia's Kitronik motor controller via radio

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:
  1. stop applies a brake to the motors.
  2. left spins the robot anti-clockwise.
  3. right spins the robot clockwise.
  4. forward ( you guessed it1) drives the robot forwards.
  5. 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.

  1. I could add a VL53L0X ToF (Time of Flight) LIDAR sensor.
  2. 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.

No comments:

Post a comment