From the Archives: The micro:bit and motors
Experimenting with controlling my @codemyrobot with a #microbit (on loan from @KidsCoding and @afmcdnl)! Excited for #LNDLCA 2018 where I'll be working with educators to develop coding and computational thinking skills! (cc @mshagerman @Megan_C_K @edukatik) pic.twitter.com/aYGmRuKPwH
— Jonathan (@jernwerber) June 7, 2018
Another one from the archives, hence the date. Here I go into a bit more detail on a very common IC, the L9110 motor driver, and write some MicroPython that allows a micro:bit to function as a rudimentary controller for a robotics platform.
After a bit of tinkering, I made a short clip of a micro:bit being used to control a robot platform. One of the challenges of using the micro:bit for something like this is the limit on the amount of current (mA) the micro:bit can provide. In some cases, the voltage (max 3.3V) that it can provide is also an issue.
In this particular case, the platform (from CodeMyRobot) uses a separate chip (or integrated circuit/IC) to drive the two motors, one for each wheel. Usually, integrated circuits will have a model number written on them to identify them. In this case, the chip being used was an L9110. A quick Google search later, and I had found a description of the L9110, including how to control it1. Once supplying it with power, two inputs could be used to control the direction of a motor:
Pin A |
Pin B |
Output |
---|---|---|
L |
L |
Off |
H |
L |
Forward |
L |
H |
Backward |
H |
H |
Off |
So, according to that table, if you wanted the motor to spin forward, you would set Pin A
to HIGH
and Pin B
to LOW
. On the micro:bit, if you’re not using a breakout board, you have access to three pins along the bottom edge: Pin 0
, Pin 1
, and Pin 2
. You also have a 3.3V power pin (which can either be an input or an output) and a ground pin. We have to be the ones to tell the micro:bit which pins it should be using and how. In our case, we can say that Pin 0
will correspond to Pin A
, and Pin 1
will correspond to Pin B
. If we want the motor to run forward when, say, Button A
is pressed, our MicroPython code might look something like:
from microbit import *
while True:
# Go forward
if button_a.is_pressed():
pin0.write_digital(1) # Pin A = High
pin1.write_digital(0) # Pin B = Low
# Stop
else:
pin0.write_digital(1) # Pin A = High
pin1.write_digital(1) # Pin B = High
So, as long as Button A is pressed, the motor will run forward; as soon as it’s not pressed, both Pin 0/A and Pin 1/B are set to “High” which, according to our table, means the motor shuts off. In the video above, both motors are using the same inputs, i.e. I’m sending the same signals to two L9110 chips, which make the motors attached to them behave the same way. This means, though, that I can only move forward or backward, because to turn, I need to have one motor running faster than the other, which means having them do different things. I can accomplish this through use of the third pin (Pin 2) and sharing one of the pins. Consider the following setup:
- we have our left motor as Motor A and our right motor as Motor B
Pin 0
is nowPin A
for Motor APin 1
is nowPin A
for Motor BPin 2
is shared, and isPin B
for Motor A+B
Then, to get the micro:bit to put out the correct signals on its pins, we have to figure out what the desired outputs should be, as in below:
Desired outputs | Pin 0 |
Pin 1 |
Pin 2 |
---|---|---|---|
Off | L |
L |
L |
Forward (i.e. Motor A+B forward) | H |
H |
L |
Backward (i.e. Motor A+B backward) | L |
L |
H |
Left (i.e. Motor B only forward) | L |
H |
L |
Right (i.e. Motor A only forward) | H |
L |
L |
The code below defines a few functions to make our lives easier if we wanted to reuse or combine any of these actions. It runs through a sequence of forward()
, back()
, left()
, then right()
, for 0.75 seconds each, with a 4 second stop()
in between.
from microbit import *
wait_amount = 750
motor_a_pin_a = pin0
motor_b_pin_a = pin1
motor_shared_pin = pin2
def forward():
motor_a_pin_a.write_digital(1)
motor_b_pin_a.write_digital(1)
motor_shared_pin.write_digital(0)
def backward():
motor_a_pin_a.write_digital(0)
motor_b_pin_a.write_digital(0)
motor_shared_pin.write_digital(1)
def left():
motor_a_pin_a.write_digital(0)
motor_b_pin_a.write_digital(1)
motor_shared_pin.write_digital(0)
def right():
motor_a_pin_a.write_digital(1)
motor_b_pin_a.write_digital(0)
motor_shared_pin.write_digital(0)
def stop():
motor_a_pin_a.write_digital(0)
motor_b_pin_a.write_digital(0)
motor_shared_pin.write_digital(0)
while True:
stop()
display.show(Image.ASLEEP, wait=False)
sleep(4000)
forward()
display.show(Image.ARROW_N, wait=False)
sleep(wait_amount)
backward()
display.show(Image.ARROW_S, wait=False)
sleep(wait_amount)
left()
display.show(Image.ARROW_W, wait=False)
sleep(wait_amount)
right()
display.show(Image.ARROW_E, wait=False)
sleep(wait_amount)
This would depend on your physical setup– for example, when I plugged everything in the first time, everything was reversed. It was an easy switch–swapping the physical connections of Pins 0 and 1. You can see the video of the code running in this tweet:
#LNDLCA in two short weeks! brushing up on my Python and micro:bit skills with a blog post about the motor drivers (https://t.co/e1tRu0HsyI) and a video (code included)! (cc @mshagerman @afmcdnl @KidsCoding) pic.twitter.com/H2FdYnA9W0
— Jonathan (@jernwerber) June 26, 2018
-
One of the easiest ways to figure out what a device is capable of is to read (or at least search) the documentation. For example, how did I know how to “tell” the pins to be high or low? I checked the documentation for MicroPython, micro:bit, and how to use its pins: http://microbit-micropython.readthedocs.io/en/latest/microbit_micropython_api.html#pins ↩