Update, 2019-01: raspblocks.com appears to be dead, with an “Account Suspended” error from the host
Raspblocks is a new Blocks-based web programming environment for Raspberry Pi. You don’t even need to write the code on a Raspberry Pi, but the Python 3 code it produces will need to be transferred to a Raspberry Pi to run.
For maximum authenticity (and slowness), I fired up http://www.raspblocks.com/ on a Raspberry Pi Zero over VNC. It took a minute or more to load up the site in Chromium, but creating a simple program was all easy dragging and dropping:
The code it produced was pretty much exactly what you’d write by hand:
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(26, GPIO.OUT)
while True:
GPIO.output(26,True)
time.sleep(1)
GPIO.output(26,False)
time.sleep(1)
And, as you might expect, the code make an LED connected to GPIO 26 turn on and off. Science!
Raspblocks isn’t as polished as its more established rival EduBlocks, but Raspblocks doesn’t need any software installed. Edublocks installs its own Node.js-based web service, which would be painfully slow on a Raspberry Pi Zero. Raspblocks’ code needs to be run manually from a terminal, but I’d put up with that any day over having yet another Node server distribution installed under /opt.
gpiozero (‘A simple interface to GPIO devices with Raspberry Pi’) continues to impress me. One of its newer features is a pinout guide, accessed by the pinout command:
Raspberry Pi Zero pinout – click through for PDF
I’m trying to resist running it on every generation of Raspberry Pi that I have (B, A, 2B, 3B, Zero, Zero W) just for these pretty displays.
(ANSI console colours captured using script, then fed through ansi2html [from the Ubuntu colorized-logs package], printed to PDF from Firefox then mucked about a bit with in Inkscape)
I just picked up a micro:bit, the little educational microprocessor board originally from the BBC. It’s a nice little unit, though like all educational resources, it’s sometimes hard to access resources as a non-edu type.
I landed upon MicroPython, a Python language subset that runs directly on the micro:bit’s ARM chip. I rather like the Mu editor: To give the old microcontroller grumps something real to complain about, MicroPython includes a bunch of very high-level functions, such as a powerful music and sound module. Getting the sound out is easy: just croc-clip a speaker onto the output pads:
(MicroPython warns against using a piezo buzzer as a speaker, but mine worked fine — loudly and supremely annoyingly — with a large piezo element. Some piezos have a fixed-frequency oscillator attached, but this simple one was great.)
This trivial example plays the Nyan Cat theme forever, but every time it loops it gets faster. The beats variable starts at the default 120 bpm, but is increased by one every time:
# nyan but it gets faster
import music
beats = 120
while True:
music.set_tempo(bpm=beats)
music.play(music.NYAN)
beats = beats + 1
This starts out as merely irritating, but quite quickly becomes deeply annoying, and in mere hours become vastly vexing. I’m sure you’d only use this power for good …
Since the Verbal Machines VM-CLAP1 sensor is an open collector type — that is, it sinks current when triggered — it behaves like a simple button to gpiozero, the Raspberry Pi Python GPIO library. If you attach a callback function to the sensor’s when_pressed event, your Python script will call that function every time it registers a clap.
As Side Door sign v3 seemed to have fallen off, I needed to make a new one. With access to a laser cutter, I can make really permanent things now, so I designed this:
Yes, that’s a pointy thing filled with pointy things (all without thumbs, you’ll notice) and labelled with Cooper Black. Irony, much? Fe!
In order to get the sign to hang correctly, I needed to work out the centroid of the pointy outline. thedatachef/inkscape-centroid: Centroids for Inkscape paths and shapes to the rescue! Well, kinda. First off, the installer had a bug that said a Ruby file was a dependency when the plugin was in Python. So I forked the repo, made the change, tested it, and issued a pull request. So yay, working centroid calculations in Inkscape!
Secondly, the plugin only works well for simple shapes, like these:
But compound shapes? Not so well:
I guess it doesn’t like the negative moments generated by the holes, and does its own thing. Oh well.
Pen plotters were pretty expensive and complex pieces of electromechanical equipment. While they often earned their keep in the CAD office, they also had a function that’s almost forgotten: they could be used as input devices, too.
As a kid, we sometimes used to drive past the office of Ferranti-Cetec in Edinburgh. They specialized in digitizers: great big desk or wall mounted devices for capturing points from maps and drawings. Here’s one of their 1973 models:
While the technology and size have changed a bit, these huge bits of engineering kit are the ancestors of today’s track pads and touch screens.
Realizing that their plotters had very precise X-Y indexing and that they had two-way communications to a computer, HP made a drafting sight that fitted in place of a pen on their plotters:
HP drafting sight, part no 09872-60066
This is a very pleasing piece of kit, all metal, thick plastic and polished optical glass. They show up on eBay occasionally, and aren’t cheap. With a bit of coercion, it fits into my HP plotter like this:
Drafting sight in HP7470A plotter
The image is very bright and clear:
Drafting sight near an axis labelDrafting sight over a point, showing cursor dot
If one has a digitizing sight, one needs to find something to digitize post haste … I’m sure everyone can sense the urgency in that. So I found this, a scan from my undergraduate project writeup (centrifugal pump impeller design ftw, or something), which was probably made on an Amiga or Atari ST:
It’s a graph, with pointy bits on it
I printed this as large as I could on Letter paper, as it’s the only size my HP7470A plotter can take. Now all it needed was a small matter of programming to get the data from the plotter. Here’s a minimally-useful digitizer for HP and compatible serial plotters. Although I ran it on my little HP grit wheel plotter attached to a Raspberry Pi, I developed it with my larger Roland plotter. The only fancy module it needs is pySerial.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# a really crap HP-GL point digitizer
# scruss - 2016
from time import sleep
from string import strip
import serial
ser = serial.Serial(port='/dev/ttyUSB1', baudrate=9600, timeout=0.5)
lbl = ''
points = []
labels = []
k = 0
retval = 0
ser.write('DP;') # put in digitizing mode
while lbl != 'quit':
ser.write('OS;')
ret = strip(ser.read(size=5), chr(13))
print ('Retval: ', ret)
if ret != '':
retval = int(ret)
if retval & 4: # bit 2 is set; we have a point!
print ('Have Point! Retval: ', retval)
retval = 0
ser.write('OD;')
pt = strip(ser.read(size=20), chr(13))
print ('OD point: ', pt)
lbl = raw_input('Input label [quit to end]: ')
points.append(pt)
labels.append(lbl)
k = k + 1
ser.write('DP;') # put in digitizing mode again
sleep(1)
ser.close()
f = open('digit.dat', 'w')
for i in range(k):
f.write(points[i])
f.write(',')
f.write(labels[i])
f.write('\n')
f.close()
In the unlikely event that anyone actually uses this, they’ll need to change the serial port details near the top of the program.
The program works like this:
Move the drafting sight to the point you want to capture using the plotter’s cursor keys, and hit the plotter’s ENTER key
Your computer will prompt you for a label. This can be anything exceptquit, that ends the program
When you have digitized all the points you want and entered quit as the last label, the program writes the points to the file digit.dat
I didn’t implement any flow control or other buffer management, so it can crash in a variety of hilarious ways. I did manage to get it to work on the lower trace of that graph, and got these data:
The first two columns are X and Y, in HP-GL units — that’s 1/40 mm, or 1/1016 inches. The third column will always be 1 if you have the sight down. The last columns are the label; if you put commas in them, opening the file as CSV will split the label into columns. I used it to fudge axis points. You’ll also note that the last three lines of data are my valiant attempts to quit the program …
Assuming the axes are not skewed (they are, very slightly, but shhh) some simple linear interpolation gives you the results below:
(For prettier things to do with plotter digitizing commands, Ed Nisley KE4ZNU has made some rather lovely Superformula patterns)
If you don’t have a plotter, or even if you do and you don’t have hours to waste mucking about with Python, obsolete optics and serial connections, Ankit Rohatgi’s excellent WebPlotDigitizer gets numbers out of graphs quickly. It handles all sorts of graphs rather well.
The cryptically-named q (it also bills itself as being able to “Run SQL directly on CSV files | Text as Data”) is very nifty indeed. It allows you to run SQL queries on delimited text files. It seems to support the full SQLite SQL dialect, too.
The first problem is that the file uses nasty date formats. Today would be 23-Jan-16 in the report’s Date field, which is filled with the ugh. You can fix that, though, with a fragment of SQL modified from here:
The above data definition sets the isodate column to be in the familiar and useful YYYY-MM-DD ISO format.
A related example would be to query the whole CSV file for monthly mean generation from Kingsbridge and K2 Wind projects (they’re next to one another) for months after K2’s commissioning in March 2015. Here’s what I did in q:
q -T -O -H -d, 'select printf("%4d-%02d", substr(Date, 8,2)+2000, (instr("---JanFebMarAprMayJunJulAugSepOctNovDec", substr(Date, 4,3))-1)/3) as isomonth, avg(KINGSBRIDGE) as kavg, avg(K2WIND) as k2avg from Downloads/HourlyWindFarmGen_20160122.csv where isomonth>"2015-03" group by isomonth'
Over the last few weeks, I’ve been playing with a few small thermal printers. Meant as POS or information booth printers, they make a diverting project for the lo-fi printing enthusiast. While they all have common features — 58 mm/2¼” paper width, 8 pixel/mm resolution, 48 mm print width, serial connection — they all have their quirks. You may have seen these sold as the Adafruit Mini Thermal Receipt Printer or Sparkfun’s Thermal Printer, but there are many others. I’m going to write more on interfacing these directly to Raspberry Pi, Arduino, and (if I can navigate the documentation) a CUPS driver.
For now, I’m just leaving you a list of things I’ve found helpful for the DP-EH600 and 701 printers. Note that the similar-looking BTHT-v6 printer uses a completely different command set.
Replacement paper is sold as 2¼” × 30′. Staples have a box of 30 rolls for under $25 (item 279096, not on their website). Longer rolls don’t fit.
You’ll need a USB→TTL Serial adaptor, preferably one with DTR control. I use one from JY-MCU. In a pinch, you can use a simpler Debug / Console Cable for Raspberry Pi, but you risk serial overruns and dodgy results. Remember that RX on the adaptor goes to TX on the printer, and vice versa.
A good solid power supply is needed; these printers draw ~8 W when printing. Some printers only support 5 V (for which a 3 amp adaptor would be ideal), others 5-9 V. The higher voltage makes text printing faster. You can’t drive these directly from your Raspberry Pi/Arduino power supply.
Linux serial ports are set to some defaults which may have been historically useful, but now corrupt 8-bit data. A trick I picked up here is to first issue the command stty -F /dev/ttyUSB1 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
which clears all settings, then set the device up as you need it: stty -F /dev/ttyUSB1 speed 9600 raw cs8
(Most of these printers default to 9600 baud. Your device may be called something different to ttyUSB1.)
I’ve written a couple of Python driver stubs which take an image and produce the relevant binary output:
scruss / esc-pos-image.py – prints an image as a single command. May not work on the SparkFun printer. Does not work on the BTHT-v6.
scruss / esc-pos-image-star.py – prints the image in 24 pixel deep bands. Can sometimes cause visible gaps in the printout, but will work on almost all printers, except the BTHT-v6.
These Python libraries also work, as long as you address the printer properly (right device, right speed):
python-escpos – image support limited to 255 pixels high, for some reason.
Reed Zhao (of Tangram Software) lent me a couple of different printers for testing after I bought a different one from him. He’s put a lot of work into sourcing these printers direct from the manufacturers. Thanks, Reed! NB: Reed doesn’t sell printers any more. Try eBay.
BTHT-V6 manual (Chinese) — probably just enough info to follow the wiring and some of the basic control codes. Looks like the one I had was 5V only, so needs a 5V 3A power supply.
… it complains that the oscilloscope is always making waves.
Ahem. Anyway. I have a Rigol DS1102E 100 MHz Digital Oscilloscope. For such a cheap device, it’s remarkable that you can control it using USB Test & Measurement Class commands. I’d been wanting to use a Raspberry Pi as a headless data acquisition box with the oscilloscope for a while, but Raspbian doesn’t ship with the usbtmc kernel module. I thought I was stuck.
Alex Forencich turned up in the forum with an all-Python solution: Python USBTMC (source: alexforencich / python-usbtmc). I got this working quite nicely today on both the Raspberry Pi and my Ubuntu laptop. Here’s how I installed it:
Check your device’s USB code with lsusb: $ lsusb Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp. …. Bus 001 Device 004: ID 1ab1:0588 Rigol Technologies DS1000 SERIES
Ensure that libusb-1.0 is installed: sudo apt-get install libusb-1.0-0
Create a new group, usbtmc: sudo groupadd usbtmc
Add yourself to this group: sudo usermod -a -G usbtmc pi
As root, create a file /etc/udev/rules.d/usbtmc.rules. You’ll need to put in your device’s ID values: # USBTMC instruments # Rigol DS1100 – ID 1ab1:0588 Rigol Technologies DS1000 SERIES SUBSYSTEMS==”usb”, ACTION==”add”, ATTRS{idVendor}==”1ab1″, ATTRS{idProduct}==”0588″, GROUP=”usbtmc”, MODE=”0660″
(all of the SUBSYSTEMS to MODE= should be one one line)
Download and install the latest pyusb (Raspbian version is rather old): git clone https://github.com/walac/pyusb.git cd pyusb python setup.py build sudo python setup.py install
Now get python-usbtmc: git clone https://github.com/alexforencich/python-usbtmc.git cd python-usbtmc python setup.py build sudo python setup.py install
For this simple demo, you’ll need to convert the USB vendor IDs to decimal: 0x1ab1 = 6833 0x0588 = 1416
Now, start python as root (sudo python) then type: import usbtmc instr = usbtmc.Instrument(6833, 1416) print(instr.ask(“*IDN?”))
This should return something like: Rigol Technologies,DS1102E,DS1EB13490xxxx,00.02.06.00.01
If you get the status line, congratulations! You now have a fully working usbtmc link. I haven’t had much time to play with this, but I know I can make really nice screenshots to an attached USB drive using the command: instr.write(“:HARDcopy”). Many more commands can be found in the DS1000D/E Programming Guide, available on Rigol‘s site.
I had a couple of problems, though:
The library seems to need root privileges, despite the udev rule thing. After creating the udev rule, you will need to reboot. This is the simplest way of getting it to work without being root.
Reading from the ‘scope’s memory chokes on non-UTF8 characters. If I do: rawdata = instr.ask(“:WAV:DATA? CHAN1”)[10:] I get a lengthy Python error which ends: … File “/usr/lib/python2.7/encodings/utf_8.py”, line 16, in decode return codecs.utf_8_decode(input, errors, True) UnicodeDecodeError: ‘utf8’ codec can’t decode byte 0x99 in position 10: invalid start byte I have no idea what that means, or how to fix it. Alex suggested using ask_raw instead of ask, and the data comes through with no complaints.
I’ve still got to work my way through the Rigol’s data format, but other people have done that before:
Incidentally, if you’re working with WFM data dumps from the Rigol ‘scopes (and you should, because they make storing data to USB drives quick), mabl/pyRigolWFM is basically magic. Not merely can it describe and decode those binary files, it can do pretty graphics with no thought required:
Update, 2013-12-20: I’ve successfully managed to run most of Ken’s examples with Alex’s code. The major modification you have to do is use ask_raw instead of ask. Example code shown below:
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Download data from a Rigol DS1102E oscilloscope and graph with matplotlib
using Alex Forencich's python-usbtmc pure python driver
https://github.com/alexforencich/python-usbtmc
scruss - 2013-12-20
based on
Download data from a Rigol DS1052E oscilloscope and graph with matplotlib.
By Ken Shirriff, http://righto.com/rigol
which in turn was
Based on http://www.cibomahto.com/2010/04/controlling-a-rigol-oscilloscope-using-linux-and-python/
by Cibo Mahto.
"""
import usbtmc
import time
import numpy
import matplotlib.pyplot as plot
# initialise device
instr = usbtmc.Instrument(0x1ab1, 0x0588) # Rigol DS1102E
# read data
instr.write(":STOP")
instr.write(":WAV:POIN:MODE RAW")
# first ten bytes are header, so skip
rawdata = instr.ask_raw(":WAV:DATA? CHAN1")[10:]
data_size = len(rawdata)
# get metadata
sample_rate = float(instr.ask_raw(':ACQ:SAMP?'))
timescale = float(instr.ask_raw(":TIM:SCAL?"))
timeoffset = float(instr.ask_raw(":TIM:OFFS?"))
voltscale = float(instr.ask_raw(':CHAN1:SCAL?'))
voltoffset = float(instr.ask_raw(":CHAN1:OFFS?"))
# show metadata
print "Data size: ", data_size
print "Sample rate: ", sample_rate
print "Time scale: ", timescale
print "Time offset: ", timeoffset
print "Voltage offset: ", voltoffset
print "Voltage scale: ", voltscale
# convert data from (inverted) bytes to an array of scaled floats
# this magic from Matthew Mets
data = numpy.frombuffer(rawdata, 'B')
data = data * -1 + 255
data = (data - 130.0 - voltoffset/voltscale*25) / 25 * voltscale
# creat array of matching timestamps
time = numpy.linspace(timeoffset - 6 * timescale, timeoffset + 6 * timescale,
num=len(data))
# scale time series and label accordingly
if (time[-1] < 1e-3):
time = time * 1e6
tUnit = "µS"
elif (time[-1] < 1):
time = time * 1e3
tUnit = "mS"
else:
tUnit = "S"
# Plot the data
plot.plot(time, data)
plot.title("Oscilloscope Channel 1")
plot.ylabel("Voltage (V)")
plot.xlabel("Time (" + tUnit + ")")
plot.xlim(time[0], time[-1])
plot.show()
Boodler is rather fun. It generates ambient music based on user-defined or downloaded ‘soundscapes’. If you’ve got a modern (HTML5/Opus-capable) browser, you can hear a streaming demo here: http://repeater.xiph.org:8000/clock.opus. It’s using the FM3 Buddha Machine samples in this demo, but it can run lots more: a tree full of crows, a thunderstorm, dripping water, …
It’s pretty easy to run on a Raspberry Pi running a recent version of Raspbian. The only technical glitch I had was that there’s something deeply confused about ALSA sound handling on the Raspberry Pi. I’m sure it’ll get fixed soon, but for now, you have to use PulseAudio. (If you want to read about my ALSA woes, go here.)
It takes a while to do this, but make sure it does something useful when it’s building the various sound drivers. You don’t want it to say:
skipping 'boodle.cboodle_pulse' extension
If it says that, you haven’t installed Pulseaudio. Go back and check your apt-get line.
Once it’s built, now install it:
sudo python setup.py install
Now test it:
boodler --hardware --output pulse --testsound
Not merely should you get some pleasant tones from your Raspberry Pi’s audio, but you sound get some informative and non-threatening terminal output. Mine looks like:
Boodler: PulseAudio sound driver.
PulseAudio library: 2.0.0.
Sample rate is 44100 fps.
Samples are 16-bit little-endian.
Buffer size is 32768.
21:37:46 (root) Running "Boodler test sound"
If that works, let’s get those crows a-cawin’. Download the soundscapes you need:
Boodler has tons of options, prebuilt packages, and instructions to build your own: Boodler Documentation.
One thing I’ve tried to get working, but failed, is streaming from Boodler via icecast. Sure, I can install and run it, it’s just that the results are, um, undesirable. If you want to have a play, here’s how to install icecast:
sudo apt-get install icecast2 ices2 libshout3-dev
Icecast will configure itself, and ask for a couple of passwords. You’ll have to rebuild and reinstall Boodler for it to catch the new configuration. You can then try streaming:
If you open a web browser at this address http://raspberrypi:8000/ you should see a config page listing your boodler-buddha.ogg stream. Click on the M3U link next to it, and your streaming music player should start making a joyful noise …
… except in my case, something went very wrong, and it started to produce industrial ultra-glitch nightmare noise: boodler-streaming_test-fail. I’m sure it’s fixable with some tweaking, but I’m not there yet.
Hey! This is a really old article. You should really be using gpiozero these days.
I hadn’t realised it, but the The Quite Rubbish Clock did something that a lot of people seem to have trouble with on the Raspberry Pi: communicating using hardware SPI. Perhaps it’s because everything is moving so fast with Raspberry Pi development, tutorials go out of date really quickly. Thankfully, hardware SPI is much easier to understand than the older way of emulation through bit-banging.
SPI is a synchronous serial protocol, so it needs a clock line as well as a data in and data out line. In addition, it has a Chip Enable (CE, or Chip Select, CS) line that is used to choose which SPI device to talk to. The Raspberry Pi has two CE lines (pins 24 and 26) so can talk to two SPI devices at once. It supports a maximum clock rate of 32 MHz, though in practice you’ll be limited to the rate your device supports.
The device I’m testing here is an MCP3008 10-bit Analogue-to-Digital Converter (ADC). These are simple to use, cheap and quite fast converters with 8 input channels. If you hook them up to a 3.3 V supply they will convert a DC voltage varying from 0-3.3 V to a digital reading of 0-1023 (= 210 – 1). Not quite up there in quality for hi-fi audio or precision sensing, but good enough to read from most simple analogue sensors.
The sensor I’m reading is the astonishingly dull LM35DZ temperature sensor. All the cool kids seem to be using TMP36s (as they can read temperatures below freezing without a negative supply voltage). One day I’ll show them all and use a LM135 direct Kelvin sensor, but not yet.
The code I’m using is a straight lift of Jeremy Blythe’s Raspberry Pi hardware SPI analog inputs using the MCP3008. The clever bit in Jeremy’s code is the readadc() function which reads the relevant length of bits (by writing the same number of bits; SPI’s weird that way) from the SPI bus and converting it to a single 10-bit value.
#!/usr/bin/python
# -*- coding: utf-8 -*-
# mcp3008_lm35.py - read an LM35 on CH0 of an MCP3008 on a Raspberry Pi
# mostly nicked from
# http://jeremyblythe.blogspot.ca/2012/09/raspberry-pi-hardware-spi-analog-inputs.html
import spidev
import time
spi = spidev.SpiDev()
spi.open(0, 0)
def readadc(adcnum):
# read SPI data from MCP3008 chip, 8 possible adc's (0 thru 7)
if adcnum > 7 or adcnum < 0:
return -1
r = spi.xfer2([1, 8 + adcnum << 4, 0])
adcout = ((r[1] & 3) << 8) + r[2]
return adcout
while True:
value = readadc(0)
volts = (value * 3.3) / 1024
temperature = volts / (10.0 / 1000)
print ("%4d/1023 => %5.3f V => %4.1f °C" % (value, volts,
temperature))
time.sleep(0.5)
The slightly awkward code temperature = volts / (10.0 / 1000) is just a simpler way of acknowledging that the LM35DZ puts out 10 mV (= 10/1000, or 0.01) per °C. Well-behaved sensors generally have a linear relationship between what they indicate and what they measure.
If you run the code:
sudo ./mcp3008_lm35.py
you should get something like:
91/1023 => 0.293 V => 29.3 °C
93/1023 => 0.300 V => 30.0 °C
94/1023 => 0.303 V => 30.3 °C
95/1023 => 0.306 V => 30.6 °C
96/1023 => 0.309 V => 30.9 °C
97/1023 => 0.313 V => 31.3 °C
97/1023 => 0.313 V => 31.3 °C
98/1023 => 0.316 V => 31.6 °C
99/1023 => 0.319 V => 31.9 °C
99/1023 => 0.319 V => 31.9 °C
100/1023 => 0.322 V => 32.2 °C
100/1023 => 0.322 V => 32.2 °C
100/1023 => 0.322 V => 32.2 °C
101/1023 => 0.325 V => 32.5 °C
101/1023 => 0.325 V => 32.5 °C
102/1023 => 0.329 V => 32.9 °C
102/1023 => 0.329 V => 32.9 °C
103/1023 => 0.332 V => 33.2 °C
Note that the sensor had been sitting over the Raspberry Pi’s CPU for a while; I don’t keep my house at 29 °C. I made the temperature go up by holding the LM35.
So, you’ve just (fairly cheaply) given your Raspberry Pi 8 analogue input channels, so it can behave much more like a real microcontroller now. I remember from my datalogging days that analogue inputs can be pretty finicky and almost always return a value even if it’s an incorrect one. Check the chip’s datasheet to see if you’re doing it right, and if in doubt, meter it!
The video of the Quite Rubbish Clock isn’t running the same code that’s in the listing. Here it is, showing off some of the handy code that’s in bgreat’s nokiaSPI Python class:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# qrmovie
import time
# need to use git://github.com/mozillazg/python-qrcode.git
import qrcode
from PIL import Image, ImageFont
import ImageOps
# uses bgreat's SPI code; see
# raspberrypi.org/phpBB3/viewtopic.php?f=32&t=9814&p=262274&hilit=nokia#p261925
import nokiaSPI
noki = nokiaSPI.NokiaSPI() # create display device
qr = qrcode.QRCode(version=1, # V.1 QR Code: 21x21 px
error_correction=qrcode.constants.ERROR_CORRECT_M,
box_size=2, border=1)
bg = Image.new('1', (84, 48)) # blank (black) image background
# intro
noki.cls()
noki.led(0)
time.sleep(3)
for i in range(0,769,32):
noki.led(i)
time.sleep(0.04)
# display is 14 columns by 8 rows
noki.centre_word(1, 'scruss.com')
noki.centre_word(3, 'presents')
time.sleep(3)
noki.cls()
noki.centre_word(1, 'qrclock')
noki.centre_word(2, 'the')
noki.gotorc(3,3)
noki.text("[Q]uite")
noki.gotorc(4,3)
noki.text("[R]ubbish")
noki.gotorc(5,3)
noki.text(" Clock")
time.sleep(3)
elapsed=0
start_time = time.time()
while (elapsed<12):
qr.clear()
newbg = bg.copy() # copy blank background
s = time.strftime('%Y-%m-%d %H:%M:%S')
qr.add_data(s) # make QR Code of YYYY-MM-DD HH:MM:SS
qr.make()
qrim = qr.make_image() # convert qrcode object to PIL image
qrim = qrim.convert('L') # make greyscale
qrim = ImageOps.invert(qrim) # invert colours: B->W and W->B
qrim = qrim.convert('1') # convert back to 1-bit
newbg.paste(qrim, (18, 0)) # paste QR Code into blank background
noki.show_image(newbg) # display code on LCD
time.sleep(0.4) # pause before next display
elapsed = time.time() - start_time
noki.cls()
noki.centre_word(1, 'for')
noki.centre_word(2, 'more')
noki.centre_word(3, 'details')
time.sleep(3)
noki.cls()
noki.load_bitmap("blogpost-nokia.bmp", True)
time.sleep(7)
noki.cls()
noki.centre_word(3, 'fin')
noki.centre_word(5, 'scruss, 2013')
time.sleep(1)
for i in range(768,-1,-32):
noki.led(i)
time.sleep(0.05)
time.sleep(1)
noki.cls()
Lines 43-58 show off the QR clock for a maximum of 12 seconds. Any more, and you’d get really bored.
The screen handling functions I used are:
cls() — Clears the screen.
led(brightness) — sets the backlight to brightness. For me, full brightness is at 768. A value of zero turns the backlight off. If you don’t have the screen LED connected to one of the Raspberry Pi’s PWM pin, this will either be full on (for any brightness >= 1), or off, for brightness=0. This is used to fade up the screen in lines 24-26, and fade it down far too theatrically in lines 72-74.
show_image(PILImage) — display a single bit depth black and white Python Imaging Library object PILImage. This can be no larger than 84×48 pixels.
load_bitmap(file, Invert) — load a single bit depth black and white BMP file of maximum size 48×84. If Invert is true, keep the colours as they are, otherwise swap black and white to make a negative image. nokiSPI flips images by 90°, so the image I loaded to show the URL of the blog post looks like this:
(I know, I could have generated this in code, but I’d already made the image using qrencode. I couldn’t be bothered working out the image size and offsets.)
The text handling functions I used are:
gotorc(row, column) — move the text cursor to row, column. The screen only has 14 columns by 8 rows if you use the standard 6×6 pixel font, so keep your text short to avoid disappointment.
text(text) — write text at the current cursor position.
centre_word(row, text) — write text centred in row row. Since the text rows are a maximum of 14 columns, text with an odd number of characters will appear slightly off-centre.
There are many more functions in the nokiaSPI class; watch the demo, have a dig through the source and see what you can use.
Update: Eep! This post was featured on the Raspberry Pi blog today. Thanks, Liz!
And now for something completely different:
… a clock that isn’t human readable. You’ll need a QR code reader to be able to tell the time.
This, however, is not the prime purpose of the exercise. I was looking for an excuse to try some direct hardware projects with the GPIO, and I remembered I had a couple of Nokia-style surplus LCDs lying about that could be pressed into service. These LCDs aren’t great: 84×48 pixels, 3V3 logic, driven by SPI via an 8-pin header which includes PWM-controllable LED backlighting. They are cheap, and available almost everywhere: DealExtreme ($5.36), SparkFun ($9.95), Adafruit ($10 – but includes a level shifter, which you really need if you’re using a 5V logic Arduino), Solarbotics ($10) and Creatron (about $12; but you can walk right in and buy one). Despite being quite difficult to use, helpful people have written drivers to make these behave like tiny dot-addressable screens.
I’d been following the discussion on the Raspberry Pi forum about driving the Nokia LCD from a Raspberry Pi. Only when user bgreat posted some compact code that was supposed to run really fast did I dig out the LCD board and jumper wires. Building on bgreat’s nokiaSPI.py class and a few other bits of code, here’s what I built to make this singularly pointless clock:
#!/usr/bin/python
# -*- coding: utf-8 -*-
# qrclock - The Quite Rubbish Clock for Raspberry Pi - scruss, 2013-01-19
import time
# need to use git://github.com/mozillazg/python-qrcode.git
import qrcode
from PIL import Image
import ImageOps
# uses bgreat's SPI code; see
# raspberrypi.org/phpBB3/viewtopic.php?f=32&amp;amp;t=9814&amp;amp;p=262274&amp;amp;hilit=nokia#p261925
import nokiaSPI
noki = nokiaSPI.NokiaSPI() # create display device
qr = qrcode.QRCode(version=1, # V.1 QR Code: 21x21 px
error_correction=qrcode.constants.ERROR_CORRECT_M,
box_size=2, border=1)
bg = Image.new('1', (84, 48)) # blank (black) image background
while 1:
qr.clear()
newbg = bg.copy() # copy blank background
s = time.strftime('%Y-%m-%d %H:%M:%S')
qr.add_data(s) # make QR Code of YYYY-MM-DD HH:MM:SS
qr.make()
qrim = qr.make_image() # convert qrcode object to PIL image
qrim = qrim.convert('L') # make greyscale
qrim = ImageOps.invert(qrim) # invert colours: B-&amp;gt;W and W-&amp;gt;B
qrim = qrim.convert('1') # convert back to 1-bit
newbg.paste(qrim, (18, 0)) # paste QR Code into blank background
noki.show_image(newbg) # display code on LCD
time.sleep(0.4) # pause before next display
(Convenient archive of all the source: qrclock2.zip, really including bgreat’s nokiaSPI class this time …)
To get all this working on your Raspberry Pi, there’s a fair amount of configuration. The best references are bgreat’s own comments in the thread, but I’ve tried to include everything here.
Enabling the SPI kernel module
As root, edit the kernel module blacklist file:
sudo vi /etc/modprobe.d/raspi-blacklist.conf
Comment out the spi-bcm2708 line so it looks like this:
#blacklist spi-bcm2708
Save the file so that the module will load on future reboots. To enable the module now, enter:
sudo modprobe spi-bcm2708
Now, if you run the lsmod command, you should see something like:
Module Size Used by
spi_bcm2708 4421 0
Installing the WiringPi, SPI and other required packages
WiringPi by Gordon is one of the neater Raspberry Pi-specific modules, as it allows relatively easy access to the Raspberry Pi’s GPIO pins. For Raspbian, there are a few other imaging libraries and package management tools you’ll need to install here:
Finding a library that provided all the right functions was the hardest part here. I ended up using mozillazg‘s fork of lincolnloop‘s python-qrcode module. mozillazg’s fork lets you use most of the lovely PIL methods, while the original hides most of them. Since I had to do some image compositing and colour remapping to make the image appear correct on the Nokia screen, the new fork was very helpful.
To install it:
git clone git://github.com/mozillazg/python-qrcode.git
cd python-qrcode/
sudo python ./setup.py install
The tiny 84×48 resolution of the Nokia screen doesn’t give you many options for sizing QR codes. For the time display of the clock, a 21×21 module Version 1 code with two pixels per module and one module margin just fits into 48 pixels. Using a medium level of error correction, you can fit the 19-character message (such as “2013-01-19 18:56:59”) into this tiny screen with a very good chance of it being read by any QR code reader.
(In the video, there’s a much larger QR code that’s a link to this blog post. That’s a Version 7 code [45×45 modules] at one pixel per module and no margin. This doesn’t meet Denso Wave’s readability guidelines, but the Nokia screen has large blank margins which seem to help. It won’t read on every phone, but you’re here at this link now, so you don’t need it …)
Wiring it all up
(Do I really need to say that you’ll be messing around with the inner delicate bits of your Raspberry Pi here, and if you do something wrong, you could end up with a dead Raspberry Pi? No? Okay. Just make sure you take some static precautions and you really should have the thing shut down and powered off.)
You’ll need 8 female-female jumper wires, and also some kind of pin header soldered in (I used right-angled ones). Note that the thick border of the LCD is the top of the screen. These boards are made who-knows-where by who-knows-whom, and there’s a hugevariety of labels and layouts on the pins. My one appears to be yet another variant, and is labelled:
VCC
GND
SCE
RST
D/C
DNK(MOSI)
SCLK
LED
This is how I wired it (from comments in bgreat’s code and the GPIO reference):
LCD Pin Function Pi GPIO Pin # Pi Pin Name
============= ============= =============== =============
1 VCC Vcc 1 3.3 V
2 GND Ground 25 GND
3 SCE Chip Enable 24 GPIO08 SPI0_CE0_N
4 RST Reset 11 GPIO17
5 D/C Data/Command 15 GPIO22
6 DNK(MOSI) Data In 19 GPIO10 SPI0_MOSI
7 SCLK Serial Clock 23 GPIO11 SPI0_SCLK
8 LED Backlight 12 GPIO18 PWM0
Wire it up, and fire up the program:
sudo ./qrclock.py
Yes, code that accesses GPIO needs to be run as root. Pesky, but helps you avoid running code that accidentally scrams the nuclear power station you’re controlling from your Raspberry Pi …
Whoa! This is so old I don’t even know where to start!
It’s using Python 2, so if it works at all it probably won’t for much longer, and Tkinter is something completely different under Python 3
(grrreat planning there, Python guys …)
pyfirmata is likely ancient history too.
Phil sent me a note last week asking how to turn an LED on or off using Python talking through Firmata to an Arduino. This was harder than it looked.
It turns out the hard part is getting the value from the Tkinter Checkbutton itself. It seems that some widgets don’t return values directly, so you must read the widget’s value with a get() method. This appears to work:
#!/usr/bin/python
# turn an LED on/off with a Tk Checkbutton - scruss 2012/11/13
# Connection:
# - small LED connected from D3, through a resistor, to GND
import pyfirmata
from Tkinter import *
# Create a new board, specifying serial port
# board = pyfirmata.Arduino('/dev/ttyACM0') # Raspberry Pi
board = pyfirmata.Arduino('/dev/tty.usbmodem411') # Mac
root = Tk()
var = BooleanVar()
# set up pins
pin3 = board.get_pin('d:3:o') # D3 On/Off Output (LED)
def set_led(): # set LED on/off
ledval = var.get()
print "Toggled", ledval
pin3.write(ledval)
# now set up GUI
b = Checkbutton(root, text = "LED", command = set_led,
variable = var)
b.pack(anchor = CENTER)
root.mainloop()
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.
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.
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.
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:
Get the required packages: sudo apt-get install python-serial mercurial
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
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 …