After the other night’s wonderfully slow detour into Processing, I thought I’d try the Raspberry Pi’s “native” language of Python to control an Arduino. This worked rather well, though I don’t have a slick GUI for it yet.
pyFirmata is the magic that allows an Arduino running Firmata to talk to Python. It’s fairly easy to install under Raspbian:
- Get the required packages:
sudo apt-get install python-serial mercurial
- Download the pyFirmata code:
hg clone https://bitbucket.org/tino/pyfirmata
sudo python setup.py install
(If this succeeds, you can delete the pyfirmata folder.)
Using pyFirmata is a bit different from other Arduino applications:
- Analogue reads and PWM writes are normalized to a 0 .. 1 range, and not the standard Arduino 0 .. 255 and 0 .. 1023.
- You really need to start a separate iterator thread to stop old readings overflowing the serial buffer
- Since the Arduino is read asynchronously, make sure that the pyFirmata connection is fully initialized before reading from ports. Otherwise, None values ensue.
Here’s some code that uses the same hardware as before, but simply reports the temperature and ramps the brightness of the LED up in 10% steps.
#!/usr/bin/python # -*- coding: utf-8 -*- # simple test of pyfirmata and Arduino; read from an LM35 on A0, # brighten an LED on D3 using PWM # scruss, 2012-08-14 - tested on Arduino Uno & Raspberry Pi (Raspbian) import pyfirmata # Create a new board, specifying serial port board = pyfirmata.Arduino('/dev/ttyACM0') # start an iterator thread so that serial buffer doesn't overflow it = pyfirmata.util.Iterator(board) it.start() # set up pins pin0=board.get_pin('a:0:i') # A0 Input (LM35) pin3=board.get_pin('d:3:p') # D3 PWM Output (LED) # IMPORTANT! discard first reads until A0 gets something valid while pin0.read() is None: pass for i in range(10): pin3.write(i/10.0) # set D3 to 0, 10%, 20%, ... brightness print "PWM: %d %% Temperature %.1f °C" % (i * 10, pin0.read() * 5 * 100) board.pass_time(1) # pause 1 second pin3.write(0) # turn LED back off board.exit()
The output from this might look like:
PWM: 0 % Temperature 24.9 °C PWM: 10 % Temperature 24.9 °C PWM: 20 % Temperature 24.9 °C PWM: 30 % Temperature 25.9 °C <- PWM: 40 % Temperature 26.9 °C | PWM: 50 % Temperature 28.3 °C | I was holding the LM35 here PWM: 60 % Temperature 28.8 °C | to make the temperature rise PWM: 70 % Temperature 29.8 °C | PWM: 80 % Temperature 29.8 °C | PWM: 90 % Temperature 29.8 °C <-
If this doesn’t work, check the output of
dmesg to see if you’re using the right port. You could try this little test script
#!/usr/bin/python # -*- coding: utf-8 -*- import pyfirmata PORT = '/dev/ttyACM0' # change this to suit board = pyfirmata.Arduino(PORT) print 'pyFirmata version:\t%s' % pyfirmata.__version__ print 'Hardware:\t\t%s' % board.__str__() print 'Firmata firmware:\t%i.%i' % (board.get_firmata_version(), board.get_firmata_version()) board.exit()
which should generate something like
pyFirmata version: 0.9.4 Hardware: Arduino /dev/ttyACM0 on /dev/ttyACM0 Firmata firmware: 2.3
Next time, I’ll try to wrap this in a tkinter GUI. But for now, pyFirmata is a much quicker way than Processing to talk to an Arduino. But there is hope of a faster Java for the Raspberry Pi …