I recently had loads of fun attending a Nodebots AU event in Sydney. (Thanks a lot to Damon and Andrew for organising, and NICTA for the venue!) I got to muck around with some simple circuits and drive them with Javascript. Towards the end of the day I was running out of time and creativity to do anything fancy, so I decided to see if I could get one of the circuits working with Haskell.
Nodebot prerequisites
I got a Node ARDX kit at the event, and followed the Nodebots AU setup guide to get all the software bits and pieces.
For Haskelling, I used my existing Haskell installation, then created a new cabal sandbox
and installed the hArduino package (v0.9) into it.
A simple circuit
Here’s a simple circuit that includes a potentiometer and a bunch of LEDs. The idea is that as someone turns up the potentiometer, the number of LEDs switched on increases accordingly. (Yes, this may seem somewhat unimpressive, but as a complete newbie who managed to do this without blowing anything up, I’m calling it a win! :))
Haskellbot
So now I’m in my cabal sandbox and it’s time to write some Haskell. Here’s the main outline of the program (with some explanatory comments added).
After the initialisation stuff, the main bit of the program is the run loop, which polls the potentiometer and updates the LEDs whenever the value changes.
The updateLeds
and related code looks like this:
The updateLeds
function takes the potentiometer value and works out how many LEDs it needs to turn on based on the numLedsOn
function. It then loops through each numbered LED and turns it on or off based on whether the ledNum <= maxLedNum
we need to switch on.1
numLedsOn
doesn’t need to be a separate function like this, but I found it helped to be able to test my arithmetic independently of hardware. :) (We could also get away without specifying any types, but I find doing so makes it easier for me to read.)
Running this… er… ‘masterpiece’
Rather than setup a build, I just ran cabal repl
from my sandbox to get a GHCi with the hArduino
package accessible, then loaded and ran the code:
ghci> :load lights.hs
ghci> main
Now I could finally fulfill my life-long dream of adjusting LEDs using a twirly dial! Hooray! :)
The
updateLeds
loop is a bit neater in applicative form, but assumes familiarity with the operators:for_ (zip leds [1..]) $ digitalWrite <$> fst <*> ((<= maxLedNum) . snd)
↩