Controlling Raspberry Pi GPIO from Ruby

After my grumpiness yesterday, I thought I'd better strike out in a different direction while I consider my options with the various sub-projects I have on the go at the moment. I have mentioned before that I am a member of local Ruby user group "IPRUG". This is on my mind at the moment as I have promised to give a talk about Raspberry Pi, and I need to prepare some things both to talk about and to demonstrate.

Given that IPRUG is a group for Ruby enthusiasts, it seems reasonable to explore controlling the Raspberry Pi hardware from Ruby, so step one is to get my self set up for this, and maybe have a go at a few simple examples.

To start with I plucked out one of my Linux SD cards. I'm guessing this is probably the one I used in my earlier ruby post, as it already had git and ruby installed. I looked around the web and found a page at elinux.org with details of how to drive GPIO from Ruby.

The first step was pretty easy: gem install wiringpi. So far so good. Unfortunately the next line of the example io = WiringPi::GPIO.new complained about not having permissions for /dev/mem. Do apps using WiringPi really need to be run as root? I tried a few things, but (for example) sudo could not find the installed ruby, and it all got to be a bit of a mess. I began to doubt everything - the code, my installation of Ruby, the updates I had done to the operating system.

I decided I should back off a bit, and try something that should work with no such messing about, so I downloaded some example code from piborg to drive the LEDBorg. This code is in python, which most definitely is installed on the Raspberry Pi Linux. This did not work either. Now I was really confused.

Rather than bang my head against a system in an unknown state, I grabbed another Linux SD and downloaded the same python example. Still no output. It seemed to want to write to /dev/ledborg but insisted on reporting "permission denied". To cut a long story short I eventually realised that I needed to install a driver for /dev/ledborg. It's a pity that the example code does not catch this common case and give some hints.

Back at piborg.org, the installation page gives a slew of different versions of drivers. I picked one which matched the OS version on this SD, and followed the installation instructions. Now when I ran the python code it lit up the LEDBorg with random changing colours.

After breathing a sight of relief, I thought I'd have a go at driving it from the shell. From my reading of the API, echo '222' > /dev/ledborg should turn all three colours full on and give me a bright white light. Unfortunately, it gave me not white, but magenta. A trip back to the piborg install page showed me that I had installed the driver for the wrong board revision. My LEDBorg is still plugged in to my Rev 1 Raspberry Pi, and I had installed the driver for Rev 2 boards. When I installed the correct driver, it worked, and I could now control each of the three LEDBorg colours.

I mentioned this in my review of the LEDBorg, but I'm even more fed up with it now. Providing such a confusing range of drivers seems plain crazy. While I can just about see the advantages of separate versions for different OS versions, forcing users to choose drivers based on board revision is very short sighted.

The logic goes like this: installing software on a Raspberry Pi, be it an operating system, a driver, or an application means installing it to an SD card. The Pi has no non-removable, persistent storage (no internal hard drive or SSD, etc.). On any particular card there will usually be just one operating system version, so it makes sense for all the installed software to be appropriate to that operating system. However, an SD card is by definition removable. It is a trivial matter to pluck a card from one Raspberry Pi and place it in another. Surely software which breaks, requiring re-installation from the web, and breaking compatibility with the original board, when this common action happens is missing something pretty important.

It's not as if finding the board revision is particularly difficult. I have written about how to read version and memory size from a bare-metal system, and on Linux it's there for all to see in /proc/cmdline. If all you want is the board revision, you can do cat /proc/cmdline | awk -v RS=" " -F= '/boardrev/ { print $2 }'. On my original "rev 1" board from May 2012 this gives 0x2, and on my "rev 2" board from January 2012 it gives 0xe. I'm not sure what the over values might be...

Anyway, just to complete at least part of my initial task. Here's a little ruby program to cycle though the colours on a LEDBorg:

#!/usr/bin/env ruby
begin

while true do
  for r in 0..2
    for g in 0..2
      for b in 0..2
        File.open('/dev/ledborg', 'w') { |file| file.write("#{r}#{g}#{b}") }
        sleep 1
      end
    end
  end
end

rescue SignalException
  File.open('/dev/ledborg', 'w') { |file| file.write("000") }
end

Note that the rescue SignalException block is there to switch off the light when the program finishes, even if it is stopped with Ctrl-C. The LEDBorg light gets noticeably hot when all the colours are on full, and I don't want to accidentally leave it like that and risk damaging the Pi, the case, or anything else in my house!

One Comment

  1. Pingback: Why is it so hard to build Raspberry Pi Linux drivers? | Raspberry Alpha Omega

Leave a Reply

Your email address will not be published. Required fields are marked *