Rotary Encoder for the Raspberry Pi

For some of the Radiodan applications Richard, Anton and I discussed on thursday at the Bristol Hackspace, we need a rotary encoder. For example, this ‘Wrong (W)radio: Time Travel Radio can play audio from the last few days, navigating time by turning the right hand knob:

Image

I’ve not done much work with the Raspi GPIO, but Richard found an Adafruit example, and then I found this one, that looked simpler on the face of it – except that my C isn’t exactly great, and doesn’t in fact exist. Anyway it had a nice simple example of how to wire a rotary encoder to the Raspi (plus an explanation of the other two legs on my rotary encoder – they’re for the built-in button).

After a bit of a struggle, I got it to work – the library needs wiringPi

git clone git://git.drogon.net/wiringPi
git pull origin
cd wiringPi
git pull origin
./build

then

git clone https://github.com/astine/rotaryencoder
cd rotaryencoder
nano test.c

contents of  test.c:

#include "stdio.h"
#include "rotaryencoder.h"
int main()
{
printf("Hello!\n");
wiringPiSetup () ;
/*using pins 23/24*/
struct encoder *encoder = setupencoder(4,5);
long value;
while (1)
 {
 updateEncoders();
 long l = encoder->value;
   if(l!=value)
   {
     printf("value: %d\n", (void *)l);
     value = l;
   }
 }
return(0);
}

Save and compile it:

gcc -lwiringPi program.c rotaryencoder.c -o test

Run it (GPIO stuff needs to be run as root): I was turning the rotary encoder anti-clockwise

sudo ./test
Hello!
value: -1
value: -2
value: -3
value: -4
value: -5
value: -6
value: -7
value: -8
value: -9
value: -10
value: -11
value: -12
value: -13
value: -14
value: -15

The wiring’s like this:

Image

Archers Avoider

Here are some rough notes from our IRFS hardware hackday so I can find them again. The hackday was organised by Cefn Hoile, Andrew Nicolaou and Jasmine Cox, and was utterly brilliant.

This is work by Dan Nuttall, Jasmine Cox, Sean O’Halpin, Nikolaos Tsipas and me (though I did little!) at a hackday organised as part of our 10% time at IRFS at BBC R&D.

The idea was to make a panic button for radio, that allowed you to skip all or part of a programme, e.g. the Archers.

aa_plan

here’s the version we made:

aa_green_box

here’s the more exciting ‘farmer’ interface, designed by Jasmine and hooked up by Nikolaos:

aa_farmer

Here’s a video of a wifi version I made at home: http://www.flickr.com/photos/nicecupoftea/8649416824/in/photostream/

It consists of a Raspberry PI, a home-made Shrimp with a button, some code that plays IP streams for the audio, which listens for changes to a file and switches streams when it sees a change. Code listens to the serial port and when it detects a button change, changes the right file. I guess we could use the GPIO on the Pi for the button, but I don’t know how to do that yet.

At home, I had a go with my own Pi – I had a power supply and wifi card for it, but no fancy display. This is what I used:

  • Raspberry pi
  • SD card (I used a speed 10 generic 8GB one)
  • some sort of speaker
  • wifi usb card for the pi
  • power supply for the pi
  • arduino or shrimp with a button

I installed wheezy on an SD card via this:

http://www.raspberrypi.org/downloads
http://elinux.org/RPi_Easy_SD_Card_Setup

I then put it in the PI, connected via ethernet and sharing internet on the Mac. I got the IP address using

ping 192.168.2.255

and looking in console.app for a response from a pi – it was 192.168.2.4. I ssh’ed to that using pi@192.168.2.4 password raspberry, then tried to update apt-get

sudo apt-get update
Err http://archive.raspberrypi.org wheezy InRelease

Err http://mirrordirector.raspbian.org wheezy InRelease

Err http://archive.raspberrypi.org wheezy Release.gpg
Temporary failure resolving 'archive.raspberrypi.org'

The default nameserver from the mac didn’t work. Using the google dns fixed it, though this kept getting overwritten on a reboot for some reason:

sudo nano /etc/resolv.conf

nameserver 8.8.8.8
nameserver 8.8.4.4

then update apt-get

sudo apt-get update

Install mpd player

sudo apt-get install mpd

[....] Starting Music Player Daemon: mpdlisten: bind to '[::1]:6600' failed: Failed to create socket: Address family not supported by protocol (continuing anyway, because binding to '127.0.0.1:6600' succeeded)
Failed to load database: Failed to open database file "/var/lib/mpd/tag_cache": No such file or directory
. ok

Install the stuff needed for Dan’s player code:

sudo aptitude install ruby1.9.1-dev #for bundler
sudo apt-get install libsqlite3-dev
sudo apt-get install git #install git

Install Dan’s code:

git clone https://github.com/pixelblend/radiodan.git # the code
sudo gem install bundler #to get all the required gems
cd radiodan
bundle install

Put the simple button code on the arduino using laptop:

// set pin numbers:
const int buttonPin = 2; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin

// variables will change:
int buttonState = 0; // variable for reading the pushbutton status

void setup() {
 // initialize the LED pin as an output:
 pinMode(ledPin, OUTPUT);
 // initialize the pushbutton pin as an input:
 pinMode(buttonPin, INPUT);
 Serial.begin(9600);
}

void loop(){
 // read the state of the pushbutton value:
 buttonState = digitalRead(buttonPin);
 //Serial.println(buttonState);
 // check if the pushbutton is pressed.
 // if it is, the buttonState is HIGH:
 if (buttonState == HIGH) {
  // turn LED on:
  digitalWrite(ledPin, HIGH);
  Serial.println("on");
 }
 else {
  // turn LED off:
  digitalWrite(ledPin, LOW);
  //Serial.println("off");

 }
}

Install required gem for Sean’s serial reading code:

sudo gem install serialport

add in Sean’s ruby code in radiodan/bin/read-serial.rb :

require 'serialport'

filename = ARGV[0] or abort "Need to specify path to file"
sp = SerialPort.new(filename, 9600)
sp.read_timeout = 100
sp.flow_control = SerialPort::NONE

p sp

TIMEOUT = 0.01
TIME_LIMIT = 0.25
PANIC_FILE = "../tmp/panic"

last_time = Time.now.to_f

state = :off

reading = true
begin
 while reading
  selectors = IO.select([sp], [], [], TIMEOUT)
  time = Time.now.to_f
  if selectors
   input = selectors.first.first
   data = input.gets.chomp
   state = state == :on ? :off : :on
   if state == :on
   File.open(PANIC_FILE, "wb") do |file|
    file.write Time.now.to_s
  end
 end
 p [data, state]
 flushing = true
 while flushing
  selectors = IO.select([sp], [], [], TIMEOUT)
   if selectors
    input = selectors.first.first
    junk = input.gets
   end
   time = Time.now.to_f
   if time > last_time + TIME_LIMIT
    flushing = false
   end
  end
 end
  last_time = Time.now.to_f
 end
ensure
 sp.close
end

plug in the arduino to the pi using the USB port, and identify it:

ls /dev | grep USB
> ttyUSB0

run the serial code in the background

cd bin
ruby read-serial.rb /dev/ttyUSB0

and

./bin/download # get the data - should run in the background
./bin/radio

-> at this point if it’s all running correctly it should work (hear R4 from speaker, press the button and it goes to radio 1 for 5 secs and then returns)

for wifi I used

http://dl.dropboxusercontent.com/u/80256631/install-rtl8188cus.txt

via

http://elinux.org/RaspberryPiBoardVerifiedPeripherals#USB_Wi-Fi_Adapters

I did this at the end, which took a looong time:

“Do you want to continue and update the software packages list, kernel software
packages and upgrade the Pi’s firmware and software or do you want to terminate
the script?”

get IP addresss with ifconfig and use wlan0

iwconfig

-> should be associated with an SSID

-> I had some problems with this…turning it off and on again worked :-)

Just for reference, here’s the full code for the exciting 7 segment LED display Cefn found for us that Jasmine wrote.

The old ebay listing is here and the library and sample code is here (zip file)


// set pin numbers:
const int buttonPin = 9; // the number of the pushbutton pin
const int ledPin = 13; // the number of the LED pin
//We always have to include the library
#include "LedControl.h"
/* we always wait a bit between updates of the display */
unsigned long delaytime=250;
/*
Now we need a LedControl to work with.
***** These pin numbers will probably not work with your hardware *****
pin 12 is connected to the DataIn
pin 11 is connected to the CLK
pin 10 is connected to LOAD
We have only a single MAX72XX.
*/
LedControl lc=LedControl(12,11,10,1);

// variables will change:
int buttonState = 0; // variable for reading the pushbutton status

void setup() {

 lc.shutdown(0,false);
 /* Set the brightness to a medium values */
 lc.setIntensity(0,8);
 /* and clear the display */
 lc.clearDisplay(0);
 // initialize the LED pin as an output:
 pinMode(ledPin, OUTPUT);
 // initialize the pushbutton pin as an input:
 pinMode(buttonPin, INPUT);

 Serial.begin(9600);
  writeRadio4();
}

void loop(){

// read the state of the pushbutton value:
 buttonState = digitalRead(buttonPin);

 // check if the pushbutton is pressed.
 // if it is, the buttonState is HIGH:
 if (buttonState == HIGH) {
  // turn LED on:
  digitalWrite(ledPin, HIGH);
  Serial.println("on");
  writeRadio1();
 }
 else {
  // turn LED off:
  digitalWrite(ledPin, LOW);
  // Serial.println("off");
 }
}

void writeRadio4() {

 lc.setRow(0,7,0x05);
 delay(delaytime);
 lc.setChar(0,6,'a',false);
 delay(delaytime);
 lc.setChar(0,5,'d',false);
 delay(delaytime);
 lc.setRow(0,4,B00010000);
 delay(delaytime);
 lc.setRow(0,3,0x1D);
 delay(delaytime);
 lc.setDigit(0,1,4,true); // Display 3 to Digit 3, " "
 delay(2000);

 lc.clearDisplay(0);
 delay(delaytime);
}

void writeRadio1(){

 lc.setRow(0,7,0x05);
 delay(delaytime);
 lc.setChar(0,6,'a',false);
 delay(delaytime);
 lc.setChar(0,5,'d',false);
 delay(delaytime);
 lc.setRow(0,4,B00010000);
 delay(delaytime);
 lc.setRow(0,3,0x1D);
 delay(delaytime);
 lc.setDigit(0,1,1,true); // Display 3 to Digit 3, " "
 delay(delaytime);

 lc.clearDisplay(0);
 delay(5000);

}

SVG D3.js bar chart

This has been driving me up the wall. I haven’t felt so stupid in a long time. Anyway, since I managed it finally, here is some code:


<html>
<head>
<script type="text/javascript" src="d3/d3.v3.min.js"></script>

<style type="text/css">
.axis text {
font: 10px sans-serif;
}

.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<div id="chart"></div>
</body>

<script type="text/javascript">
var margin = {top: 10, right: 10, bottom: 30, left: 50},
width = 500 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;

var x = d3.scale.linear()
.domain([0, 20])
.range([0, width]);

var y = d3.scale.linear()
.domain([0,100])
.range([height,0]);

var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");

var yAxis = d3.svg.axis()
.scale(y)
.orient("left");

var svg = d3.select("#chart").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);

svg.append("g")
.attr("class", "y axis")
.call(yAxis);

var data = [[1,100],[6,20],[20, 50]];

var bars = svg.selectAll("rect")
.data(data)
.enter().append("rect")
.attr("x", function(d) {return x(d[0]) - 5;})
.attr("y", function(d) {return y(d[1]);})
.attr("width",10)
.attr("height", function(d) {return height - y(d[1]);})
.style("fill","blue");

</script>

</html>

and the output:

output

Adapted from this example on jsfiddle. Another good source of information is Scott Murray’s d3.js tutorials particularly scales and axes.

Connecting a Wifly shield to an Arduino

I’m trying to make a more mobile version of my ‘remote control’

which connects to the web in order to send commands. My first version was with a Nanode with built-in ethernet, but I also have a Arduino Duemilanove ATmega168, so I thought I’d try that with my new Wifly shield and a battery pack.

The Wifly shield is this version and I have some stackable headers to go with it. I connected the shield on top of the Arduino like this:

You can see that the USB socket means that the shield is a bit high up.

I downloaded this version of the Wifly library that’s been recently changed to work with Arduino 1.0 Library. All connected up, and running this code from the examples:

#include "WiFly.h"

char passphrase[] = "pass";
char ssid[] = "ssid";

byte server[] = { 66, 249, 89, 104 }; // Google

Client client("google.com", 80);

void setup() {

Serial.begin(9600);
delay(100);
Serial.println("[Wifly]");

WiFly.begin();

Serial.println("finished beginning");

if (!WiFly.join(ssid, passphrase)) {
Serial.println("Association failed.");
while (1) {
// Hang on failure.
}
}

Serial.println("connecting...");

if (client.connect()) {
Serial.println("connected");
client.println("GET /search?q=arduino HTTP/1.0");
client.println();
} else {
Serial.println("connection failed");
}

}

void loop() {
if (client.available()) {
char c = client.read();
Serial.print(c);
}

if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
for(;;)
;
}
}

it was hanging on Wifly.begin().

After a bit of hunting round I found this detailed description of what might be up – essentially a timeout, and then twice only, while I was fiddling with the headers, SpiUartTerminal.pde worked.

The rest of the time it just hangs on this:


Attempting to connect to SPI UART...

So really I’m looking for a bit of advice – I don’t really want to solder it on, but are there better ways of connecting the shield to the Arduino? Are headers typically less reliable than soldering? Is there a better way to connect the shield somehow maybe using a breadboard? (e.g. like this). Or am I just doing something daft …?

UPDATE: Thanks to John (see comment below) I sorted out the problem, which was a newby issue: stackable headers need to be soldered! Anyway I persuaded Damian to solder for me (I’ve never done it before) and we now have a working wireless, battery-powered remote control:

(All it does is send the category to a http web service and that randomly chooses an item from all iPlayer available items in that category, and sends it to a web page connected with XMPP).

Thanks everyone who helped. I’m very pleased with it :D

Nanode / twitter blink example

Here are some notes on my adventures trying to make an ethernet connected Nanode that blinks when certain words are mentioned on twitter. I was working with Mac OS X and there were a few gotchas, so I’ve mentioned them here so I don’t forget and in case anything is useful to anyone else. There’s an exciting video of the resulting beast here featuring the acrylic case from the excellent and fast SKPang. The code (an unholy mixture of C++ and Processing) is here. I was coming at this as someone who’d previously only got blinking and similar going on a Arduino Duemilanove.

Getting the Nanode working

  • Buy a Nanode (ethernet Arduinos are also available, I chose a Nanode because it was recommended to me, also their support is very good and it arrived very quickly. I think in retrospect it’s a bit hard to use for a real novice like me, though I enjoyed finding out…). I got a prebuilt Nanode RFX (which has a Hope RF shield and a microSD slot). You need to also buy a Programming Adaptor, which you need in order to talk to a Nanode as the USB programming interface isn’t built in.
  • Download the Arduino IDE
  • Install the FTDI driver (see this comment, which helped me out a lot) – installing it will restart your computer. This is a different driver to the one you use with a standard Arduino – see the Arduino guide if you’re not using a Nanode
  • Open the blink Arduino example (under file -> examples -> Basic, or here) and change the output to 6
  • Connect the Nanode to the Mac using the FTDI cable using a USB cable
  • In the IDE, set the port to the new driver and the board to ‘Arduino Duemilanove with ATMega 328′
  • Compile and run the Blink example on the Nanode
  • The default LED on the Nanode should blink
  • Celebrate

Connecting up Ethernet

  • Install Ethernet Library -> cd ~/Documents/Arduino; mkdir libraries
  • Download EtherCard library and unzip it in this directory
  • Restart the Arduino IDE and you should see sketch / import library – a new library (not Ethernet but EtherCard at the bottom)
  • Start a new sketch
  • Next I copied and pasted this WebClient example from EtherCard into a new file, and that formed the basis of my code.
  • Click on sketch / import library – and import EtherCard – and it puts some import statements at the top
  • Add this at the top: #include <stdint.h>
  • Connect it to an ethernet connection (e.g. I shared airport to ethernet connection on my mac)

The one problem I had was that it appeared to work intermittently, or once per restart of the board. I think this must have been some sort of race condition. Anyway, I solved it by adding a tiny wait after these two lines:

void loop () {

 ether.packetLoop(ether.packetReceive());

 delay(100); //<--  add this.

...

If you look then at the serial monitor (button with the little magnifing glass on the top right of the Arduino IDE), you should see some results. Click restart on the Nanode if not. It takes a while to get the IP address.

A couple of useful links: