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.

Friday, 18 December 2015

Sniff and Flotilla

I recently posted that my Flotilla Medium starter kit had arrived, and I documented the low level code that you might find useful if you were going to write your own code to talk directly to the hardware. You could actually to that yourself entirely in Sniff using the serialPort device, but the plan was always to add Sniff devices to support the Flotilla.

I've now got those working, and you can download them and add them to an existing Sniff installation. Normally I'd release this as part of a full Sniff release, but it's getting close to Xmas, and I probably won't get a full release out until the new year. There's a particular cool feature that needs a little more work, so I'm holding off until that's fully working. In the mean time here are the files you need to try it out. The drivers (in the XHosted folder) need to be added to the lib/XHosted folder you already have. There are also some examples which I'll talk about now... [Update: as of R24 Flotilla support is included i the current release]

To compile the examples, use the normal "sniff" commands. On Unix platforms the Flotilla gets found the same way as an Arduino when you run "./setup". On Windows you'll need to explicitly tell it by typing:

export ARDUINODEV=COM4

or whatever port you have it on in the shell after you've run setup.



make flotilla device

make light flotillaLight device
make brightness number

when start
.forever
..tell light to "update"
..say join "Brightness:"[brightness]
..wait 1 secs


The first thing you need to do is make a flotilla device. This represents a the flotilla dock and much like the dock you don't actually need to do much with it. It just acts as a hub for all the other devices you might want to use.

Once you've got a dock you can make an actual module and do something with it. Here I've attached a light module, by making a flotillaLight device and calling it light. The Flotilla has 8 ports, but you can plug the module into any of them - Sniff will look for a light sensor and use whichever port it finds it on. However if there isn't one plugged in then it will give and stop your program.

Alternatively you can specify which port the module is plugged in to:
make light flotillaLight device 4

This has the advantage that if you've not plugged it in yet you'll get a warning message but your program will keep running, and you can plug the device into port 4 later. In future you'll also need to use this if you want to plug in multiple devices of the same type (the mega-treasure chest includes two light modules and two motors). At the moment you can only attach one of each type of module, but that'll be fixed before the full release.

To read or write a sensor, just tell it to "update". You can also tell the dock to update, which you might want to do if you're not updating any other sensors for a long time just to give it a chance to do any housekeeping work, but this generally shouldn't be necessary.

In the case of the Light sensor "update" sets the variable brightness and we just print it out.


make flotilla device
make thermometer flotillaWeather device
make temperature number
make pressure number


when start
.forever
..tell thermometer to "update"
..say join "temp :"[temperature]
..say join "pressure:"[pressure]
..say ""
..wait 1 secs


Weather works in the same way, setting temperature and pressure.

make flotilla device
make keypad flotillaTouch device 
make key1 boolean
make key2 boolean
make key3 boolean
make key4 boolean


when start
.forever
..tell keypad to "update"
..if key1
...say "1" 
..if key2
...say "2" 
..if key3
...say "3" 
..if key4
...say "4" 
..wait 0.1 secs

Touch sets the four variables to be true of false depending on if the button is pressed.


Rainbow is the most complex module in the Medium kit, and works just like the neoPixel device, except that we change the names.

make flotilla device
make rainbow flotillaRainbow device
make rainbowShade list of numbers
make rainbowColor list of numbers


rainbowShade is the brightness (between 0 and 100), while rainbowColor is the hue between 0 and 360. 

Rainbow Thermometer

Lets look at how we can use that to make "thermometer":

make flotilla device
make sensor flotillaWeather device 
make temperature number
make pressure number

make rainbow flotillaRainbow device
make rainbowShade list of number
make rainbowColor list of number


make counter number


when start
.repeat 5
..add 0 to rainbowColor
.
.forever
..tell sensor to "update"
..#say [temperature]
..
..delete all of rainbowShade
..set counter to 1
..repeat 5
...if counter*2+20<temperature
....add 10 to rainbowShade
...else
....add 0 to rainbowShade
...change counter by 1
..
..tell rainbow to "update"

We make a rainbow and a weather device, then fill the rainbowColor list with 0's representing red. Then we read the temperature, and fill in rainbowShade. Using counter, we calculate a value for each LED from 22 to 30 degrees. If the actually temperature is greater than that we turn the LED on (red). If its less than that we turn it off.

The result is a thermometer that displays temperatures from 20-30 degrees in 2 degree steps. This is a handy range as its easy to see the display change just by holding the sensor.

Altimeter

One of the neat things you can do with the weather sensor is measure altitude. We did this last summer using an Arduino and BMP180, but now we can do it with Flotilla. The code required virtually no changes - just swapping out the BMP180 for a flotillaWeather module:

make flotilla device
make sensor flotillaWeather device
make pressure number
make temperature number

make altitude number
make seaLevelPressure number
make seaLevelTemperature number

make message string

when start
.tell sensor to "update"
.set seaLevelPressure to pressure
.set seaLevelTemperature to temperature+273.15
.
.forever
..tell sensor to "update"
..broadcast calculateAltitude and wait
..set message to join "Temperature:" [ temperature ]
..say message
..set message to join "Pressure:" [ pressure*0.01 ]
..say message
..set message to join "Delta:" [ (pressure-seaLevelPressure)*0.01 ]
..say message
..set message to join "Altitude:" [ altitude ]
..say message
..say ""
..wait 1 secs



when calculateAltitude
.set altitude to seaLevelPressure/pressure
.set altitude to ln of altitude
.set altitude to altitude * 0.1903
.set altitude to e^ of altitude
.set altitude to seaLevelTemperature * (altitude-1)
.set altitude to altitude/0.0065


Check the original post for more details on this one. You might need a longer USB lead to get the most out of this example but its still pretty cool

Simon

Finally I wanted to do something with Touch, so I build a game of "Simon". The computer flashes the Rainbow LED's in a sequence which gets longer each turn, and you have to copy the patten on the keypad.

make flotilla device

make rainbow flotillaRainbow device
make rainbowShade list of numbers
make rainbowColor list of numbers


make keypad flotillaTouch device 
make key1 boolean
make key2 boolean
make key3 boolean
make key4 boolean

make pattern list of numbers

when start
.repeat 5
..add 0 to rainbowShade
.
.add 0 to rainbowColor
.add 120 to rainbowColor
.add 240 to rainbowColor
.add 60 to rainbowColor
.
.tell rainbow to "update"
.
.forever
..broadcast playGame and wait
..wait 5 secs

This is standard flotilla setup. Then we have a list called "pattern" that we're going to store the pattern so far in. We put four distinct colours in the rainbowColor list, but turn all the LED's off by setting their brightness to 0. Then we're ready to go...


make counter number
make led number

when playPattern
.set counter to 1
.repeat length of pattern
..set led to item counter of pattern
..replace item led of rainbowShade with 10
..tell rainbow to "update"
..wait 0.3 secs
..replace item led of rainbowShade with 0
..tell rainbow to "update"
..wait 0.1 secs
..change counter by 1


To play the pattern we  simply loop over the list turning on the required LED of a short period with a smaller time gap between each.

when playGame
.delete all of pattern
.forever
..add pick random 1 to 4 to pattern
..broadcast playPattern and wait
..
..set counter to 1
..repeat length of pattern
...set led to 0
...repeat until not led = 0
....if key1
.....set led to 1
.....wait until not key1
....if key2
.....set led to 2
.....wait until not key2
....if key3
.....set led to 3
.....wait until not key3
....if key4
.....set led to 4
.....wait until not key4
...if not led = item counter of pattern
....broadcast flash and wait
....stop script
...change counter by 1


To actually play the game we add a random led to the pattern so far then play it back. Now we need to check the the touch pad. We go through the pattern one step at a time and wait for a key to be pressed. We record the key press then wait for the key to be released.... This is important otherwise just touching one key would be recorded multiple times.

Then we check that the key pressed was the right one. If it wasn't we run a script called flash to indicate failure, and end the came. If we get to the end of the pattern then we go background, add another light to the sequence and keep going!


when start
.forever
..tell keypad to "update"
..set dummy to pick random 1 to 10
..wait 0.01 secs

You'll not that when I'm checking the buttons I'm not calling update. I need to keep calling it, otherwise the variables representing the keys will never change, but it would make the code messy, so instead I've got a separate script which just keeps calling update. (it also randomises the game by throwing away random numbers - I've talked enough about that in other posts).


when flash
.repeat 5
..delete all of rainbowShade
..repeat 5
...add 10 to rainbowShade
..tell rainbow to "update"
..delete all of rainbowShade
..repeat 5
...add 0 to rainbowShade
..tell rainbow to "update"

That just leaves flash which is pretty obvious.

Conclusions

And that's about it. So far I'm pretty impressed with the hardware. It's really nicely built, and the design allows for lots of expansion. Price wise its not cheap - the Medium kit with a dock and four modules is £39, but its not too bad. Based on the prices of the different sized starter kits I'd expect individual modules to cost between £5 and £10 (some costing more than others) when they become available. Many of the modules have arduino compatible equivalents that cost about £1, but that's from overseas suppliers. From a regular UK seller they'd cost about £4 so a couple of pounds extra to have something kid friendly and just plugs in and works is actually good value. For comparison LittleBits charge $18 for their temperature sensor!!! On the downside, having got the Medium kit up and running,  I want to do more with it than I can with just four modules, so I will need to get more modules...

Where the HW has real potential is for expansion. The design allows new modules to be added. There are currently 12 available, but I'm surprised the so called "pirates" at Pimoroni forgot to include a compass. A 16x2 LCD text screen would also be simple to add. Right now its a nice piece of fun, but wth an ever expanding range of modules at good prices, then this could be a really great piece of kit.

2 comments:

  1. Help please! I'm trying the Weather example but getting an error "No Port Name Set" when trying to run it.

    The first time I ran the .setup I didn't have the dock plugged in (oops) so ran it again after plugging the dock in. It then found the dock as an Arduino ("Using Arduino on /dev/ttyACM1") but I'm a bit stumped why I'm getting the above error...

    ReplyDelete
    Replies
    1. Sorry for not getting back to you - I missed the comment here.

      plug the dock in and run setup. it should say find "arduino" (that just means it found an interesting device. Then in the same shell, run the compiled program.

      The "no port name set" message means either setup hasn't been run in that window, or it was run and didn't find anything.

      If you're still having problems you can email me ian@dctsytems.co.uk or DM on twitter @sniffCode

      Delete