Infrared Remote Control

I discover this week that it is possible to use the headphone jack to send IR signals. The intructions are for a iPhone but one can use almost any audio source… even the computer audio card! And it is already suported in LIRC (Linux Infrared Remote Control), their page even includes a simple circuit!

LIRC – audio IR transmitter

Then I also found this lego-lirc repo in GitHub from a guy nicknamed iConor. It has the source code to generate LIRC configuration files for the LEGO Power Functions Infrared protocol… and also two configurations files:

The first file works like the 8885 – PF IR Remote Control and contains the usual FORWARD / BACKWARD / HOLD / BREAK codes; the second file works like the 8879 – PF IR Speed Remote Control and contains the codes to control the speed (duty cycle) of the motors.

So… why not give it a try?

I searched for more info about ‘lego-lirc’ but found nothing so I opened an issue asking iConor permission to publish those two files (and he promptly agreed, thank you iConor!).

My laptop has Ubuntu 14.10 x64. I installed LIRC and the required Portaudio library for using the audio card:

$ sudo apt-get install lirc libportaudio0

When LIRC is being installed it asks for an IR Receiver and an IR Transmitter, I chose ‘none’ twice.

Then I copied iConor configuration files to LIRC folder:

sudo cp Combo_Direct.conf /etc/lirc/lircd.conf
sudo cp Combo_PWM.conf  /etc/lirc/lircd.conf

and edited /etc/lirc/hardware.conf to create a LEGO_Combo_Direct transmitter associated to the audio card output:

(...)
#Chosen IR Transmitter
TRANSMITTER="LEGO_Combo_Direct"
TRANSMITTER_MODULES=""
TRANSMITTER_DRIVER="audio"
TRANSMITTER_DEVICE="hw@96000"
TRANSMITTER_SOCKET=""
TRANSMITTER_LIRCD_CONF="/usr/lirc/Combo_Direct.conf"
TRANSMITTER_LIRCD_ARGS=""
(...)

My audio card accepts sampling at 96 kHz but others may require lower values like 48 kHz.

I also edited /etc/lirc/lircd.conf to include both iConor configuration files

(...)
include "/etc/lirc/Combo_Direct.conf"
include "/etc/lirc/Combo_PWM.conf"
(...)

but I’m not sure if it is really needed since hardware.conf already has the right path.

I am also not sure if it is really needed or not but somewhere between my several tries I had to create a folder for lirc where it writes 2 files (one I think is a lock, the other contains just the process id)

~$ sudo mkdir /var/run/lirc/

Now let us start the lirc daemon:

~$ sudo service lirc start

and check if it is working:

~$ pgrep lirc
1234

and what kind of transmitter does it understands:

~$ irsend LIST "" ""
irsend: LEGO_Combo_Direct
irsend: LEGO_Combo_PWM

and also  what codes are available:

$ irsend LIST LEGO_Combo_Direct ""
irsend: 000000000000010e FLOAT_FLOAT
irsend: 000000000000011f FLOAT_FORWARD
irsend: 000000000000012c FLOAT_BACKWARD
irsend: 000000000000013d FLOAT_BRAKE
irsend: 000000000000014a FORWARD_FLOAT
irsend: 000000000000015b FORWARD_FORWARD
irsend: 0000000000000168 FORWARD_BACKWARD
irsend: 0000000000000179 FORWARD_BRAKE
irsend: 0000000000000186 BACKWARD_FLOAT
irsend: 0000000000000197 BACKWARD_FORWARD
irsend: 00000000000001a4 BACKWARD_BACKWARD
irsend: 00000000000001b5 BACKWARD_BRAKE
irsend: 00000000000001c2 BRAKE_FLOAT
irsend: 00000000000001d3 BRAKE_FORWARD
irsend: 00000000000001e0 BRAKE_BACKWARD
irsend: 00000000000001f1 BRAKE_BRAKE

OK, we’re ready! Now suppose we want to make both motors spin forward:

~$ irsend SEND_ONCE LEGO_Combo_Direct FORWARD_FORWARD

Yeah! The motor(s) spin for about 1 second.

So if we want shorter runs we can send a BREAK or a FLOAT after a short time, say 0.1 second:

~$ irsend SEND_ONCE LEGO_Combo_Direct FORWARD_FORWARD; sleep 0.1; irsend SEND_ONCE LEGO_Combo_Direct FLOAT_FLOAT

I faced some strange behaviours (delays, lags) until I better read the LIRC audio page and saw this warning:

“It takes some time to set up (50 ms or so) so when no clients are connected to lircd the first transmission will have some higher latency.

A workaround for this is to keep irw running with a bash script like this:

 #!/bin/bash
 while [ true ]; do
 irw || true
 sleep 1
 done

(…)”

So i created a ‘lirc-keepalive.sh’ file, gave it execution permissions and executed in the background:

~$ chmod +x lirc-keepalive.sh
~$ ./lirc-keepalive.sh &

And it makes a REALLY BIG difference.

For anyone who might get interested in this, I suggest first trying with just a headphone or 2 common LEDs (I used a pair of red). If there is a click or a blink then use 2 IR LEDs. Mine are L-934F3C – IR Emitter 3mm 940nm (€0.25 each) and no resistor at all but if you want to play safe use a small resistor like 8Ω.

You also need a cable (just cut the cable of a old headphone set) and a soldering iron. I also used heat shrinking tube but any kind of insulation material is OK.

The required materials:

And the completed cable:

Now about the LEDs…

These LEDs are from Kingbright, their specs say

1.2V Typ @ 20mA, 940 nm, 50° angle, 10 mW/sr Typ @20 mA

I also tried a pair of TSAL6100 950nm High Power Infrared Led from Vishay:

1.35V Typ@ 100 mA, 10° angle, 170 mW/sr @100 mA

but I got more or less the same results and as their emission angle is much smaller I needed to point more carefully to the PF RC receiver. so I kept the first pair. The audio output is intended for headphone so it isn’t much powerfull and might not give enough current to notice a difference – or i just made a mistake.

My first tests achieved a respectable 3 meter range. Not bad for something so simple and costing less than €1 – now everyone can programmaticaly control their LEGO models. Kudos for LIRC people for being so open-minded and for iConor for creating this configuration files.

Next I’m going to try the same with a LEGO Mindstorms EV3 and also a Raspberry Pi.