Raspberry Pi Controls LEGO Power Functions Train


Project Description

LEGO Power Functions RC infrared control is specified in LEGO Power Functions RC v120.pdf

But I wanted to know what my controller (8879 LEGO Power Functions IR Speed Remote Control) was actually sending. So I hooked it up to a scope.

It's a little hard to read, but you can see the 0 bits are shorter than the 1 bits. This picture is the first row of the table below.

I decoded:
Right STOP button
1000 0101 1000 1010
Brake then float, Output 1
Left STOP button
1000 0100 1000 1011
Brake then float, Output 0
Right CW (clockwise)
0000 0111 0101 1101
Decrement PWM, Output 1
Right CCW (counter-clockwise)
1000 0111 0100 0100
Increment PWM, Output 1
I compared the bits to each of the sequences in the specification, to find that it was using "Single Output Mode" on page 9.

Hardware

I used a Logitech Mini Blaster for the infrared (IR) LED output because I had one on hand. I used a meter to figure out the schematic. I added a 2N4401 NPN transistor driver to protect the Raspberry Pi GPIO and to make the LEDs brighter.

Software

Download source code here. This code uses the LIRC driver by Aron Szabo. built into Raspberry Pi Linux. LIRC includes a bunch of stuff to record and play back IR. Since I didn't want to do any of that, I just wrote directly to the driver (/dev/lirc0). lirc_rpi must be loaded with softcarrier=0 since the code writes every pulse.(modprobe lirc_rpi softcarrier=0)

Originally I wrote code to use /sys/class/gpio, and it worked, but was not very reliable. Because user mode code can be interrupted by lots of things going on in the OS, pulses and pauses were often too long. To fix this, you need to disable interrupts, and to do that you need a kernel mode driver. LIRC already had one, so it made sense to use it.

I also looked at using wiringPi, but it has the same timing problem as /sys/class/gpio since it also runs in user mode.

This code runs from http in cgi-bin, so parameters come from the QUERY_STRING environment variable. This complicates the code a little.

Another complication is the toggle bit needs to change for every command sent so multiple "increase speed" commands can be sent for redundancy, but the train only increases speed once. The computer science way to handle this is with a counting semaphore, which is what this code does.

Battery (Attempt #1)

This didn't work so well because had to take the train off the track to charge the battery. So couldn't run it unattended. So on to attempt #2

I was disappointed to learn the 8878 LEGO Power Functions Rechargeable Battery Box has a 2 hour auto-shutoff. This means the power will likely be off when I want to run the train remotely. The 88000 LEGO Power Functions AAA Battery Box auto-shutoff can be disabled (by holding down the power button), but AAA batteries don't last very long (they discharge when you look at them).

So I needed another solution. I bought two LiPo (Lithium Ion Polymer) batteries and chargers from adafruit.com and wired them up in series using an 8886 LEGO Power Functions Extension Wire.

LiPo batteries are delicate and you must be careful to not overcharge or over discharge them or they could fail or catch fire. So I was careful to buy batteries with built-in overcharge/discharge protection. Most LiPo batteries for radio control toys do not have built-in protection so I couldn't use them.

Here is version 2 which includes two charger boards wired in series.

This worked, but since the train was switched on all the time, the battery died too fast. It only lasted a few days, and I would have to open up the train and charge the battery. And most of the time it wasn't being used.

So I added a LightBlue Bean Bluetooth Low Energy module to control the power and report the battery level. This uses node.js, noble and bean-writer to control the Bean from Raspberry Pi. Whenever the control page is loaded or a button is pressed, battery power is turned on for 5 minutes.

Battery (Attempt #2)

I wanted to run the train on a timer (every 15 minutes). And I didn't want to keep taking the train off the track to charge it.

I considered changing everything to a 9V layout, but this has a few disadvantages:

I also considered building a catenary system to charge the batteries, or just hanging wires to each battery from the ceiling. Finally I settled on using 9V track to charge an 8878 LEGO Power Functions Rechargeable Battery Box. Parts List: The bridge rectifier is required because the polarity of voltage from the track depends on the direction you place the Lego motor on the track.

References

http://www.lirc.org/ Linux Infrared Remote Control includes the device driver I used to control the LED.

http://aron.ws/projects/lirc_rpi/ Aron Szabo wrote the LIRC driver for an IR LED connected to Raspberry Pi GPIO.

http://visualgdb.com/tutorials/raspberry/LED/ uses /sys/class/gpio to control a GPIO LED.

http://elinux.org/RPi_Low-level_peripherals covers all the different ways to access hardware and how fast they are.

http://wiringpi.com/ looks like another great way to control GPIO's.

Author

alan@nishioka.com