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.

Saturday, 28 November 2015

Flappy Bird

Earlier in the week @Dr Hannah posted on twitter looking for a project for a Yr6 class. Last year she'd done the TechWillSaveUs DIY Gamer Kit, and found it hard work... To be honest I think if she could get a group of primary school kids through this at all, then they're some smart kids and they've been taught well, as the project is massively ambitious for this age group.

However looking at the kit I wondered if we could do something better in Sniff. For a start the kit is £65. While that includes some nice things like pre-cut plastic sheets to produce something pretty sweet looking, I think we could get the same functionality for about £10.

  • Arduino Uno (clone): £5
  • LED Matrix display £2
  • Buttons: £1
  • Buzzer: £0.50
  • Battery Clip: £0.50
  • IR Receiver: £0.50
  • IR Transmitter: £0.20
  • LDR: £0.10


To that we would need to add some kind of case - if you've got access to a laser cutter then you could make something really cool for a couple of pounds. Alternatively get creative and cut up some ice cream tubs. We'd also need some way of assembling the electronics. If its a permanent build you could solder it to a piece of breadboard (50p), and I'd look at using an Arduino Nano which is more suited to permanent builds than the Uno (and cheaper, but otherwise identical). For a "lego" build were I'll probably tear it apart and build something else tomorrow I'd use sensor shield (V4 - about £2).

Of course it's nice to have it all picked up with a case, but its up to you if that's worth the £55 difference.

However things really fall down when you start programming the thing in C++... This is advertised as ages 12+. OK, I'm sure you're going to tell me how you were toggling bits of raw machine code into a  Pdp11 at the age of seven, but lets be realistic... C++ is not a nice language (and I say that as a long experienced C programmer, who's payed the bills using C++ for at least some of the last 25 years).

One of the examples is a Flappy Bird tutorial, which begins "open the completed Flappy Bird" code. Continues with "change some constants", and ends with "look at the code". In C++ that's about the limit of what we can do, but lets try writing flappy bird in Sniff for Arduino.

Lets start with the hardware. We need a 8x8 LED Matrix. You can by these separately but you can get a board with a max7912 driver chip on it which makes everything nice and easy to hook up. In addition to the power (5v) you need to connect Clock to D13, Data to D11, and CS to D10 on the Arduino. We're also going to need a button. We could get some cheap/pcb mount button for a few pennies, but you can get real arcade machine buttons/switches for about £2, and as we only need 1, lets splash out (we're not going to need any of the other stuff so out build is still going to be under £10).




To wire them up connect 5V to the NO terminal, 0V to NC terminal and connect COM to D3 on the Arduino. If you get one that lights up it will have additional terminals on each side - connect 5V across these!

Now to the code. Lets start by defining all of that hardware:
make spi device
make display maxMatrix device D10
make displayX number
make displayY number
make displayColor number
make displayFlush boolean
make message string

make button digital input D3

We create an SPI bus, which is used by the maxMatrix device which we're calling "display". Then we set up the variables that we're going to use to talk to the display. Finally place the button on D3.

Now to the game code. Lets start by thinking about the variables in the game: 

make wallX number
make wallY number

make birdX number
make birdY number
make birdVy number

make gameOver boolean


The wall is going to move form right to left, so has an X position, and a Y height. The bird as an X position, and a Y position. It also has a Y velocity - how fast its falling! Finally gameOver is YES if you're dead, and NO of there's a game in progress... We'll see how we need this in a while.

We could start looking at the rest of the code from the beginning, but just like telling a story, that's not always the best place to start, so lets look at the core mechanic first:

when moveBird
.repeat until gameOver
..change birdVy by -0.005
..change birdY by birdVy
..if birdY<0.5
...set gameOver to yes
..wait 0.01 secs


The Bird has a velocity, and each time round this loop that velocity becomes more negative - this is GRAVITY. If you throw a ball up it slows down, until it stops, then it starts coming  back down. At each instant gravity is taking away some of its upward speed (even when its already moving down!). Here we take away 0.005 from the birds velocity. Similarly each time the bird moves by its velocity. We wait 1/100th of a second and do it again.  This is also a good place to check if the bird has hit the ground, in which case it's gameOver.

The next step is to make the bird flap:

when checkButton
.repeat until gameOver
..wait until  button
..set birdVy to 0.15
..wait until not button

Again we're going to keep doing this until the game ends. We wait until the button is pressed, and set the birds velocity to be 0.15 - its moving UP! You could experiment here - what if a flap changes the velocity, so if you're already falling, then it might just slow you down? We need to wait until we stop pressing the button, so we only get one flap per press.

Thats' the bird done, so now the wall:

when moveWall
.repeat until gameOver
..wait 0.2 secs
..change wallX by -1
..if wallX=0
...set wallX to pick random 8 to 10
...set wallY to pick random 1 to 4
..
..if wallX=birdX
...if birdY<wallY+0.5 or birdY>wallY+3.5
....set gameOver to yes

Each time around we move the wall left one step. If it reaches 0 then its offscreen, so make a new wall on the right. If the bird and the wall are in the same column, then  check that the bird's Y position is in the gap, otherwise its gameOver again.


The only real work left to do is draw everything:

when drawScreen
.set displayFlush to no
.repeat until gameOver
..set displayColor to 0
..tell display to "clear"
..
..set displayColor to 1
..set displayX to wallX
..set displayY to 1
..tell display to "move"
..set displayY to wallY
..tell display to "draw"
..change displayY by 4
..tell display to "move"
..set displayY to 8
..tell display to "draw"
..
..set displayX to 1
..set displayY to 1
..tell display to "move"
..set displayX to 8
..tell display to "draw"
..
..set displayX to birdX
..set displayY to birdY
..tell display to "set pixel"
..tell display to "flush"
..wait 0.05 secs

Setting displayFlush to be NO lets us draw the whole screen before making it visible, which looks nicer for games. Clear the screen to black, then draw the wall, draw the ground and finally draw the bird before flushing the whole thing out to the display.

So we just set everything in motion:

when start
.forever
..wait until button
..wait 0.1 secs
..
..set wallX to 9
..set wallY to 4
..set birdY to 3
..set birdY to 5
..set birdVy to 0.1
..set gameOver to no
..
..broadcast drawScreen
..broadcast moveBird
..broadcast moveWall
..broadcast checkButton
..
..wait until gameOver
..wait 0.5 secs
..set displayColor to -
..tell display to "clear"
..tell display to "flush"

We wait for the button to be pressed, set the initial positions of everything, and then kick off the 4 scripts we've already written. All we have to do now is wait for the player to kill themselves (10 seconds tops!), clear the screen and then go round again.



The Sniff version doesn't do as much as the C++ version, which keeps score and makes sounds but its about half the length (about 100 lines Vs over 200), and adding those things in is something that older kids should be able to do, and the whole thing should be pretty readable and manageable to kids at a KS3 level.

Unfortunately as stands the Sniff version of Flappy Bird won't run on a real TWSU Gamer Kit, as they use different kind of display, but if someone wants to send me one it would be simple to write a new display device for it, so you'd simply replace the maxMatrix line with twsuMatrix. Until then you'll have to build your own...

Wednesday, 25 November 2015

The generation of random numbers is too important to be left to chance.

The title of the post is taken from the title of 1970 paper by mathematician Robert Covey. I picked it up from Per Christensen who used it during a short presentation he gave at BAFTA last year. Why was someone talking about theoretical mathematics at BAFTA? Probably the same reason Per has an academy award - he knows lots about computer graphics, and works for Pixar writing code and doing maths. He was talking about a cool new way they'd developed for generating sequences of numbers that appeared random. Most of the people there thought what he was showing us sounded a lot more exciting that Finding Dorey...

Random numbers are VERY important if you want to make a CG movie. So important that Pixar even have a patent on it! However its not just CG that uses random numbers. They're needed for all sorts of things. We often run code multiple times to explore a problem space, but we need it to be different each time. Maybe we want a game to be a little different each time we play. Whenever we use computers to simulate things we need to create simulations which aren't "perfect", and we need them to be slightly different each time. For example I once saw a student writing a physics engine place a stack of sphere's on top of each other... when he ran the sim they balanced perfectly! 

Middle Squares

One of the simplest ways of generating random numbers is with the "middle square" method:
make x number
make s string
make mid string


when start
.set x to 42
.repeat 20
..set s to [x*x]
..repeat until length of s =4
...set s to join "0" s
..
..set mid to ""
..set mid to join mid letter 2 of s
..set mid to join mid letter 3 of s
..set x to value of mid
..
..say [x]


Here we start with a 2 digit number and square it. That gives us (in general) a 4 digit number, but just in case it doesn't we pad it to 4 digits with leading zeros. Then we use the middle two digits of our number as our next random number.

So here we've started with 42. 42 squared is 1764, so out next number is 76 which squared is 5776, so our next number is 77, which we then square and so on... This is a great way to introduce the idea of random number generation by doing it with pencil and paper. 

Unfortunately it doesn't work so well... Most seriously if you ever end up with a number less than 10 you're pretty much doomed, as the result will always be less than 10. Depending on the number you start with you'll probably end up with a value of 0, which means from then on you're going nowhere.

It's particulary bad with this code, as we've limited it to 2 digits. It should be pretty obvious that means we've only got 100 possible values, and we're (at best) going to end up back where we started from pretty quickly - in fact this happens with all generators of all types, but we can at least delay the problem as long as possible. With 4 digit numbers we'd get 8 digit squares, and it works a lot better, and if we were implementing this is C or another low level language we could do it in binary pretty effectively, but its still a pretty poor method.


Linear congruential generator

A better method is the Linear Congruential Generator (LCG). This just uses the simple equation to generate a sequence:



The trick is to pick "good" values of a,c and m. If we were doing this for "real" m would typically be 2 to the power of 32, as its really easy for computers to just throw away the top bits of a number and do the modulus that way. However to get a "good" sequence we need to ensure certain properties of a,c and m with can most easily me achieved by making m prime.

when start
.set m to 211
.set a to 3
.set c to 7
.set x to 1
.repeat 480
..set x to (a*x+c) mod m
..say [x]

Running this produces the sequence:
10
37
118
150
35
112
132
192
161
68
0
7
 and so on... Interestingly we've already had a 0, and it keeps going, so it looks promising.


I wrote another Sniff program to plot the random numbers in a window. The x coordinate is the generated number, and the y axis is time through the sequence. This looks pretty good. There are some gaps and some clusters, but actually that's something we'd expect from random numbers - if they don't cluster they're not random!

In fact you probably noticed this before: if you put your music on random play after a while you realise it just played three songs by the same band in a row... that's odd! But its not! Say you've got songs, by 10 different bands. It doesn't matter  what the first one is, what's the chances that the second one is by the same band? 0.1 - two in a row is pretty likely. Three in a row is 0.01 - there's a 1 in a hundred chance that three songs that get played will all be by the same band. That's not so likely, but if you listen to 20 songs, then that's a 1 in 5 chance of getting 3 in a row (actually its slightly more complex than that, but it'll do for now!). Except its not just "same band" that you could have noticed - songs released in a particular year, CD's with red covers, songs with the word "Night" in them (actually that's pretty much all of them - really go check!). We spot patterns, and there are lots of potential patterns so its inevitable that we're going to get some form of clustering. That's why mp3 players don't actually do random play (and why Per was talking about a clever way of introducing randomness that wasn't really random).

So far so good and infact LRG's have been used for real work. However they have a severe problem:


Here rather than just plotting individual values we've plotted consecutive values as x/y coordinates... THAT IS BAD!!! If we were generating 2D coordinates then we'd totally fail. The original rand() function had similar problems, and in fact if you type "man 3 rand" on a Mac you get the manual page:


RAND(3)                  BSD Library Functions Manual                  RAND(3)

NAME
     rand, rand_r, srand, sranddev -- bad random number generator

LIBRARY
     Standard C Library (libc, -lc)

SYNOPSIS
     #include <stdlib.h>

     int
     rand(void);



That's right. The MANUAL says its bad. It's been superseded by random() which is MUCH MUCH better.

We can improve things by picking better values for a,c and m but we can't fix this problem. Lets try something else instead.

Blum Blum Shub

Yeah - its a silly name, but its a better random number generator. Pick two prime numbers, then multiply them together to get m. Then use:


That does look familiar... two prime numbers... multiply.... power... modulus... That's RSA, as in public key encryption! Yes the maths is very much the same - one of the purposes of encryption is to destroy patterns in the text you're trying to hide, so that the encrypted sequence looks like random numbers.

when start
.set x to 3
.
.#p and q should be one less than a multiple of 4.
.#set p to 11
.#set q to 19
.
.set p to 47
.set q to 67
.
.set m to p*q
.
.repeat 480
..set x to (x*x) mod m
..say [x mod 256]!

I've used two different  sets of values for  p and q here. While any prime values would sort of work, it comes out better if p and q are both 1 less than a multiple of 4, so 11, 19, 23 are good values, while 13 despite being prime doesn't work so well.

Strictly we shouldn't try and get too much out of each number in the sequence, so serious systems might only use 1 bit from each number (is it odd or even), but here I'm using mod 256. This throws away some of the data, but keeps probably more than we should - but close enough for a quick test.

Plotting the values against time, looks pretty good. It's pretty obvious that the sequence repeats - just as our previous ones did, but using bigger numbers would fix that.


The small amount of numbers in the sequence  really shows up where where we plot them in pairs, but more importantly there are no obvious correlations, so this is looking a lot better.

If we picked some larger values for p and q we could turn this into a workable system.

There are other methods, some of which are easy to implement in  hardware (which might be important if you need LOTS), which others are more complex and less predictable. 

However all of these methods have one HUGE problem: THEY'RE NOT RANDOM!

Every time you run the code you get the same output. That's fine (and in fact useful), but any computer program given the same inputs will produce the same outputs. If we want to get a different sequence each time then we would either need to change to code each time, or use different parameters for the algorithm (a,c,m X0 etc). But how could  we change them each time - however we calculate them the would calculate it the same each time!!!

We need some "true" randomness to "seed" these values, but for that we need to look outside the computer... And I guess that's other post!

Friday, 20 November 2015

433MHz Remote Control

A lot of Arduino projects that we've done have been about measuring, and sensing the world. That's fun, but that's only half of the potential... We also want to be able to control things. When we put those two parts together things get really exciting.

The main problem of controlling things - particularly high power electrical things is doing it safely. in the past I've done it using a DMX Dimmer pack. I was lucky enough to already have access to plenty of DMX equipment, and using a dimmer pack allows easy control over 4 mains sockets, including (as the name suggests) the ability to dim lights connected to them. Unfortunately a cheap dimmer pack costs about £70, plus you'll need a DMX interface, and cabling on top of that. While its not impossibly expensive it isn't the "pocket money prices" that allow you to throw together a system just to play with it.


However Alastair has been asking me for a while to add support for 433MHz RC remote controls. He pointed out that you could get these plugs for about £5 each, and you can buy the transmitter and receiver as a set for under £2. You'll also need a "real" remote to get started, but you can be up and running for about £10. As there's not physical connection to the mains equipment there's no electrical "risk assessment" issues (though you absolutely shouldn't connect anything to these plugs that you wouldn't be happy to leave running, unattended 24/7 - always consider what would happen if the equipment was turned on unexpectedly, or when you're not there!).

Well I finally got round to getting them running and they're a lot of fun!


There are various versions of these plugs which means that you'll need to do some figuring out and testing to get things working. Some plugs have switches to set a unique number for each plug, while the ones I got are programmable. It can be a bit hit and miss figuring out how a particular device works, bit once you've got the encoding you're good to go!

Start by setting up your plug so it works as its supposed to - its always a good idea to start by following the instructions and get everything working before you start making "improvements".

Decoding Messages

Next we need to plug the receiver (the rectangular board) into an Arduino. Most of the documentation suggests that these can be plugged into a 5V digital input and used to drive an interrupt...  I tried this... it didn't work very well... If you've got an arduino Due (which is 3.3v) then this works, but I could never get the receiver to work reliably when powered by 5V, and at 3.3v the output never exceeded 2.5V. The output pins (there are two - they're wired together, so use either) are analog and represent the signal strength (I think!). They're not going reliably to generate a logic high on a 5V Arduino.

Instead we're going to have to connect the data in to an Analog pin... This works OK, but its slow and means we can't use use efficient interrupt driven version of the code that I first wrote (and couldn't get working!!).

make rc analog input A0
make hi number
make lo number

when start
.make startTime number
.set hi to 0.4
.set lo to 0.1
.forever
..wait until rc>hi
..set startTime to fasttimer
..wait until rc<lo
..wait until rc>hi
..say [(fasttimer-startTime)*1000000]
..
..#We've wasted too much time printing out the duration, so skip next pulse
..wait until rc<lo

These transmitters work by sending a sequence of pulses. Sometimes they send a long pulse followed by a short gap, or sometimes they send a short pulse followed by a long gap... The first part of their trick is that the pulse plus the gap alway take the same amount of time. Or to look at it another way the time between the start of consecutive pulses is always the same. We need to find the time between consecutive pulses.

Here we wait until the pin is greater than 0.4 (2Volts) and then measure the time until the pin goes low and then high again. We do some printing, and then make sure the pin is low before going round again.

If you run this you'll see a lot of random times printed as the receiver searches for a signal. However once you press a button on the remote you should see it lock in pretty quickly, and print out some consistent results. For my transmitter I got a time of about 1200 microSeconds(uS) between pulses. Mixed in with these was a larger value of about 9000uS. This it the "break period" - when the button on the remote is held down it sends the same message over and over with a gap between it. You'll see quite a bit of variation in both these values, but they're not critical so pick something representative.

This is all the information we need to start decoding messages. There are minor variations on the way the data can be encoded, but basically a 0 is a short pulse/long gap while a 1 is long pulse/short gap... The trick is that start of the pulse is the beginning of a bit, and half way through the 1200uS bit period if we read the input we can find the value of the bit. We don't have to worry about pulse durations - just look for the start of a bit, wait half a 600uS and read in the value!

make rc analog input A0

make code string

make codeAvailable boolean
when start
.forever
..if codeAvailable
...say code
...set codeAvailable to no
..wait 0.1 secs


Lets start with the boring/housekeeping bits... We don't want to be printing things out in the main code as this would mess the timing (more!), so we write a script to print out the code whenever its available. Now for the good bits:

when start
.make gotPartial boolean
.make startTime number
.make r string
.forever
..set startTime to fasttimer
..repeat until rc>0.3
...if gotPartial and  fasttimer-startTime >0.005 #break time goes here
....if length of r >8
.....set code to r
.....set codeAvailable to yes
....set r to ""
....set gotPartial to no
..wait 500 microsecs
..if rc>0.3
...set r to join r "1"
..else
...set r to join r "0"
..set gotPartial to yes
..wait until rc<0.1

This is a bit tricky, but basically waits for rc to go high. If this takes longer than 0.005 seconds then that's longer than the 1200uS we're expecting, so we must be between messages. If we've found something so far we make it available to the previous script.

If rc does go high then we wait half a bit period, and then check rc again  - if its high we add 1 to the end of the message, otherwise we add 0. However there's a gotcha... Rc is an analog input, which means the Arduino needs to measure the input voltage which takes time - up to 100uS. We should be taking this reading after 600uS (half of the 1200uS I measured earlier), but we could be up to 100uS late getting to the wait. Similar even if the measurement of starts after 600uS, it wouldn't finish till 700, which is to late.

Using 600uS started to produce some results but they were unreliable. If we want the measurement to represent 600uS we should start it after a 550uS delay so it runs from 550 to 650. On average the wait will start 50uS late, so we use an actual delay of 500uS (bitPeriod/2 -100).

With this we should now start seeing the data values being sent from the controller. In my case my plug is responding to two keys:

On:1010111111000000111011110
Off:1010111111000000111011100


You should note that the code ALWAYS ends in 0. This is a stop bit, and its part of the structure of the system, rather than actual data.

If you're working with kids then you probably want to do most of previous prep work yourself, and give them examples that are set up to actually work. Getting this far can be a bit frustrating - or at least it was for me. From here it gets a LOT easier.

Controlling Stuff

Setting up the transmitter is much easier, as there's and rcSwitch device which does the work, and the Transmitter works when plugged into a standard digital output. Here its connected to pin 5.

make rcSwitch transmit433 device 5

make rcPayload string
make rcBitPeriod number
make rcBreakPeriod number


when start
.set rcBitPeriod to 1200
.set rcBreakPeriod to 9000
.
.forever
..set rcPayload to "101011111100000011101111"
..repeat 10
...tell rcSwitch to "send"
..wait 3 secs
..
..set rcPayload to "101011111100000011101110"
..repeat 10
...tell rcSwitch to "send"
..wait 3 secs

To control our plug we set the bit period and break period to the values we previously measured, then set the payload to be the message we decoded from the remote handset. Do not include  the final 0 stop bit, as this gets added automatically. Typically to make sure the message gets through we send it a few times in rapid succession. In this case 10 times. This code sends the "turn on" button, waits 3 seconds and then sends the turn off button.

when start
.set rcBitPeriod to 750
.set rcBreakPeriod to 1500
.
.forever
..set rcPayload to "0101101010100101"
..repeat 10
...tell rcSwitch to "send"
..wait 3 secs
..
..set rcPayload to "1010010101011010"
..repeat 10
...tell rcSwitch to "send"
..wait 3 secs

The 1200uS bit period is very common but other timings are also used. Recording the messages from a different remote device we found it had a bit period of 750uS and a break period of 1500uS. The payload format was also very different.

Wrap up!

And that's all there is to it! Getting the parameters for your system is a bit tricky, but once you've got those its not to painful to record the messages, and playing them back is really easy. You could write something to check the time from a real time clock and turn the lights on in the evening. You could measure the temperature and humidity and turn a fan on if it gets too hot. When you're ready to get fancy you could program "scenes", where pressing a button dims the lights and turns on the TV at the same time!

In addition to simple remotes/plugs there are a whole range of cheap devices operating on this frequency range - motion sensors, alarms, smoke detectors etc. Go have some fun!


In the released code there's a folder of example code which includes a receiveRC device. However the receive examples all require that the receiver is capable of driving a digital input. For these to work you'll need to either run them on a 3.3V CPU,  or add a level shifting/ buffering circuit. The examples here will work fine on a 5V CPU (Arduino Uno) but the receive code is really only suitable for testing and diagnostic work rather than as a remote.

Wednesday, 18 November 2015

Playing Sounds

One of the features in the recent release is support for playing sound files. We've actually had a "sound" device (on Hosted platforms) for some time, but so far it only actually worked with js-sniff, where the compiled code runs in a browser. This meant you could write games in Sniff and have sound when you embed them in a web page, but the sounds wouldn't actually play when you ran the code as a real program on your own machine!

We've fixed that, and now you can play sounds on Mac, Windows and Linux.

make player sound device
make fileData string

when start
.set fileData to "chainsaw.wav"
.tell player to "load sound"
.forever
..tell player to "play"
..wait 10 secs

The code is about as simple as it gets: we make a sound device (called player in this case), and tell the player the name of the sound file we want it to play. With that out of the way, we can just tell it to play whenever we want to hear that sound.


If you want to play multiple sounds then you can either create multiple devices, or create one device, and keep telling it to load different sounds. Use whichever approach makes most sense for your app.

Because each system handles sound file slightly differently there are minor variations in behaviour across platforms. On Mac and JS you should be able to use most types of sound files, while on windows and Linux it must be a WAV. On Windows if the file can't be loaded a default "ping" sound is played instead. The Linux version uses the external program "aplay" to actually play the sound. This is standard in most distributions. Some Linux variants give a warning that a return value is ignored when you compile the Sniff program - this is harmless, and we've fixed it in new versions so if you do see it, just ignore it.

That's about it - get out there, play some music, and add some sound effects to your Sniff games!

Tuesday, 17 November 2015

Release 23: (the not very exciting one)

Release 23 is out, and contains a bunch of fixes and a few new features.

We had some problems with the Release 22 for Windows build getting flagged by Windows Defender... In response we pulled all old versions from the downloads page, ran full virus scans on our windows machine, and rebuilt the zip files from scratch. However even though Windows reported no problems with the files, it did occasionally complain about the zip file containing those files. We're as confident as we can be that the files are clean, and we've run scans on everything in the current build and they're giving a clean bill of heath.


The most fun thing in R23 is that it lets you play back sound files. There's also support for 433MHz transmitters and receivers so you can turn stuff on and off by remote control. Finally we've got support for i2c PWM extenders, which you can use to drive up to 16 servos - we've got a big servo project coming up soon.

Check the Downloads page!