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.

Tuesday, 21 February 2017

Release 30 - at last!

It's been a while since the last release, and while there's not to much in the way of major changes there are a lot of tweaks on fixes. Most importantly the documentation is much improved - check out the "doc" folder for both an improved/updated manually and separate documentation for a lot of the different devices (as both Pages, and PDF's). This is still a work in progress, but it should make things a lot easier for everyone.

We've also made some tweaks to SniffPad that you'll appreciate if you're running on a laptop - its now a LOT less CPU intensive, which means it won't hog your battery, and it a little more responsive on slower machines.

When reworking the documentation we also made a few tweaks to the compiler - a few odds and ends had been missed, which should now work. We also changed the error message so instead of things like "syntax error" it now says things like "oops" and "I don't understand". Hopefully its a bit less intimidating (and clearer for people who don't actually know what a syntax error is yet!).

There's also the usual updates of devices and examples. We added support for cheer lights - just cause they're fun. There's a cheerlight demo for flotilla, plus code to bridge cheer light to MQTT.

Check it out on the downloads page.



Saturday, 18 February 2017

Girls Like Robots

I don't play a lot of games, but when I read about the Humble Bundle Freedom Bundle is seemed like an easy buy - lots of games and all the money goes to a good cause. So far the game that's taken up the most of my time is a little puzzler called "Girls Like Robots". It only takes a few hours to play through the whole game, but its a lot of fun.

The premise of the game is easy enough: place cards on the grid so that they all get along with their neighbours: Girls like Robots, and Robots like Girls. Nerds like girls (and robots) too, but they also like being on their own, so they like being on the edge of the board, and they don't like other Nerds. Of course Girls don't like Nerds (while Robots just ignore Nerds).

Here's a typical level (from around the point where its starts go get a little interesting). The grid is 4x3, and the level starts with a Nerd in the top left hand corner. We have to place 4 Girls, 4 Robots, and 3 more Nerds to score as many points as possible. Around 20 will pass the level, 22 to get a "Good" rating, and 26 is the perfect score.

It's the sort of problem that's really easy to solve with a little code - while we could do something clever, the easiest thing to do is just generate random placements and keep track of which is the best one. So lets give it a go!

The first problem is that Sniff only has a List which stores things in order - there's no easy way to obvious represent a 2D grid. We could make a list of strings, with each character representing a grid slot, and each string representing a row, but replacing individual letters would be fiddley.

Instead I made a list of numbers. Each number represents one square, along each row and then on to the next. We use a couple of other variables to store the height and width.

make arena list of numbers
make width number 4
make height number 3

make  empty number 0
make girl number 1
make robot number 2
make nerd number 3

make edge number 99

Now we can just make up a number to represent each card type, and use that number but its going to be much clearer if we use a constant. I've declared empty, girl, robot, and nerd so I can put them in the list without having to remember what actual values I used. I've also declared edge, which will come in handly later.


when print
.make message string
.make counter number
.make card number
.set counter to 1
.repeat height
..set message to ""
..repeat width
...set card to item counter of arena
...if card=empty
....set message to join message "."
...if card=girl
....set message to join message "G"
...if card=robot
....set message to join message "R"
...if card=nerd
....set message to join message "N"
...change counter by 1
..say message

The first script I wrote was to print out the game status. We go along each of the rows, checking the square, and depending what it is we add a suitable letter to the message. When we reach the end of the line we print out the message and go around again.

The next thing I wrote was something to place a card somewhere in the grid:

make card number
when placeRandom
.make x number
.make y number
.make counter number
.forever
..set x to pick random 1 to width
..set y to pick random 1 to height
..#say join [x] join "," [y]
..set counter to (y-1)*width+x
..if item counter of arena =empty
...replace item counter of arena with card
...stop script

I generate a random x,y coordinate and then calculate the index of that square in the list. This is a bit tricky but basically each step in Y moves us down the grid one square, which moves us on by width steps through the list.

If the square us currently empty then we place the card in the square and we're done. Otherwise we go around again and try another square. With that in place its pretty trivial to fill up an entire grid with a random layout:

when fillArena
.broadcast makeEmpty and wait
.replace item 1 of arena with nerd
.repeat 4
..set card to girl
..broadcast placeRandom and wait
.repeat 4
..set card to robot
..broadcast placeRandom and wait
.repeat 3
..set card to nerd
..broadcast placeRandom and wait

Or at least almost random: As per the level above, I've placed a Nerd in the top left, then placed 4 girls, 4 robots and 3 nerds randomly. Of course I've been testing all of this as we go along using something like this:


when start
.repeat 10
..broadcast fillArena and wait
..broadcast calcScore and wait
..broadcast print and wait
..say ""

Which simply prints out 10 random card layouts.

Now for the hard part - we need to calculate a score for a card layout.

when calcScore
.make counter number
.make x number
.make y number
.set score to 0
.set counter to 1
.repeat height using y
..repeat width using x
...set card to item counter of arena
...
...if x>1
....set neighbour to item counter-1 of arena
...else
....set neighbour to edge
...broadcast calcCompatability and wait
...
...if x<width
....set neighbour to item counter+1 of arena
...else
....set neighbour to edge
...broadcast calcCompatability and wait
...
...if y>1
....set neighbour to item counter-width of arena
...else
....set neighbour to edge
...broadcast calcCompatability and wait
...
...if y<height
....set neighbour to item counter+width of arena
...else
....set neighbour to edge
...broadcast calcCompatability and wait
...
...change counter by 1

So to do that we go through the grid one square at a time, and calculate its happiness score. First we get the card thats in the square itself (item counter of arena). Then we check each of its neighbours starting with its left hand neighbour at counter-1.  If course that won't work if we're on the left hand edge (x=1), so we check that x>1 and if its not we set the neighbour to be an edge (in other games we might be able to use empty, but remember Nerds like being on an edge). 

Having set card and neighbour we then call calcCompatablity to actually work out that pairings contribution.

when calcCompatability
.if card=girl
..if neighbour=robot
...change score by 1
..if neighbour=nerd
...change score by -1
.
.if card=robot
..if neighbour=girl
...change score by 1
.
.if card=nerd
..if neighbour=girl
...change score by 1
..if neighbour=robot
...change score by 1
..if neighbour=edge
...change score by 1
..if neighbour=nerd
...change score by -1

This is where the "game logic" really lives. Here you can specifically see that girls like robots and don't like Nerds. As you can see Nerds are by far the most complex, as they have a reaction to pretty much every other card.

Finally all we have to do is generate lots of random layouts and see which is best:

make hiScore number
when start
.repeat 10000
..broadcast fillArena and wait
..broadcast calcScore and wait
..if score>hiScore
...set hiScore to score
...say [score]
...broadcast print and wait
...say ""

And when we do something strange happens... it suggests the solution:
NRNG
RGRG
NRGN
Which it thinks will score 27 points on a level where the "perfect" score is 26... 
And there it is!!! 27 points!!!

In later levels we get to add in new cards - Pies (pie makes every one happy, except robots) and baby seals (everyone loves baby seals, but they hate girls), fish and cows. There's also the rule that robots can get too excited and panic if they're surrounded by 4 girls. Some of these are a bit more tricky to implement as they don't just apply to a single pair of cards, but with the framework in place its fairly simple to add these extra features.

Check out the Humble Bundle, and Girls Like Robots. They're almost as much fun as writing the solution!

Friday, 13 January 2017

Round and Round (rotary encoder)

Pots are fun, but they have two limitations - firstly they have a position, which is great feedback, but if it gets out of sync with the "real" value because you've changed it for some other reason then you need a motorised pot (as we saw list time) to get it back to the correct position. The second issue is that they have limited travel - when you reach the end, then you can't go any further.

Both of these are easily fixed using a rotary encoder (which also have the advantage of being digital, so you don't need an analog input, so on a Pi they're ideal).



Our encoder has 5 pins: Gnd and +ve are obvious. SW refers to an inbuilt switch, you can press down separately from the actual rotation. The other two are clk and dt, which are the interesting ones.

make dt digital input D5
make clk digital input D6

when start
.forever
..wait until clk
..say [clk]
..wait until not clk
..say [clk]

Clock will go from high to low and back repeatedly as you turn the shaft, so to get started we wait for it to change.

when start
.forever
..wait until clk
..wait until not clk
..say [dt]

The next thing to do is to check "dt" - direction of turn. Here I've set the code up to check dt whenever the clock goes low and we conveniently find that it is true when we turn clockwise and false when we turn anticlockwise.

All that's left is to add something to keep track of the number of times we turn in each direction:

make counter number
when start
.forever
..wait until clk
..wait until not clk
..if dt
...change counter by 1
..else
...change counter by -1
..say [counter]

This works perfectly well but we can do a little better. For the encoder I got we get 15 clocks per full turn, but we can look a little closer, and get 30 half clocks by checking dt when clock goes high as well as when it goes low. When we check this we see that when we check dt at this point in the cycle it has the opposite value - its low when we go clockwise, and high anti-clockwise. Adding this in doubles the resolution of our encoder:

make counter number
when start
.forever
..wait until clk
..if not dt
...change counter by 1
..else
...change counter by -1
..say [counter]
..wait until not clk
..if dt
...change counter by 1
..else
...change counter by -1
..say [counter]

This works really well and reliably, with one gotcha. It assumes that we're actually running this code regularly. If we go off and run another script at the same time we might miss a clock change. We will spot it eventually, but by that time DT may have changed to an incorrect value - its important to check DT immedialtly the clock changes. If you're running a lot of other code at the same time, then you may need to switch back to the other version which is a little more reliable.

Friday, 2 December 2016

Motorised Pot

I've been looking at a lot of smart home stuff recently and having fun with things like the Philips Hue and cheer lights. Ironically one of the best features of Hue is its light switch! It shouldn't come as much as a surprise that the best way to turn lights on and off is with a switch! Taking your phone out of your pocket is way too clunky. Even using Siri on Apple Watch you need to press the button and say "turn on the lights", when you could just press a button in the first place!

That's not to say Hue isn't really great - it is really great (and addictive and expensive!), but the best bits are having lights turn off automatically in rooms you're not using, being able to dim them exactly as you want, and turning on and off lamps from the switch by the door. Seriously that lamp in the far corner will see a lot more use when you don't have to turn on the main lights, walk across the room, turn it on, walk back then turn off the main light, then walk back and sit down! (then repeat when its time to leave).

Most of the cool tricks involve being able to control the lights in more flexible ways in addition to just a basic switch (and the ability to place that switch anywhere).

We've already implemented Hue support in Sniff so you can use and Arduino or PC as part of that control mechanism. Specifically I wanted to be able to use a Pot connected to an Arduino to dim lights. While an up/button works OK, the good old fashioned dial is something that's sorely missing from our modern lives. It would be really easy to have a pot connected to an Arduino, control the brightness of a Hue light, but with physical controls there's a big catch - turning the dial can easily dim the lights, but what happens when I dim the lights on my phone? Now the dial is out of sync with the lights...

What we need is a motorised pot - which is exactly what it sounds like: a Pot with a motor attached. These can be quite expensive, but I found a cheap source on eBay and picked one up for about £3.

Conceptually they couldn't be easier - the pot at the front can be driven by the motor at the back. The only tricky part was figuring out the pins, as for some reason there are 8 pins on the pot instead of the usual 3. With a bit of googling and poking around with a multi-meter, I found the connections I've penciled on in the picture:
  • Pin 2: V+
  • Pin 6: 0V
  • Pin 7: Signal

Signal just connects to any analog in, and we can read the position of the pot.

make dial analog input A0

when start
.forever
..say [dial]
..wait 1 secs



Hooking up the motor is simple but requires a motor driver. I could have used a motor shield, but I had some stand alone boards around. We don't need much power, so I just powered the motor board from the 5V of the Arduino. Connect the motor wires to the outputs of the board, and then connect two wires from Arduino digital pins to the control pins of the motor board.

Coding this is simple but quite fun:

make dial analog input A0
make motorCW digital output D2
make motorCCW digital output D3

make targetDial number

Here I've set up the pins, and created a variable targetDial. The only thing to watch is that the motor pins are the correct way around, and CW does turn the pot clockwise and CCW counter-clockwise (and similarly that turning CW increases the value of dial). Now we need to just change dial until it matches targetDial:

when adjustDial
.repeat until abs of (dial-targetDial)<0.01
..set motorCW to targetDial>dial
..set motorCCW to targetDial<dial
.set motorCW to no
.set motorCCW to no

We've made a loop, and we keep going round the loop until the difference between the desired and actual values are less than 0.01. We use abs because we don't care if the difference is positive or negative.

The contents of the loop might look a bit odd, but its really pretty simple. When ever we use a greater than (or less than) its actually testing something to see if its true or false, so the answer to the question "is targetDial>dial" is either a yes or a no. So if targetDial is bigger than the actual position (dial) then we set motorCW to yes, and the motor turns clockwise. If it isn't then motorCW becomes no, but motorCCW probably becomes less and we turn the pot CCW.

This will keep adjusting the dial until it reaches the target position. The neat thing is that if it overshoots, then it will adjust back the other way automatically, until its in exactly the right position and the loop exits. Then we turn the motor off, and we're done.

when start
.forever
..say ""
..say join "Current Val:" [dial]
..set targetDial to ( pick random 0 to 10 ) *0.1
..say join "Target Val:" [targetDial]
..broadcast adjustDial and wait
..say [dial]
..wait 5 secs

To test the adjustDial script I wrote the start script above. It picks a random value between 0 and 1, and adjusts the dial to that position. It then waits 5 seconds (during which you can turn the dial manually) before starting over again.

The next step would be to read values from the Hue system, and move the pot appropriately, and when the pot is turned, push values form the pot back to Hue. There are some updates in the next release to make that all very easy, so I'll cover that another time, but in the mean time consider what else needs a nice rotary control...

Wednesday, 23 November 2016

Sniff Documentation-fest

Lets be honest... no one likes writing documentation, and the Sniff docs haven't been the best. It's just more fun writing code than writing it up. We'd claim that all the information you need it there, either here on the blog, or in the examples folder but as the blog has got bigger (great - more resources and ideas!) its increasingly harder to find older posts. I'll admit I've googled my own posts to try and find instructions for a project I developed months ago.

While the examples folder is still the goto-place for code to get you started, the last few weeks have been spent trying to put together something more tangible, so you've a solid base of reference material you can work from. 

In fact we've always had a manual... you did read the manual right? Most of it was written way back when Sniff was very new. It's in the Sniff/docs folder when you download Sniff. We've now given it a bit of an overhaul, adding a few extra chapters to the tutorial section, updating the reference section, and adding an index of blocks, so you can look up "blocks" in alphabetical order. While the updated version will still be in the docs folder for download the pdf of the latest version is in the new online docs folder.

In addition we've updated the Device docs. "Devices" are external code to talk to specific hardware, so there are quite a lot of these (currently 145, though some of those are interdependent), and keeping track of how to use each device can be quite hard. Again there were some docs for a couple of the Devices: Filesystem and Sprite, as these are two of the more complex Devices with many commands, but now we've added documents for some of the simpler devices on the basis that these are the ones you'll encounter first, and need the most help with. They should be suitable for printing out, and keeping a few copies around when you're working with a particular device.

For each documented device, there's a page on the hardware (of appropriate), a page defining the Variables used, and then a list of all the commands that the device recognise. For each method, the variables that it uses as parameters are shown in a table, with a brief statement on their meaning. Finally there's an example.

We're still refining the format and the documentation only exists for a small subset of the available devices, but hopefully by establishing a standard format for documenting devices, we can do better in future (and at least document new devices better).

Currently there are documents for DHT11/DHT22, DS18b20, text LCD's, the Motor Controller shield, NeoPixels, IR Receiver for use with Arduino, and for Hosted systems there's Filesystem, Sprites, Flotilla and Window. There's also a generic DisplayDevices which applies to all bitmapped screens.

You can get The Docs online now, and we'll be including them as PDF's in future distributions of Sniff. The Sniff distribution will also include the LaTeX source for the main manual, and Pages files for the Devices so you can edit them (If you're PC based, then you can still edit pages on iCloud).

Sunday, 6 November 2016

Simple Reation Timer

Yesterday I ran the first of a series of workshops, making fun stuff with Sniff on Arduino. We started with an Arduino and an LED, then added a button and a potentiometer (dial). That neatly covers inputs and outputs, both digital and analog, so we can declare all that hardware with something like:

make led1 digital output D13
make led2 analog output D9
make button digital input D4
make dial analog input A0

Then we can use the button to control the "digital led"

when start
.forever
..set led1 to not button

use the potentiometer  to control the brightness of the analog led:

when start
.forever
..set led2 to dial

or we can use the dial to set the speed of a flash:

when start
.forever
..set led1 to on
..wait dial secs
..set led1 to off
..wait dial secs

we can even make the button control a flashing LED

when start
.forever
..if not button
...set led1 to on
...wait dial secs
...set led1 to off
...wait dial secs

The idea was then that we could build something fun or useful using the components. The code for a simple ration timer is:

when start
.forever
..set led to off
..wait pick random 1 to 5 secs
..set led1 to on
..reset timer
..wait until not button
..say [timer]

You can extend this a little to prevent cheating by checking that the button isn't pressed before the LED comes on:

when start
.forever
..set led to off
..wait pick random 1 to 5 secs
..if not button
...say "Cheater!"
..else
...set led1 to on
...reset timer
...wait until not button
...say [timer]

Hopefully everyone had a fun time with this, and I've got some ideas for a Xmas/Winter project next month...

Friday, 4 November 2016

Flotilla and MQTT

I've not played with the Flotilla for a few months, but when I was playing with MQTT last month, I kept thinking that I should integrate the flotilla Weather sensor into the MQTT network that we built.

Previously I used and Arduino with a temperature sensor, pushed the data to MQTT, processed the data in Node-Red and finally pushed a message back through MQTT to an LCD screen. You'll need MQTT and Node-Red servers running already, along with the Node-Red flow I built in the last post.

Rewriting it for the Flotilla is mainly a case of changing a few declarations:

make mqtt device
make networkPeer string
make networkConnected boolean
make clientid string

make message string
make topic string
make retain boolean


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


We don't need an ethernet device,  as the MQTT device doesn't need to drive the hardware directly. And I've just replaced the DHT11 with a flotilla dock and weather sensor.

when start
.set clientid to "flotillaSensor"
.set networkPeer to "raspberrypi.local." 
.
.repeat until networkConnected
..tell mqtt to "connect"
.
.say "connected"
.
.broadcast measureStuff
.
.set topic to "text"
.tell mqtt to "subscribe"
.set topic to "office/text"
.tell mqtt to "subscribe"
.forever
..tell mqtt to "loop"
..if not message = ""
...say message

There are a few minor tweaks to change the name of the client, and specific that the MQTT server is on raspberrypi.local before we subscribe to the text topics  Currently there's no text based screen for the flotilla (an i2c 16x2 LCD would be nice...) so when we get the message we just print it on the terminal with "say".

when measureStuff
.forever
..tell sensor to "update"
..
..set retain to yes
..set topic to "office/temperature"
..set message to [temperature]
..tell mqtt to "publish"
..
..set retain to yes
..set topic to "office/pressure"
..set message to [pressure]
..tell mqtt to "publish"
..
..wait 10 secs

The script to do the measuring is essentially the same too, though now we're recording temperature and pressure, rather than temp and humidity.

And that's it! Neat huh? Lots of scope for fun... Have one set of sensors running, and let everyone tap into them, or place sensors all over the place and collect data from them. Have one group of kids responsible for posting data, and other for displaying it - on the same or separate computers.