Raspberry Pi, Python & Arduino

Hey! This article is really old! So old, in fact, that it really only exists to track down content farms that like to knock off my articles (oh hai, CircuitDigest!). Information here may be misleading and possibly wrong. You probably want to be using a newer client library and you definitely want to use an Arduino IDE ≥ 1.6 and not the ancient one that comes with Raspbian.

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:

  1. Get the required packages:
    sudo apt-get install python-serial mercurial
  2. Download the pyFirmata code:
    hg clone https://bitbucket.org/tino/pyfirmata
    cd 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()[0],
                                    board.get_firmata_version()[1])
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

learning to tolerate python

Python is okay, I guess, but there’s not a hint of music to it. I’m a dyed-in-the-wool Perl programmer since 4.036 days. When I think of how I’ll solve a programming problem, I think in Perl (or, more rarely, in PostScript, but I really have to be pretty off-balance to be thinking in stacks). I’m learning Python because all of the seemingly nifty open source geospatial software uses it, and if I’m to write anything for or about the Raspberry Pi, it seems that Python is the language they officially support on it.

So I’m learning Python by porting some of the simple Perl tools I use around here. It’s painful, not just dealing with the language Fortranesque space-significance, but also physically; I think I put my shoulder out picking up Mark Lutz‘s giant books on Python. The first program I chose to port matches input lines against known words in the system dictionary file. Here’s the Perl version:

#!/usr/bin/perl -w

use strict;
use constant WORDLIST => '/usr/share/dict/words';

my %words;
open(WORDS, WORDLIST);
while () {
    chomp;
    my $word  = lc($_);
    $words{$word}++;
}
close(WORDS);

# now read candidate words from stdin
while (<>) {
  chomp;
  $_=lc($_);
  print $_,"\n" if defined($words{$_});
}

exit;

I most recently used this to look for available call signs that — minus the number — were real words. The input lines from the available call sign list look like this:

VA3PHZ
VA3PIA
VA3PID
VA3PIF
VA3PIH
...

so if I strip out the 3s and run it through the program:

sed 's/3//;' va3_avail.txt | ./callsigncheck.pl

I get one hit: vapid. Which is now my call sign, VA3PID. Moohah.

The Python version is much shorter, and I’m semi-impressed with the nifty little trick in line 5 (aka ‘dictionary comprehension’) which offers some hope for the future of terse, idiomatic code. The fileinput module gives Perlish stdin-or-ARGV[] file input, without which I’m sunk.

#!/usr/bin/python
import fileinput                        # Perl-like file input

# get our wordlist
words={w.lower(): 1 for w in open('/usr/share/dict/words', 'r').read().split()}

# read through input looking for matching words
for l in fileinput.input():
    ll=l.lower().rstrip()
    if words.get(ll, 0):
        print(ll)

(So far, I’ve found the PLEAC – Programming Language Examples Alike Cookbook useful in comparing the languages.)