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!
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.