DEV Community

Cover image for Building a Bluetooth LE Lego Controller + Web Bluetooth App

Building a Bluetooth LE Lego Controller + Web Bluetooth App

I make things and write about them (╯°□°)╯︵ ┻━┻
・9 min read

(Note: these posts are migrated from my previous blog)

I’m a big fan of Lego, especially the Technic series. Some of these sets come with Power Functions, which adds motors/servos/lights to the model and lets you control them with an IR remote:

2 of my favourite, the excavator and the Mercedes Benz Arocs

2 of my favourite, the excavator and the Mercedes Benz Arocs

Lego Power Functions
Lego Power Functions

Not all sets come with a remote, and for each channel you would need an IR receiver; wouldn’t it be cool if you could control everything with your phone over Bluetooth?

Power Functions: How Do They Work?

All Lego Power Function connectors have 4 wires; 2 of them carry the +/- 9V from the battery box, while the other 2 provide direction and speed control:

Image source [](

The wires C1 & C2 allows you to control to the motors/servos/lights. Drive one of the wires with PWM and the other at ground to control the speed; swapping the input reverses the direction. A great resource to learn more about the Power Function actuators can be found here:

Concept Diagram

System Overview

There are 3 main components to this build:

  1. A Bluetooth module for sending/receiving commands

  2. An Arduino to interpret those commands and output PWM signals

  3. A motor controller that can provide enough current to drive the actuators

I would normally just wire all of these components together and call it a day, but this time I wanted a cleaner solution and try creating my own PCB…

PCB Design and Fabrication

Our build is simple enough that you could hand wire everything and be done with it, but where’s the fun in that? Designing your own PCB is a great learning experience that can be both fun and rewarding; it will also help you down the road as you try to tackle more sophisticated projects. There are quite a few free tools out there that let’s you do that now (e.g. KiCad, Eagle, EasyEDA, Upverter, etc.), with tons of online resources to learn how.

I won’t go into details on how to use these tools in this post (YouTube is your friend), but the first step is to turn the concept diagram into a schematic and choosing the right components:

I used EasyEDA for this design (an online editor), but my favourite is KiCad :)

For the main Arduino controller, I chose the Arduino Pro Micro as I have a few of those around. It also has the right number of GPIO pins we need in a small form factor. I chose the 3.3V variation as our Bluetooth module runs on 2.7V — 3.3V.

For the Bluetooth LE module, I chose the HM-10; it’s based on the CC2541 and can be found for a few dollars on eBay. It has a simple UART interface that simply passes through any data you send to it via its custom Service & Characteristic.

For the motor controllers I chose the TB6612FNG from Toshiba. I originally wanted to use the popular L298N as it’s capable of driving more current. Unfortunately, it is commonly found in the Multiwatt15 package, which is too big for my desired form factor. Each TB6612FNG IC can drive 2 channels, so we’ll need 2 of them total. I also threw in some decoupling capacitors to reduce noise (10uF electrolytic and 0.1uF tantalum).

Last but not least, we’ll need 4 pin connectors for the Power Function Lego connectors. We could have soldered the wires directly to the board, but I wanted to keep things modular (plus connectors look nicer). I chose the popular JST XH connectors.

All the above components can be found on DigiKey or eBay. I always order extras in case I mess up the soldering (or when I lose those super tiny SMD components).

I was lazy and used the auto-route feature,

The next step is to convert your schematic into a board layout. I chose a 2 layer design and placed the components strategically around the board. The Pro Micro, motor controllers, and connectors go on the top for easy access, while the Bluetooth module goes on the bottom to save space. I also used the auto-route feature so you don’t have to do the routing yourself; I do find, however, that routing your traces manually yields cleaner results. The screenshot above was my first iteration of the design.

Top Layer

Bottom Layer (with a Lego man on the silkscreen!)

Once you are happy with your board layout, you can generate a render of your board. It is a great visual check for any outstanding issues (and it also lets you play around with the design, like adding a Lego man to the silkscreen).

The final step is to generate Gerber files from your design, and sending it off to PCB fabs! Gerber files are the standard for PCB manufacturing, and they serve as instructions for creating the board (e.g. layout, top/bottom silkscreen, drill holes, vias, etc.); think of it as gcode in 3D printing. There are tons of PCB fabs out there but my favourite is OSHpark; they offer quick turnaround times and they also accept KiCAD/Eagle project files, this means you won’t have to generate/convert Gerber files with them and can directly upload your project.

Lovely PCBs!

My boards came in 2 weeks after I sent in the designs. I wanted to get a blue PCB like my render, but that costed $10 more :( You can find all of the design files on my GitHub

Board Assembly

Things you will need

We only have a few SMD components but they can be tricky to solder if you don’t have steady hands. I used Kester flux and ‘drag soldered’ the SMD components, then did all of the through hole components. An easier alternative would be to use solder paste and put the whole thing in a reflow oven.

The tiny pins on the TB6612FNG were a pain! But with lots of flux and sweat, they turned out great :)

Bottom layer, where our Bluetooth module sits

Everything assembled! Before powering it on I did a quick test with my multi-meter to test for shorts

You will also need to attach the Lego extension wires to your 4 pin connectors. Make sure you have them in the right orientation by referring to the schematic. You could also solder the extension wires directly to the board without the connectors.

Both ends of the Lego extension wires have the same wire/pin layout, but the light gray connectors have no bottom pins

All connected and ready for testing. Note I don’t have enough Lego extension wires, so I omitted the Channel 4 connector


The firmware is very basic: read some input string from the serial port and turn on/off the appropriate pins accordingly. Every channel requires 3 GPIO pins to control its direction and speed:

I almost forgot to enable the STDBY pin and was wondering why nothing was working :p

You can find the pin number mappings in the schematic; the code snippet below shows how to turn the motor in one direction at half speed:

digitalWrite(m1en1, HIGH); //CW or CCW
digitalWrite(m1en2, LOW);
analogWrite(m1pwm, 128); //values can be 0-255

For the command protocol, it is simply a string of 4 integer values separated by a #. For example, **128#-255#10#0 **means drive Channel 1 at ~50%, drive Channel 2 at full speed in reverse, drive Channel 3 at 10/255 speed (~4% of max), and brake Channel 4. If a channel is connected to a Lego servo, -255 represents -90 degrees, 0 is center, and 255 represents +90 degrees. Unlike a regular hobby servo, the Lego servo only has 7 steps in each direction, so intermediate values between that range will be ignored (you can learn more about the Lego servo in this YouTube video.

All together, the firmware is simply an infinite loop that waits for commands from the Bluetooth module via serial, then sets the motor direction and speed for each channel. You can find the firmware code on my GitHub

Web Bluetooth App

To control our Lego Power Function motors/servos/lights, we will need to talk to our Bluetooth LE module some how. We can create a native mobile app for iOS/Android, or use one of the Bluetooth LE APIs in Python or Node.JS (such as Bleno by @sandeepmistry).

For this project, I’ve decided to leverage the cutting edge Web Bluetooth APIs available in Chrome 45+. You will need to first enable this experimental feature under chrome://flags (though this feature is enabled by default in Chrome 56+)

The cool thing about Web Bluetooth is that it works right from your browser, without needing additional libraries/plugins! It works on both desktop and Android, and you don’t need to download anything extra; simply visit a web page that has Web Bluetooth enabled and you’re presented with option to interact with nearby Bluetooth LE devices. The JavaScript snippet below shows how you can discover devices, connect, discover services/characteristics, and reading/writing to them:

navigator.bluetooth.requestDevice({ filters: [{ services: [service] }] })
    .then(device => device.gatt.connect())
    .then(server => server.getPrimaryService(service))
    .then(service => service.getCharacteristic(characteristic))
    .then(characteristic => {
        characteristicInstance = characteristic;
    setInterval(updateSpeed,200); //send commands every 200ms
    return characteristic.writeValue(str2ab("0#0#0#0"));
.catch(error => { console.log(error); });

The complete code can be found here; I’ve also enabled GitHub pages on my repo, so if you built the same controller as I have, you could simply go to and start controlling your Lego!

I renamed my HM-10 module to “LEGO-BLE” with AT commands, the default name is BT05

I only created 2 control channels in this interface for testing; to expand on this example, you can add additional UI elements (such as toggle buttons, dials, etc.) and simply map them to the command string (CH1#CH2#CH3#CH4, right now CH3 and CH4 default to 0). You can also use your phone’s accelerometer data as input (e.g. deviceorientation ).

Trying It Out

I should build a nice Lego enclosure for the controller board…

I put together a “car” to test out everything and much to my delight, everything worked perfectly :)

This learning experience has been a lot of fun and I look forward to improving on this design. In the next iteration I plan to consolidate the Bluetooth LE module and the main microcontroller, and not use the Pro Micro + HM-10 (ESP32 perhaps?).

You can find everything you need on my GitHub; I still have a few extra PCBs so feel free to reach out and I’d be glad to send you one to try for yourself.


Discussion (0)