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.

Thursday, 24 April 2014

A Brighter BubbleSort

On of the great things about embedded computing is that it lets you measure all sorts of fun things. By taking programming out into the "real world" it becomes much more engaging, but then we bring it back home and display it on a screen and it all gets a bit dull again. What if we could display our results in a physical fashion?

I just got hold of 1m of SMRT Pixels from Embedded Adventures. These are basically the same as AdaFruit NeoPixels as they're both based on the WS2812B chip/led system. NeoPixels are tricolour LED's, but what makes them special is that they have a controller embedded on each one which allows you connect them together in a chain, and control any number with a single control pin. The colour of each of the 30 LED's in my 1m strip can be individually controlled!

The way these works makes them very tricky to program, as the timing has to be accurate to about a micro-second. This is hard on a 16Mhz Arduino, and even harder on a Pi as its got a whole load of other code running on it at the same time. Fortunatly AdaFruit have some good Arduino code, so I took that and wrapped it into a Sniff "neoPixel" device - currently Arduino only.

make neoPixel device 3
make neoShade list of number
make neoColor list of number

The string of pixels is connected to pin 3, and the colour of the pixels is controlled by two lists - neoColor and neoShade. These follow the Scratch pen colour model, that the newColor list sets the Hue, while the Shade controls brightness.

To turn the LED's on we just give them a colour:

when start
.set ledCount to 16
.set ledA to 0
.repeat ledCount
..add (ledA/ledCount)*120 to neoColor
..change ledA by 1
.tell neoPixel to "show"

We're not worried about brightness, so I've ignored the neoShade list - if you don't add entries to that list it assumes the default value of 50 (0 is black, 100 is white, 50 is a fully saturated colour). The neoColor list is filled in with values from 0 to 120, which is 1/3 of the way round the colour circle from Red to Green. 360 takes us all the way back through blue and back to red again (Scratch uses a value of 200 but 360 makes far more sense!).



Of course the obvious thing to do is produce lots of cool animated patterns - which of course I did, but there's plenty of other fun things you could do to visualise data using these: you could make a Pie Chart (or what ever a linear Pie chart is called?), you could move dots at specific speeds, you could make a giant thermometer. You can of course cut these into shorter strips, so you could make a digital abacus, or a clock face, or any number of cool things (I've got a totally insane project in mind for these, but thats for another day!).

I filled the strip with red to green rather than a full spectrum for a specific reason... because we're going to sort them, and red to green has a clear "order". Sorting is a classic computer science problem, and it usually involves lists of numbers. The SMRT/NeoPixel strip makes in physical! Rather than some abstract values, the colours actually mean something, and we need to "repair the rainbow!".

First we need to break the rainbow:

when swap
.set tmpVal to item ledA of neoColor
.replace item ledA of neoColor with (item ledB of neoColor)
.replace item ledB of neoColor with tmpVal

.repeat ledCount
..set ledA to pick random 1 to ledCount
..set ledB to pick random 1 to ledCount
..broadcast swap and wait

The best way to make a messed up list is to start with a good list, then pick random pairs and swap them over. If you think it would be better to just generate a list of random numbers, feel free to read up on low discrepancy sequences, then come back and do it my way... (actually its not really a big deal here, but something like a Halton Sequence is far better than random numbers for lots of applications - but I digress).



To help us see what going on we can create a showSwap script which flashes the pixels back and forth a couple of times, so we can see they're being swapped:

when showSwap
.repeat 3
..broadcast swap and wait
..tell neoPixel to "show"
..wait 0.01 secs

when showNoSwap
.repeat 2
..broadcast swap and wait
..tell neoPixel to "show"
..wait 0.01 secs

showNoSwap does the same, but leaves them back where they started, so we can show they were compared at but not swapped.  You probably want to adjust the timings to slow things down (unless you're trying to make the whole demo fit in a six second video).

.repeat ledCount
..set ledA to 0
..repeat ledCount-1
...set ledB to ledA+1
...if item ledA of neoColor > item ledB of neoColor
....broadcast showSwap and wait
...else
....broadcast showNoSwap and wait
...change ledA by 1

And finally we're ready to sort the list, using a bubble sort. A bubble sort compares the first two items, and if they're in the wrong order its swaps them. It then compares the second and third, and so on until it reaches the end of the list. If you repeat that enough times, then the list ends up sorted (enough times being some unknown number less than or equal to the number of elements in the list).



I feel compelled to point out that bubble-sort is a TERRIBLE way to sort a list, and this isn't even a good bubble sort, but its probably the first sort everyone learns, and the point here is that we're visualising the sort,  not that we're doing a good job of sorting. You really should be using something better - a comb sort or shell sort is only a little more complex. A quick sort is generally best, but is a bit more tricky...

The code for this will of course go into the next Sniff release, but for now you can download and install the files yourself:Download

The code is tested on a standard 16Mhz Arduino, but should support a variety of AVR speeds, and the Due ARM board. If you try it on any other boards, then let me know how you get on.








Wednesday, 23 April 2014

Wii Mouse

One of the fun things you can do on the Leonardo and Yun boards is send "HID" messages over USB to a computer. HID stands for "Human Interface Devce", and basically means any kind of Joystick, Trackpad, Mouse or Keyboard.  While this features main application appears to be practical jokes, such as moving someones mouse randomly, or logging them out at unexpected times, it can actually be useful.

One thing you can easily do is hook up a wii nunchuck controller and pretend its a mouse - handy if you have to stand at the front of a room demoing some software in front of a projector, and don't want to be tied to a desk. Similar "Air Mouse" devices are available commercially, but building one yourself is far more fun, and totally configurable (and its cheaper even if you buy all the parts especially for the project - you can get a Leo + wii nunchuck for less than $10 on ebay).

Lets start with the nun-chuck: It turns out Nintendo used i2c to communicate between the Wii and the Nunchuck controller, so you can just cut the Wii connector off a cheap controller and solder on some pins to connect it to an Arduino. Unfortunately you may not know what each wire does! You can figure it out pretty easily with a multimeter, or you can by an adapter on ebay which plugs into the Wii plug and breaks out the pins. I took the middle route - I bought an adapter, got it working, then used the adapter to help me find the correct wires.

There are 4 wires to connect - ground, power, data and clock. Strictly the wii controller is a 3.3V device, but it works OK at 5V (I used 3.3v for mine). Watch out when connecting Data and Clock - on an Uno these are on pins A4 and A5 respectively, but on an Leonardo or Yun they're on the last two (probably unmarked!) pins next to D13, and ARef. Data is the one next to ARef, and Clock is the final pin. Strictly speaking we're taking some liberties with the voltages here, but the Ninchuck's don't seem to mind - If you're wiring this up permanently you might like to use a slightly more legitimate approach to i2C wiring, but this is fine for a fun test...

On to the code:

make i2c device
make wiiNunchuck device
make wiiZbutton boolean
make wiiCbutton boolean
make wiiJoyX number
make wiiJoyY number
make wiiAccX number
make wiiAccY number
make wiiAccZ number

when start
.forever
..tell wiiNunchuck to "read"

OK that's a lot of lines, but actually that's just because the Wii controller collects a lot of data! For a couple of dollars you get a Joystick, two buttons and an accelerometer. Each time we call read on the nunChuck device it updates all of these values.

To pretent to be a fake mouse, we need to create a usb and a mouse device:

make usb device
make fakeMouse device
make mouseDeltaX number
make mouseDeltaY number

Now we can code the actions we want to perform:

when start
.forever
..set mouseDeltaX to wiiJoyX*0.5
..set mouseDeltaY to -wiiJoyY*0.5
..tell fakeMouse to "move"
..wait 0.02 secs

when start
.forever
..wait until wiiZbutton
..tell fakeMouse to "leftClick"
..wait until not wiiZbutton

when start
.forever
..wait until wiiCbutton
..tell fakeMouse to "rightClick"
..wait until not wiiCbutton


I first mapped the Joystick position to the mouse movement. Of course you could also use the accelerometer.  You can also play with the scaling and timing to adjust the speed of the mouse pointer. Once we've decided how much to move the mouse pointer just 'tell fakeMouse to "move"'.

Simlarly I mapped the two wii buttons to left and right click. Currently the fakeMouse device restricts mouse actions to clicks rather than up/down so that there's always a valid up/down->click pairing, rather than potentially sending a down, and forgetting to send an up. This could be changed - feedback is always appreciated.

And that's it - plug it together, double click the leo/yun reset button, then run leo-sniff (yun-sniff). Occasionally the code downloaded into a yun/leo doesn't start running immediately, so if it doesn't work, hit reset once more. Downloading is a bit more fiddly with these Arduinos - unfortunately its known problem that happens even when you're running the official Arduino software.

There's lots more you could do with this - you could map the accelerometer the mouse movement, and use the joystick for send pre-defined key presses, for example to move forwards and backwards through a presentation. You could even add some buttons and a screen to the Arduino, to select different configurations, or maybe even automatically type predefined messages.

Tuesday, 22 April 2014

Release 6

After putting if off for a while in favour of building rc-cars and hot wheels test track, the Sniff Beta 6 release is now available from the Downloads page.

Looking at release notes it doesn't look like there's much there, but Arduino Yun and Leo support is actually pretty huge.  These boards handle USB on the main processor, which means they can pretend to be a mouse or a keyboard (Wii mouse anyone?). Remember to include the usb and usbConsole devices if you want to be able to print stuff out the host computer! The downside to this flexibility is that you have less memory left for your code (as about 6.5K is used up by the USB stuff), and programming is a little more tricky, so stick with the Uno over the Leo unless you need these features.

The Yun however is a different beast - it runs Linux on one processor, and has regular (ish) Arduino piggybacked on. This means you either communicate with it like a Leo, or use the Unix side to access it via the network. The Yun-upload script lets you send a compiled Sniff program to the Yun over the network. 

Your Sniff program can also talk to the Linux processor using the Bridge device. This doesn't yet support the full range of services in the Arduino Bridge library, but allows you to use the bridgeConsole to access text i/o over the network (check the examples and manual for more info - YES there's a manual!!).

Arduino bridge also supports keystore access. This is a great feature of the Yun that's massively under documented in the Arduino world. Using the bridgeKeystore device, you can use the variables bridgeKey, and bridgeValue to put and get values into a dictionary that's held on the Linux side of the Yun. Most crucially you can access this store from elsewhere on the network using http. Just access the URL: arduino.local.//data/get or arduino.local.//data/get/keyname to fetch values, and arduino.local.//data/put/keyName/newValue to change them. For example you could use this to fetch values from a sensor, or send values to a controller, without having to write any significant networking code.

Elsewhere there's also support for i2c lcd displays, and the lpd8008 device is now included. Other new examples include code for PiBot, Pibrella, 7Seg, and the Hot Wheels demo.

Friday, 18 April 2014

Lighting McQueen Vs the Batmobile

I've been wanting to build some kind of speed trap experiment for ages, and today I finally built it, and it worked out great - total component costs less than $1 to answer the question that every five year old boy, and everyone who's ever been a five year old boy wants answered: Could Lightning McQueen beat the Batmobile in a straight race?

To answer this, we need to build a speed trap to measure their top speed. As speed is just distance divided by time, the easiest way to do that is to trigger something at one point on the track to start a timer, and then trigger further along the track to stop the timer. We can measure the distance, divide it by the measured time and we've got our answer!

There are bunch of different triggers we could use but by far the best is a light dependant resistor. These cost pennies, and I had a bag of 20 or so, so I melted a couple of holes at each end of a piece of hot wheels track and put an LDR in each.


The LDR has a low resistance when there's light shining on it, and a higher resistance when not. The ones I had measured around 10Kohms so I wired the LDR at the top of the track between 5V and Arduino A0, and a 10K resistor from A0 to 0V. I repeated this at the other end of the track with Arduino A1 to stop stop the measurement.

I also used an LCD Shield for display and a Sensor Shield to make hooking this up easier, but they're strictly optional.

make lcd device
make message string

make startTrigger analog input A0
make endTrigger analog input A1

make startTime number
make recordedTime number
make recordedSpeed number
make distance number

when start
.set distance to 0.3
.
.forever
..tell lcd to "clear"
..set message to "Hot Wheels Speed Trap"
..tell lcd to "show"
..set message to "ready..."
..tell lcd to "show"

First thing the code does is create an LCD device and two analog inputs. To calibrate the system we need to measure the distance between the sensors, and for a standard piece of hot wheels track it turns out that they end up exactly 30cm apart. Then we display a "ready..." message on the LCD.

..wait until startTrigger < 0.5
..set startTime to timer

Now we just wait for the start gate to be triggered. The value of 0.5 might need a bit of tweaking depending on your lighting conditions and components, but for me using a 10K resistor in a normally lit room, 0.5 worked pretty reliably. 

..wait until endTrigger < 0.5

We could use the same code to wait for the timer to end, but if you're timing over a longer piece of track you might like to use:

..repeat until endTrigger < 0.5
...tell lcd to "clear"
...set message to [timer - startTime ]
...tell lcd to "show"

to give a runing timer through the speed trap. However over a single track piece removing this improves accuracy, and you couldn't really see it any way.


..set recordedTime to timer - startTime
..set recordedSpeed to distance/recordedTime
..
..set message to "time       :"
..set message to join message [ recordedTime ]
..tell lcd to "show"
..set message to "speed (m/s):"
..set message to join message [ recordedSpeed ]
..tell lcd to "show"
..wait 5 secs

Now we just calculate the elapsed time, and speed. Of course this is in metres per second, so multiplying by 3.6 gives kilometres per hour.

..set recordedSpeed to recordedSpeed*3600/1000
..set message to "speed (kph):"
..set message to join message [ recordedSpeed ]
..tell lcd to "show"
..wait 5 secs

So what to the results tell us? Well both cars clocked in at 0.10 seconds for the 30cm distance, giving a speed of 3m/s or around 11km/h when run down a ramp about 1m high.

That's a potential energy (mgh) of 10m (where m is the mass of the car, h is the height and g is gravity which I'm calling 10 cause its close enough). That gets turned into  kinetic energy(1/2 mv^2or about 5m (1/2m*3*3 - I'm rounding up again!). That's actually pretty good as there's a lot of friction to be dealt with and we're turning the car through 90 degrees as it wants to drop down, but we push it forwards, so 50% efficient isn't at all bad. The best we could hope for on this track is about 4.5m/s or 16km/h.



There's lots more you can do with this - different cars, different heights, different shapes of tracks.


My money's on this guy - on the ground he only does 0.1kph but on the way to Mars he clocked in at around 21,000kph!

Tuesday, 15 April 2014

2500 LEDS!


Some time ago I picked up a couple of LPD-8008 displays from Embedded Adventures. Each display is made up of ten of the 8x8 LED matrices  that are often hooked up to Arduino and Pi's. That's 64 pixels per matrix,or 128 LEDs (as they're tricolour),making 1280 LED's per panel. Hooking up two panels makes a crazy 2560 LED's.

Half the time, when you buy stuff like this, half the problem of making it work is figuring out exactly what you have - but in this case the documentation is excellent. One thing it warns about when hooking up these panels is that this many LED's can use a lot of power. If you try turning on all of the LED's at the same time, then you need 2.5A (@5V=12.5W) per panel. What this means is that you shouldn't be running it of the internal power regulator of your Pi or Arduino... In practise you'll just about get away with it for displaying text as most of the pixels are off most of the time, so power consumption is a lot lower . However I did overload the Arduino power supply several times during development so I wouldn't recommend it - particularly on a Pi where reseting the PSU is far more serious than an Arduino.

To get these working in Sniff, I wrote a new lpd8008 device extension. While it would be possible to drive the whole thing from Sniff, writing an extension hides the internals, and makes it easy to use complex devices with only a few lines of code. The heavy lifting is done by the extension which consists of the two files Xlpd8008.h and Xlpd8008.c. Placing these in the Sniff lib directory automatically adds the device into your Sniff system.

For Arduino I chose the fairly arbitrary pinout:

  • Arduino 4 -> A
  • Arduino 5 -> B
  • Arduino 6 -> C
  • Arduino 7 -> D (Unused in the 8008)
  • Arduino 8 -> Enable
  • Arduini 9 ->  Green
  • Arduino 10 -> Red
  • Arduino 11 -> Latch
  • Arduino 12 -> Shift
You can check this in C file, as it might change in future (there are also pins declared for Raspberry Pi). Hooking up multiple displays is simply a matter of daisy changing them together with a ribbon cable!

One of the tricky parts of using these kinds of displays is that they only display one row of pixels at a time - you need to keep displaying each line in turn. Driving this from most programming languages generally means some tricky programming: you either need interrupts, or to integrate the screen refresh into your main code - you can't just display a message and forget about it. However Sniff repeatedly demonstrates its power here. Multiple scripts can run in parallel, so to get the display up and running we just need to use the following lines of code:

make lpd8008 device 160
make message string
make startColumn number
make endColumn number
make ledColor number

when start
.forever
..tell lpd8008 to "tick"

when start
.set message to "Hello World!"

We start by making an lpd8008 device, but as I'm using two hooked together I tell it to use 160 columns (rather than the default 80). The device supports a single command "tick" - which updates one row of the display. The first script is set up to constantly call this function, so that the whole display is active. In the second script we simply set the variable message, which contains the string to be displayed.

StartColumn allows you to shift the message right or left, so we can scroll the message to the right by simply using:

when start
.set message to "Hello World!"
.set startColumn to 0
.repeat until startColumn=160
..change startColumn by 1
..wait 0.1 secs

However this scrolls the message off the screen completely. If we just want to bounce a short message from left to right, so that it all stays on screen, we need to know the length of the text. This is a little tricky: the extension uses the standard 5x8 pixel font every device, but to make the most of the limited screen space, and to simply make it look better it proportionally spaces the letters. To make things easier, the "tick" command calculates the variable endColumn, which we can use. To scroll to the right, stopping while the whole message is still visible we an use:

..repeat until endColumn=160
...change startColumn by 1
...wait 0.1 secs

To bounce a message back and forth we can use:

.repeat 2
..repeat until endColumn=160
...change startColumn by 1
...wait 0.1 secs
..
..repeat until startColumn=0
...change startColumn by -1
...wait 0.1 secs

To Scroll it from offscreen right to offscreen left we can use:

.set ledColor to 2
.forever
..set startColumn to 160
..repeat until endColumn<0
...change startColumn by -1
...wait 0.1 secs

This also sets the colour to green (1=red, 2=green, 3=orange).

While its certainly possible to do more with these displays than just text, a large easily programmable text display that can easily be added to your own projects is a lot of fun. Here's a simple count down, which looks really cool:

make counter number
when start
.set startColumn to 15
.set ledColor to 3
.
.repeat until counter <0
..set counter to 10-timer
..set message to [ counter ]


The files will be included in the next Sniff release, but in the mean time you can download and install them into your current Sniff system: Download. They've been developed and tested on Arduino, but should work fine on Pi too.

Personally I'm looking forward to hooking this up to a Punchthough Bean, and displaying my phone notifications on it!

Sunday, 6 April 2014

Pibot

@code_ED and I had a bit of a catch up last week, and he leant me a few toys to play with -  an Arduino Yun and one of his PiBots (http://raspberryfool.net). I'll save the Yun to talk about another day, but the PiBot works great with Sniff.

The PiBot consist of two tracked sets of wheels, driven from a board which handles the electrical side of things, including providing battery power to the Pi. Driving it from Sniff is pretty easy (once I'd figured out that the sample Python code used Pi header pin numbers rather than broadcom gpio pin numbers).

make pibotPower digital output 17

make leftForward digital output 18
make leftBackward digital output 27 #21 on rev 1 Pi board
make rightForward digital output 23
make rightBackward digital output 24

Firstly we set up some digital outputs. The pibotPower is a global on/off switch which also resets the driver board - the driver board includes a kill switch, which turns out to be pretty handy when your robot gets out of control (note when it gets out of control, rather than if). The first thing the code needs to do is turn off the power to reset the kill switch, then turn on the power:

when start
.set pibotPower to no
.wait 0.2 secs
.set pibotPower to yes


and then we can start moving around. To go forwards:

.set rightBackward to no
.set rightForward to yes
.set leftBackward to no
.set leftForward to yes

and of course we can go backwards similarly:

.set rightBackward to yes
.set rightForward to no
.set leftBackward to yes
.set leftForward to no

To stop, we can either kill the master power, or set all of the values to "no". To turn we just send one track forwards and the other backwards:

.set rightBackward to yes
.set rightForward to no
.set leftBackward to no
.set leftForward to yes

slightly counterintuitivly, sending left forwards, means you're turning right!

It's pretty easy to put each of these in a script, and then move the PiBot around using something like:

.repeat 4
..broadcast forward
..wait 1 secs
..broadcast left
..wait 1 secs
.broadcast stop

However while this works fine, and is a really good way to get started I wanted to do something more fun. To get the PiBot to move more smoothly we need to be able to set the speed of the motors. We would do this by changing the voltage supplied to them. Unfortunately the PiBot can't do that, but what if we turned the motors on and off really fast - like 1000 times a second. If they were on for half the time, and off for half the time, then it would look like they were running at half speed (in fact they probably are because the motors probably take longer than that to stop or start). This is exactly the trick the Arduino uses when we use an analog output as the Arduino's AVR chip has hardware specifically to do that, but the Pi's GPIO can't do that either.

But as I've worked with Sniff I've found that its surprisingly good at doing stuff like that. It's not really designed for high speed low level IO, but it seems work.

make leftSpeed number

when start
.forever
..if leftSpeed>0
...set leftBackward to no
...set leftForward to yes
...wait leftSpeed*1000 microsecs
...set leftForward to no
...wait (1-leftSpeed)*1000 microsecs
..else
...set leftForward to no
...set leftBackward to yes
...wait leftSpeed*-1000 microsecs
...set leftBackward to no
...wait (1+leftSpeed)*1000 microsecs

We have a number "leftSpeed" which is going to go from -1 to +1. -1 is full speed backwards, while +1 is full speed forwards. I'm sure there's a more elegant way to do this, but we handle forwards and backwards separately. If we're going forwards then we turn the left motor on for a fraction of a millisecond, then off for the rest of the millisecond. The longer that fraction then the more power goes to the motor, and the faster it goes. Same for backwards, and the same for the right track.

.set leftSpeed to 1
.set rightSpeed to 0.5
.wait 10 secs

makes the piBot turn in a nice circle, while to get the sidewinder dance in the video, you can try:

.forever
..set leftSpeed to  sin of (timer * 100)
..set rightSpeed to  cos of (timer * 100)

Just set leftSpeed and rightSpeed to the values you want, and off it goes!

here's the complete code:

make pibotPower digital output 17

make leftForward digital output 18
make leftBackward digital output 27 #21 on rev 1 board
make rightForward digital output 23
make rightBackward digital output 24

make leftSpeed number
make rightSpeed number

when start
.forever
..if leftSpeed>0
...set leftBackward to no
...set leftForward to yes
...wait leftSpeed*1000 microsecs
...set leftForward to no
...wait (1-leftSpeed)*1000 microsecs
..else
...set leftForward to no
...set leftBackward to yes
...wait leftSpeed*-1000 microsecs
...set leftBackward to no
...wait (1+leftSpeed)*1000 microsecs

when start
.forever
..if rightSpeed>0
...set rightBackward to no
...set rightForward to yes
...wait rightSpeed*1000 microsecs
...set rightForward to no
...wait (1-rightSpeed)*1000 microsecs
..else
...set rightForward to no
...set rightBackward to yes
...wait rightSpeed*-1000 microsecs
...set rightBackward to no
...wait (1+rightSpeed)*1000 microsecs

when start
.set pibotPower to no
.wait 0.2 secs
.broadcast startPiBot
.
.set leftSpeed to 1
.set rightSpeed to 0.5
.wait 10 secs
.
.reset timer
.repeat until timer > 10
..set leftSpeed to  sin of (timer * 100)
..set rightSpeed to  cos of (timer * 100)
.
.set pibotPower to yes

Of course the real irony is that the PiBot board includes an AVRTiny processor to handle the kill switch. Sniff works great on AVRTiny processors - with a bit of tweaking to allow reprogramming, the PiBot board could run all this stuff itself, and it wouldn't even need the Pi!