Tag: python

  • Servo Control from pyfirmata + arduino

    Hey! This article is really old! So old, in fact, that I clearly thought that saying (ahem) “w00t w00t” was a good idea. 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.

    pyFirmata‘s documentation is, to be charitable, sparse. After writing Raspberry Pi, Python & Arduino *and* a GUI (which should be making an appearance in The MagPi soon, w00t w00t yeet!), I looked at pyFirmata again to see what it could do. That pretty much meant digging through the source.

    Firmata can drive hobby servos, and if you’re not driving too many, you can run them straight from the Arduino with no additional power. I used a standard cheapo-but-decent Futaba S3003, which gives you about 180° of motion. The particular one I tried started to make little growly noises past 175°, so in the example below, that’s hardcoded as the limit.

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    # move a servo from a Tk slider - scruss 2012-10-28
    
    import pyfirmata
    from Tkinter import *
    
    # don't forget to change the serial port to suit
    board = pyfirmata.Arduino('/dev/tty.usbmodem26271')
    
    # start an iterator thread so
    # serial buffer doesn't overflow
    iter8 = pyfirmata.util.Iterator(board)
    iter8.start()
    
    # set up pin D9 as Servo Output
    pin9 = board.get_pin('d:9:s')
    
    def move_servo(a):
        pin9.write(a)
    
    # set up GUI
    root = Tk()
    
    # draw a nice big slider for servo position
    scale = Scale(root,
        command = move_servo,
        to = 175,
        orient = HORIZONTAL,
        length = 400,
        label = 'Angle')
    scale.pack(anchor = CENTER)
    
    # run Tk event loop
    root.mainloop()
    

    The code above makes a slider (oh, okay, a Tkinter Scale widget) that moves the servo connected to Arduino pin D9 through its whole range. To set the servo position, you just need to write the angle value to the pin.

    I haven’t tried this with the Raspberry Pi yet. It wouldn’t surprise me if it needed external power to drive the Arduino and the servo. This might be a good excuse to use my Omega-328U board — it’s Arduino code compatible, runs from an external power supply, and has Signal-Voltage-Ground (SVG) connectors that the servo cable would just plug straight into.

  • the russian peasants are multiplying!

    Via this post, I found out about Russian Peasant Multiplication, a rather clever method of multiplication that only requires, doubling, halving and adding. So I wrote some code to display it:

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    import sys
    results=[]
    indicator=' '
    
    left=int(sys.argv[1])
    right=int(sys.argv[2])
    
    while right >= 1:
        indicator='X'
        if right % 2:
            indicator=' '              # right number is odd,
            results.append(left)       #  so add left number to results
        print (" %s %16d \t %16d %s") % (indicator, left, right, indicator)
        left *= 2
        right /= 2
    
    print("%s × %s = %s = %d")%(sys.argv[1], sys.argv[2],
                                ' + '.join(map(str,results)), sum(results))

    So to multiply 571 × 293:

    $ ./rpmult.py 571 293
                    571                   293  
     X             1142                   146 X
                   2284                    73  
     X             4568                    36 X
     X             9136                    18 X
                  18272                     9  
     X            36544                     4 X
     X            73088                     2 X
                 146176                     1  
    571 × 293 = 571 + 2284 + 18272 + 146176 = 167303

    Python’s still got some weirdness compared to Perl; where I’d join the list of sum terms in Perl with join(' + ', @results), in Python you have to convert the integer values to strings, then call the join method of the separator string: ' + '.join(map(str,results)). Still, I’ll give Python props for having a built-in list sum() function, which Perl lacks.

  • Raspberry Pi, Python & Arduino *and* a GUI …

    Whee! This entry was the basis of the cover article of The MagPi issue 7. Read it on Issuu, or download the PDF.

    Okay, so maybe I can stop answering the StackExchange question “How to attach an Arduino?” now. While I got the Arduino working with pyFirmata on the Raspberry Pi before, it wasn’t that pretty. With a TkInter front end, it actually looks like some effort was involved. You can happily brighten and dim the LED attached to the Arduino all you want, while the temperature quietly updates on the screen independent of your LED frobbing.

    I’d never used TkInter before. For tiny simple things like this, it’s not that hard. Every widget needs a callback; either a subroutine it calls every time it is activated, or a variable that the widget’s value is tied to. In this case, the Scale widget merely calls a function set_brightness() that sets a PWM value on the Arduino.

    Updating the temperature was more difficult, though. After TkInter has set up its GUI, it runs in a loop, waiting for user events to trigger callback events. It doesn’t really allow you to run another loop alongside its main event loop. What you have to do then is set up a routine which is called periodically using TkInter’s after() function, which calls a subroutine after a set amount of time. If this subroutine ends with another call to after() to call itself again, it will maintain its own event loop separate from TkInter’s GUI loop. This is what I do in the get_temp() subroutine, which schedules itself after a ½ second.

    
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    # graphical test of pyfirmata and Arduino; read from an LM35 on A0,
    #                                          brighten an LED on D3 using PWM
    # Connections:
    # - small LED connected from D3, through a 1kΩ resistor to GND;
    # - LM35: +Vs -> +5V, Vout -> A0, and GND -> GND.
    # scruss, 2012-08-16 - tested on Raspberry Pi and Arduino Uno
    
    import pyfirmata
    import sys                              # just for script name and window
    from Tkinter import *
    
    # 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
    
    def get_temp():                         # LM35 reading in °C to label
        selection = "Temperature: %6.1f °C" % (pin0.read() * 5 * 100)
        label.config(text = selection)
        root.after(500, get_temp)           # reschedule after half second
    
    def set_brightness(x):  # set LED; range 0 .. 100 called by Scale widget
        y=float(x)
        pin3.write(y / 100.0)               # pyfirmata expects 0 .. 1.0
    
    def cleanup():                          # on exit
        print("Shutting down ...")
        pin3.write(0)                       # turn LED back off
        board.exit()
    
    # now set up GUI
    root = Tk()
    root.wm_title(sys.argv[0])              # set window title to program name
    root.wm_protocol("WM_DELETE_WINDOW", cleanup) # cleanup called on exit
    scale = Scale( root, command=set_brightness, orient=HORIZONTAL, length=400,
                   label='Brightness')      # a nice big slider for LED brightness
    scale.pack(anchor=CENTER)
    
    label = Label(root)
    label.pack(anchor='nw')                 # place label up against scale widget
    
    root.after(500, get_temp)               # start temperature read loop
    root.mainloop()
    
    

    The program takes a few seconds to start on the Raspberry Pi, mainly because initializing pyFirmata over a serial line and waiting for the duff values to subside takes time. I tried to exit the program gracefully in the cleanup() subroutine, but sometimes one of the loops (I suspect pyFirmata’s iterator) doesn’t want to quit, so it takes a few clicks to exit.

    The program also seems to chew up a fair bit of CPU on the Raspberry Pi; I had it at around 40% usage just sitting idle. I guess those serial ports don’t read themselves, and you have to remember that this computer is basically no more powerful than a phone.

    So there you are; a simple demo of how to control an output and read an input on an Arduino, from a Raspberry Pi, written in Python (the Raspberry Pi’s official language) with a simple GUI. Considering I’d never written a line of Python before the beginning of this month, I think I’m doing not too badly.

  • 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.)