Sniff is a "Scratch-like" programming language that's designed to help Scratchers move gently from Scratch to more conventional languages. They can start writing programs, without having to learn a new language because Sniff is based on Scratch. They learn a little more about variables, compiling, syntax errors (!), and they can have fun controlling real hardware while they're doing it.

Wednesday, 4 February 2015

The Lighthouse Keepers Arduino

The Lighthouse Keepers Lunch is a book all primary school teachers are probably familiar with, and its often used to spin off lots of different projects. On of the more obvious being to build a model lighthouse! I couldn't resist totally over-engineering an Arduino/Sniff powered lighthouse, that can create different lighting patterns. While the kids at this age are too young to fully understand the details they can certainly recognise that we're using a computer, and electronics to make something that's real and fun, rather than just another powerpoint presentation. If they learn at this stage that you can make cool things by programming, then when they get the chance to do it themselves they're more likely to jump in.

I wanted to make something that could "turn" rather than just flash, so rather than use a single LED I arranged 6 around a heavy cardboard tube. By turning them on and off one individually we can make any pattern we like. For each LED I made two holes in the tube - one near the top which I pushed the negative leg through, and then I ran the postive leg of each LED down the outside of the tube for a short distance before putting it through the second hole. I secured all the LEDs in place with tape before soldering them in inside the tube.





Inside I ran a loop of white around the top, connecting all of the legs together. The postive legs were soldered individually to the strands of a 3pin dupont cable I cut in half. That gave me six signal wires, and one earth wire to connect to an Arduino.

The Arduino Nano I used, is almost exactly the same as an Uno, using the same AVR 328 chip operating at 5V, with more or less the same pins. However its format makes it more suitable for permanent installation in projects like this:  It has 30pins arranged so that they can be plugged easily into breadboard, strip board or protoboard, which is less friendly than the standard Arduino layout, but easier to integrate with other circuits. It's also cheaper (as little as £2) and smaller which both are nice bonuses.

Like the Uno the Nano have 13 digital pins, which we could use to flash our LEDs on and off, but pins 3, 5, 6, 9, 10, and 11 support PWM which will allow us to adjust the brigtness of the LEDs by turning them on and off really quicky. Setting a value of 0.5 means the LED is actually only on half the time, but changes so quickly it looks like its half brightness. Fortunately there are exactly 6, which is the number we need, I wired each pin to the headers using a 1K resistor.

If we do the maths, then this means we're getting somewhere around 3mA per LED. LED's can typically handle up to around 20mA, so we could use a resistor as low as 200ohms, but the LED's were sufficiently bright as is, and 1K keeps us well within limits of what the chip can provide. To be honest I had loads of 1K's lying around, but was a bit short on 200ohms and need them for another project so...

With everything wired up it was time to build the software. While this is initially being build as a demo, at some point I hope to get students reprogramming it. All the electronics will be packed away, but there'll still be external power via USB, so it'll always be possible to load new code onto the board. I'd exect them to write something like:

make led1 digital output 3
make led2 digital output 5
make led3 digital output 6
make led4 digital output 9
make led5 digital output 10
make led6 digital output 11

when start
.forever
..set led1 to on
..wait .5 secs
..set led1 to off
..
..set led2 to on
..wait .5 secs
..set led2 to off
..
..set led3 to on
..wait .5 secs
..set led3 to off
..
..set led4 to on
..wait .5 secs
..set led4 to off
..
..set led5 to on
..wait .5 secs
..set led5 to off
..
..set led6 to on
..wait .5 secs
..set led6 to off

This is pretty good first start, and is handy for debugging the hardware - primarily making sure I'd plugged the cables in the right way. Everything works fine if you plug the LED cables in, in a different order, but we really need them to go in a sensible order around, rather than being randomly connected. We could fix it in software, but swapping the plugs around is easier.

Now its time to write the "real" software.

make led1 analog output 3
make led2 analog output 5
make led3 analog output 6
make led4 analog output 9
make led5 analog output 10
make led6 analog output 11

Here I've changed the outputs to analog so we'll be able to fade them on and off gradually. Lets start by flashing them all in sync:

when start
.forever
..set theta to timer*180
..set brightness to (sin of (theta))*0.5+0.5
..
..set led1 to brightness
..set led2 to brightness
..set led3 to brightness
..set led4 to brightness
..set led5 to brightness
..set led6 to brightness

Whenever I want something to fade in and out, I use a sin() function (understanding the "shape" of functions is really usefull, even if you don't know the maths - you don't need to wait until kids understand sin and cos to introduce sin as a function that goes up and down! While calculators may have reduced this kind of intuition, computing offers the chance be bring it back). I scale it to between 0 and 1, and all the lights pulse on and off.

However I didn't like the way this looked - the LED's were on most of the time, and only pulsed off briefly (on lighthouse terminology this is an "occult" light - where the light flashes off, rather than flashing on). But using my experience of "shaping" functions to produce the right look (believe it or not, thats a skill that gets you a job in the movies!) I know that if I raise a function to a power, the brightest bits stay bright, but the dark values get pushed towards 0. A little trial and error and I came up with:

when calcBrightness
.set brightness to (sin of (theta))*0.5+0.5
.set brightness to brightness * brightness
.set brightness to brightness * brightness
.set brightness to brightness * brightness

I wanted the lighthouse to have "modes" so it could be on, off, flashing or spinning, so I used a mode variable to choose when the flash script is active:

when start
.forever if mode=0
..set led1 to 0
..set led2 to 0
..set led3 to 0
..set led4 to 0
..set led5 to 0
..set led6 to 0

when start
.forever if mode=4
..set led1 to 1
..set led2 to 1
..set led3 to 1
..set led4 to 1
..set led5 to 1
..set led6 to 1

when start
.forever if mode=2
..set theta to tVal
..broadcast calcBrightness and wait
..
..set led1 to brightness
..set led2 to brightness
..set led3 to brightness
..set led4 to brightness
..set led5 to brightness
..set led6 to brightness

0 is off, 1 is going to be spin, 2 is flash, on 4 is always on. To produce the spin we just need to modify our flash so that each LED is out of phase with the others:

when start
.forever if mode=1
..set theta to tVal
..
..broadcast calcBrightness and wait
..set led1 to brightness
..
..change theta by 60
..broadcast calcBrightness and wait
..set led2 to brightness
..
..change theta by 60
..broadcast calcBrightness and wait
..set led3 to brightness
..
..change theta by 60
..broadcast calcBrightness and wait
..set led4 to brightness
..
..change theta by 60
..broadcast calcBrightness and wait
..set led5 to brightness
..
..change theta by 60
..broadcast calcBrightness and wait
..set led6 to brightness
..
..wait 0.01 secs


We have six LED's 60 degrees apart - easy.

Finally we have mode 3: The Lighthouse Keepers Disco!

when start
.forever if mode=3
..set tVal to 0
..wait until tVal > 90
..set led1 to pick random 0 to 1
..set led2 to pick random 0 to 1
..set led3 to pick random 0 to 1
..set led4 to pick random 0 to 1
..set led5 to pick random 0 to 1
..set led6 to pick random 0 to 1


Wait a period of time, and then turn each LED on or off randomly. We could do something to fade them randomly too, but for this effect full on or off worked better.


So far all the patterns have been driven by tVal, which we're going to set in the final script. Initially I planned to control the speed and modes using either a Wii Nunchuck, or an InfraRed remote control. Both of these are simple to implement in Sniff, and normally work well, but we hit a snag with each. The Wii controller has a cable about 1m long - not long enough to run from the electroncs at the top of the lighthouse to the bottom where it could exit the model unobtrusively. I guess we could have just taken it out from the top of the lighthouse like some kind of washing line, but... well... those pesky seagulls and all!

Setting up the IR controller would have been neat - a small IR receiver costs less than a pound, and we could mount it somewhere on the outside of the lighthouse. Unfortunatly the IR software uses one the the Arduino's timers, which is needed to do PWM on pins 3 and 11. If we just had 4 LEDs, or they were just on/off, then it would have worked, but we really need 6, and the fading looks really cool!

As it happens sometimes having to think a bit harder and longer about a problem turns up a better solution. I'd wired up a couple of headers on the  A2 and A3 pins to connect some kind of controls, and any extra hardware, so I attached a pot to control the speed (just attach the ends to 0 and 5v, and connect the wiper to A3):

make speedDial analog input A3

when start
.set mode to 1
.forever
..change tVal by 720*speedDial*0.01
..wait 0.01 secs

speedDial will read between 0 and 1, so on max it till advance by 7.2 steps per iteration, or two revolutions per second. If you've not  tried this then its definitely recommended - in a world of buttons, a good old fashioned dial to control the speed of the light is refreshingly direct.

I then started thinking about adding an extra button or control to select the mode, but then I realised if  you turn the dial all the way to the left it stops the animation - and we can use that as a trigger to advance the mode. All we need to do is tag the following code on the end of the previous speed control code:

..if speedDial < 0.05
...change mode by 1
...if mode>4
....set mode to 0

...wait until speedDial >0.05

Full control with a single dial, and nice analog control over the speed. Though it takes a few seconds to understand how the control works, once you get it, its a far nicer system than either of the "controller" based solutions solutions would have been.

And with that the electronics was done. Now we just need to hand it over to the structural team to build it into the tower... The top section, including the balcony just lifts off for maintenance, and the Arduino is suspended underneath it. The USB connector and the cable for the pot run down inside, and exit through a small hole at the bottom... and and here it is:






No comments:

Post a Comment