The MicroPython Lego Bot

In the quest for getting my kids interested in coding, I’ve decided to make them a message controlled bot car with Lego bricks and an ESP8266 board. The idea is to have an environment where we can jointly program a sequence of actions that can be sent via WiFi to the bot for execution. With this setup we can make challenges like creating the optimal sequence for navigating through a maze or simply try out crazy movements & mayhem just for the fun of it. Hopefully, having an assignment were you need to connect an abstraction like a sequence of symbols with a physical object will ignite a spark of interest for electronics and the basics of programming.

This post describes the first part of this project. I will use Lego bricks and some servos to build a car bot and mount an ESP8266 board loaded with MicroPython. To begin with, the bot will be controlled via WiFi through MicroPython’s WebREPL.

Parts needed

To create the first version of the bot, these parts are needed:

Building the bot

The first version of the bot does not have to be pretty, it just needs to be functional and be able to house the microprocessor board, servos and the batteries. Lego mini-figures are optional.

We’ll need a Huzzah board and a FeatherWing with a servo driver. I use a FeatherWing doubler to connect the Huzzah and the FeatherWing (the servo board can also be stacked on top of the Huzzah with appropriate headers):


I will use two continuous rotation servos (with servo wheels) and three standard micro servos for the bot’s weapons. The Kragle fixes 2×3 bricks to the servos.


To power the Huzzah, I use a 3.7V LiPo battery. The servos need a separate power source. I use 4xAA batteries in a box.


Finally, we need some Lego parts. More job for the Kragle. I have glued the caster ball to a flat 4×2 brick (in turn glued to a 4×2 normal brick) and also fixated three servo horns to Lego bricks.


The big battery box goes under the bot and the servos, boards and 3.7V battery is put on top.


Hey Ho Let’s Go!

PWM servo basics

An analogue Pulse-Width-Modulation servo is controlled by a signal where the width of the pulses controls the angle of rotation of the motor axis. A typical servo can rotate the axis between 0 and 180 degrees with control signals in the ms range. A continuous rotation servo is a modified standard servo where the feedback loop has been removed. In these servos,  the pulse width will define the speed and direction of the rotation. With a servo library, you would typically get no movement when sending 90 degrees to a continuous rotation servo and increasing speeds in one direction with degrees 89-0 and increasing speeds in the other direction with degrees 91-180.

Calibrating the servos

The FS90R servo has an accessible potentiometer that controls what pulse width that defines “stop”. On my inexpensive micro servos, the potentiometer drifts easily, so frequent adjustments are needed.


I have mounted rubber wheels (for traction) and glued 2×3 Lego bricks (for attachment purposes) on the servos.

Powering the servos

The ESP8266/Huzzah-board will not be able to provide enough current for running the servos directly. Thus a separate power supply with a driver is needed and the Huzzah will only provide the control signals. You could wire up an H-bridge for this purpose, but I use a FeatherWing servo board with i2C-communication that fits directly on the Huzzah (or beside it when using a FeatherWing doubler).

Servos with MicroPython

Adafruit has a MicroPython library that can be used with the FeatherWing for accessing the servos:

You will need to download pca9685.mpy and servo.mpy and transfer them to the board with ampy.

MicroPython basics

For this project, MicroPython needs to be flashed on the ESP8266/Adafruit Huzzah. I use version 1.8.5 of MicroPython for ESP8266. Adafruit has several tutorials on how to flash and use MicroPython with an ESP8266 board:

To program the board I use Visual Studio Code on a Mac Book Air for typing Python scripts and Adafruit’s ampy tool for uploading the scripts:

To program the the board via WiFi, I use MicroPython’s WebREPL:

Programming the bot

I want the bot to act on a sequence of action commands. To keep it simple, an action can be defined as a single character and a whole sequence can be a string. For example, to move forward two steps, turn right, move forward one step and then turn left, the command string would be:


To lift and lower the front weapon (hammer) and open and close the side weapons (claws), I would use:


(Up, Down, Open, Close)

So, I need a Python method that takes a string as an argument, iterates over each character and then performs an action depending on that character. This is accomplished with a dictionary that maps between characters and object methods.

action_methods = {
'F' : wheels.fw_step,
'B' : wheels.back_step,
'L' : wheels.turn_left,
'R' : wheels.turn_right,
'S' : wheels.stop,
'U' : hammer.up,
'D' : hammer.down,
'O' :,
'C' : claws.close
def run(sequence):
for action in sequence:
if action in action_methods:

The action implementations

Forward- and backward movements are created by rotating the wheels in the same direction. But as the wheels are mounted on opposite sides of the vehicle, the programmed directions through the servo library are actually opposite:

def stop():
"""Stops the wheels"""
servos.position(left_wheel, degrees=90)
servos.position(right_wheel, degrees=90)
def fw_step():
"""Moves the bot forward one step"""
servos.position(left_wheel, degrees=90 + wheel_speed)
servos.position(right_wheel, degrees=90 wheel_speed + drift)
def back_step():
"""Moves the bot backwards one step"""
servos.position(left_wheel, degrees=90 wheel_speed)
servos.position(right_wheel, degrees=90 + wheel_speed + drift)

view raw

hosted with ❤ by GitHub

Left- and right turns are created by rotating the wheels in opposite directions and the weapons are controlled by standard micro servos that can rotate between 0 and 180 degrees.

The complete implementation exists in a Bot class that aggregates a Wheels-, a Hammer- and a Claws object. Each helper object defines the behaviour of their particular servo(s).

The code for the Bot class looks like this:

A bot with servos for an Adafruit Feather Huzzah
Requires the Adafruit PWM servo library:
Uses a FeatherWing servo board attached with i2C
import machine
import servo
import utime
from wheels import Wheels
from hammer import Hammer
from claws import Claws
class Bot(object):
A robot car with two continuous servos as wheels
and three standard servos as weapons (hammer and claws)
def __init__(self):
# Setup pins to use for i2c and create the servos object
i2c = machine.I2C(machine.Pin(5), machine.Pin(4))
servos = servo.Servos(i2c)
# Create the the servo controlled parts of the bot
# and assign the control pins to use
self.wheels = Wheels(servos, 0, 1)
self.hammer = Hammer(servos, 5)
self.claws = Claws(servos, 7, 6)
# A mapping between each command and the
# corresponding method on the servo objects
self.action_methods = {
'F' : self.wheels.fw_step,
'B' : self.wheels.back_step,
'L' : self.wheels.turn_left,
'R' : self.wheels.turn_right,
'S' : self.wheels.stop,
'U' : self.hammer.up,
'D' : self.hammer.down,
'O' :,
'C' : self.claws.close
def run(self, sequence):
Input is a string where each character
represents an action. Each action is executed according
to the defined action method mapping
for action in sequence:
if action in self.action_methods:

view raw

hosted with ❤ by GitHub

The code for the other classes are available in GitHub:

Testing the bot

The ingenious WebREPL let’s you have a Python prompt in a browser that directly communicates with the ESP8266. It lets you upload scripts remotely that you can import in the REPL and work with.

I assume that you have setup the ESP8266 with MicroPython WebREPL (see the previously mentioned tutorial link from Adafruit) and also uploaded the Adafruit mpy files for the servo library and the,, and files from my GitHub repository to the board with ampy. Then we can connect to the ESP8266’s access point and start the WebREPL. After logging in we can try out the bot:


Calibration and live editing of properties

As the mechanics of the servos and the attached wheels is not top of the line, it is hard to get perfect movements (like a forward movement along a straight line). Thus, I have some calibration parameters in my script that I use for adjusting the movements for a particular setup. When working via the MicroPython WebREPL it is easy to change the parameters on-the-fly:


This would be very tedious work if every change had to go through a compile-flash-load sequence with a compiled language. With MicroPython you can make these changes instantly as it is an interpreted language. Have I mentioned that I love embedded programming with wireless MicroPython?

Possible enhancements

My inexpensive micro servos are not very accurate, nor powerful. It would be interesting to test the setup with more advanced hardware in the future. The FeatherWing servo board has eight servo connections in total, so adding a few more servos for some creative animation could also be a possible enhancement.

Next steps

The next step in my project is to do the bot communication via MQTT. This way, any device on the same network as the bot will be able to send command sequences. Ultimately, I want a REST backend that sends out the commands with the MQTT protocol and a simple HTML front end where the user can define the command sequence. More on this in a later post.

All code for this project is available in GitHub:

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s