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

Wednesday, 30 September 2015

IPACA Game Jam

Last week we held a game jam event at Bournemouth University with 15 KS3 kids from IPACA (Isle of Portland Aldridge Commity Academy). We've been working up to this for a few months, rolling out various supporting code and worksheet resources, so that (we hoped!) we could teach them Sniff to the level of having some kind of working game within 2 days.

That's a big challenge, which wasn't helped by traffic on the A35 from Weymouth to Bournemouth on the first morning... so they arrived almost 2 hours late. That's a big chunk of time out of the first day! Second day was able to start a bit more promptly by we still ended up with about 9 hours to do a project we thought was ambitious in 12 hours!

Sniff's actually based in the NCCA at Bournemouth University (You may have heard of us from the NESTA NextGen Report) so we had use of one of the Linux labs there (not sure of the spec, but I believe there's around 1.6 Terabytes of RAM installed in the room!). We were able to divide everyone up into groups of 3, and give them their own work area with one machine each. While its hard (on this scale) to have more than one person working directly on code, this meant that in their teams they could have 1 person developing assets, 1 programming, and a 3rd assisting/coordinating). This worked really well.

We ran a smaller pilot session at the end of the summer term, which some of the students had attended, but most of them hadn't used Sniff before, so I kicked of the session with a 20minute crash course on Sniff. This generally goes something along the lines of getting them to run sniffpad, and then throwing a few examples at them:

when start
.say "hello"

when start
.repeat 10
..say "hello"

make count number
when start
.set count to 1
.repeat 10
..say [count]

make count number
when start
.set count to 1
.repeat 100
..if count mod 5 = 0
...say "fizz"
...say [count]

You might recognise this final example as a simplified version of fizz buzz - in fact its just fizz (which is much easier to code). Look closely and you'll see what a great example it is - sequence, iteration, selection. It's all there. It also lets me talk about indention, typing, and with a bit of tweaking you can also explain the broadcast mechanism (which even kids who claim to be "expert" at Scratch seem to have rarely used).

While I'd normally take a little longer to cover this it really doesn't take very much time to throw down some basic Sniff examples. The general reaction is "OK - I get it", can we make a game now. If you've laid the foundations in Scratch then there's no need to spend much time "teaching  Sniff" - you can move on quickly to making things, and learn the rest of Sniff indirectly.

To do that we've got a bunch of worksheets/cards that Michelle developed over the summer. Throwing them straight into sprites is a little unfair, as its quite a complex library, but their enthusiasm for coding games helps make up for that.

These contain fragments of code to do all sorts of useful things with Sprites. However they're not complete programs, and also require small modifications depending on how you want to use them. We give out a basic framework which contains all the generic boiler plate where all the devices are made, and then kids can work through the cards to implement all the basic features they'll need in a game. Though there's a general "order" to the cards (they're numbered!) you don't need to cover them all sequentially, so you can hold back certain bits of code until they're needed.

It took an hour or two for everyone to more or less get through these and produce some kind of crazy moving object that they could control with the keyboard.

Sandwiches and crisps were provided by the CDE (Centre for Digital Entertainment - thanks Dan!), and as we were running late, Phil Wilkinson (a DEng student attached to the CDE/Bournemouth and IPACA) asked everyone to discuss what sort of game they might like to make for the rest of the workshop over lunch. Phil is interested in how getting kids to make games can be used to explore social issues with chi. For this sessions we wanted something fairly lightweight, so he decided "to teach something relevantsomething modern. The Internet!" [those of you over the age of 16 who don't see why that's funny, are welcome to google it. It may be NSFW depending on where you work!].

So we asked them to build a game around the theme of the internet. The idea was that it was open enough that they could make more or less anything, but there was at least a jumping off point for discussion. 

After lunch I introduced sniff paint, which proved very effective, and we immediately started getting some great artwork.

Over the course of the rest of the afternoon icons started to appear, and the some sort of vague game play ideas started to be discussed.

Day 2

On the morning of day 2, Phil worked with them to turn their rough game ideas into concepts that could be realised within a few hours, while I ran around fielding technical questions. Almost all of these were really solid questions about how they could implement features of their game. As we were doing this in an intense 2 day session, there was a lot about the sprite library that we didn't have time to teach in advance. However I you learn better if you already have a need for the knowledge, and I was able to explain features on-demand. Some better reference documentation would be useful here, or if you were working at a more relaxed pace, perhaps over a number of shorter sessions, you could introduce some of these in a more structured way. At around this time as they started to get seriously into development we encountered a bug in the Sprite "load costume" code, which I had to make a quick patch to, and distribute round the lab (yes it was stressful). However apart from that the system help up pretty well to some serious testing.

One concept we'd deliberatly kept back was how to dynamically create sprites at runtime. This is a more advanced feature, but only one team needed it.

Just after lunch one of the teams accidentally deleted their code - someone clicked save when they mean to click load and saved over their program. Michelle was able to work with them to quickly rewrite most of what they'd lost, but they never quite caught up. Things like this are always going to happen, as they were under quite a lot of pressure at this stage to get everything working. Some sort of automated backup script would probably be a good idea.

At 3pm we called time on the development to allow for everyone to go around and play everyone else games. While everyone would have benefited from "a little more time", pretty much all the teams had produced a game that was to some extent playable. If we'd had another day most of them could have been refined into something that was actually finished. My main concern was that at some point they might just get stuck and not know how to progress. In fact this never came close to happening - they all knew what they wanted to do and worked hard, and asked a lot of questions to get there.

Most importantly everyone seemed to have a fun 2 days, and the teams all worked well to get something working within the time limit. They went home enthusiastic about programming, and knowing that with a bit more practise and a less crazy schedule they could actually make their own game.

Here are 4 of the 5 games which you can play online:
Virus Defence (use the mouse to block the virus)
Ad Invaders (space invaders - cursor keys)
Internet Survival (another shooter variane - cursor keys)
Oops We Deleted Everything (they didn't get finished - cursor keys)

[At the end of the session I grabbed copies of all of the code, which I used to make these. They're exactly as they were written, and I've not tidied them up, so there's still a few bugs in there. The final game I seem to have copied the wrong files, as I don't have a working version of the game, which is a shame as it looked great.]

Tuesday, 15 September 2015

E-Compasses revisited

We've had support for the hmc5883 magnetometer for some time. This measures the magnetic field strength on 3 axis, which with a little bit of trigonometry can be turned into a compass. We used this on SniffBot so that it could be instructed to face North when in idle mode. This worked brilliantly sometimes, but a few times we tried it, it just behaved very badly. We put this down to the generally messy magnetic field caused by all the metal and electronic equipment we have around here.

However we were prompted to revisit it, by the announcement of the BBC Microbit. Despite this being promised to arrive in schools in the next few weeks, no one has yet seen one... slightly worrying. However we do know it includes a mag3110 magnetometer. This does exactly the same job as the hmc5883, and in fact they both run on i2c, so for all practical purposes its a direct drop in replacement. So in Sniff R21 we've added support for the mag3110. With the new driver you should be able to just change:

make magnetometer hmc5883 device


make magnetometer mag3110 device

And you're good to go.

When we tried it, we found that the results were pretty unreliable, but a bit of research suggested we could improve things by calbrating the sensor. If you've got an iPhone and used the compass app, then you'll be familiar with this, where it asks you to wave the phone around. The problem is that the chip tends to be biased, outputting the results with a fixed offset.

From our experience (sample size 1) on the hmc5883 this is sometimes quite a small error, so we got OK results... sometimes! On the mag3110 this is typically quite a larger error so we need always need to compensate for it.

While your phone does some complex stuff, including using the accelerometer to track the movement of your phone during calibration, we can do a basic calibration by getting you to wave the chip around. If you move it enough we'll get max and minimum values on each axis which are Offset+field, and Offset-field. Taking the average gives is the offset, which we can then subtract from subsequent readings.

To make this happen we've added a new variable compassCalibrate. If you set it to "yes" then you can  still use the compass as normal but the readings are also used for calibration. Provided you're operating in a relatively constant magnetic field, this works really well, so if you just need a generic compass just set it to "yes".

when start
.set compassCalibrate to yes
.say "Calibrating"
.repeat 100
..tell magnetometer to "read"
..wait 0.1 secs

In the compass.sniff example code, we set compassCalibrate to yes, then take 100 readings over 10 seconds to get a baseline calibration. During this time you should turn the chip around as much as possible. However even after we leave this setup phase, and start collecting "real" readings, we leave calibration on, and in fact the accuracy does seem to improve with further use.

..tell magnetometer to "read"
..say join "Heading " [ heading ]
..say ""
..wait 1 secs

Where this approach will fail is if you actually want to measure a changing magnetic field. Large changes in the field will be partially calibrated out, as the sensor tries to correct for something it actually should be measuring. In which case you should probably calibrate initially in a constant field, then turn calibration mode off.

With this code in place the Mag3110 worked really well, so we went back and added the same calibration modes to the Hmc5883. Your old code should work just as it always did, but if you add a calibration phase, or simple let the device calibrate as you're using it you should see much better results.

Sunday, 13 September 2015


We've had a bit of a push on "games" this summer, and we've previously blogged about the Sprite device system we've built. We developed that using just keyboard input, but I thought it would be nice to add joystick support. This turned out to be pretty easy on most of the Sniff platforms - the javascript and Windows versions were the easiest, with Linux only slightly tricky. However Apple really don't want you using joysticks on your Mac, so for now the joystick device doesn't work on OS X.

Using the joystick device is pretty trivial. In fact here's the basic code:

make joystick device
make joyX number
make joyY number
make joyZ number
make joyButton boolean

when start
..tell joystick to "update"
..if joyButton
...say [joyX]
...say [joyY]
...say [joyZ]
...say ""
..wait 0.1 secs

We only support one button, and it shouldn't make any difference which one you press on the joystick. While it would be possible to expose more buttons we then run into the problem of mapping then, and joysticks and gamepads are just too varied to do that in a simple and consistent way.

We do support a third Z axis if your hardware has one, but most of the time you can just use the joyX and joyY values, which are scaled from -1 to +1.

Depending on your preferred coding style you can either call "update" in the main game loop, so like we did above or break the code so that the joystick is refreshed in a separate script, and then simply use the variables as you need them:

when start
..tell joystick to "update"
..wait 0.01 secs

when start
..if joyButton
...say [joyX]
...say [joyY]
...say [joyZ]
...say ""
...wait 0.1 secs

There's no smart device detection plug/unplug tracking, so just make sure your gamepad is plugged in before you start, and don't unplug it during the game.

It should only take a few seconds to modify existing games to use the new controllers.

Friday, 11 September 2015

Weighing Things

We like measuring things here at Sniff Labs, so we're always looking out for cheap and fun sensors we can hook up to an Arduino. In Release 21 we've added support for weighing things using a load cell.
These can cost anything from a couple of pounds to hundreds of pounds depending on what you want to measure, but I bought a cheap one that can weigh up to 5Kg for about £3. They work on by attaching strain gauges to a metal bar. When weight is applied the bar deforms (slightly!) and the strain gauges reflect this. To turn this into something we can measure, the changing resistances of the strain gauge are arranged in a wheatstone bridge.

If all the resistances are equal the potential difference between D and B will be 0. Depending on your gauge several (or all) of the resistances can change, but basically the bigger the weight on the cell, then the bigger voltage between B and D.

Hopefully you're ahead of me, that we can measure a voltage using an Analog to Digital Converter (ADC). The Arduino has one of those built in, but there's a catch. The voltage we want to measure is very small and we need to measure it very accurately. The Arduino's analog inputs are the right general idea but we need something a bit more powerful...

And that would be the hx711. These cost about £2, and perform the same task as the Analog inputs, but much more accurately. In fact they're specifically designed for connecting to load cells, and have differential inputs, so they can measure the difference in voltage between the two points directly.

Wiring up the load cell can be a bit intimidating, as it (typically) just has four, unlabeled wires coming out of it. To make matters worse, the colours aren't totally standard, but most seem to be:
  • Red -> E+ (+ve power)
  • Black -> E- (-ve power)
  • Green -> A+ (+ve input)
  • White -> A- (-ve input)

If you get them wrong it probably won't do anything bad. In fact I got the green and white reversed when I made mine, and the only thing that happens is that it reads a negative voltage, rather than positive when a load is applied (which is perfectly fine, as it gets fixed when we do the calibration step).

The hx711 has two further inputs B+ and B- which allow you to connect a second load cell, but the Sniff device doesn't currently support that (if you need it, then drop me an email, and I'll look into it).

To connect the x711 to an Arduino we need two data pins: Data and Clock. Which ever pin you choose for Data, clock should be the next one, so I've used 8 for data, which puts clock on 9:

make loadCell hx711 device D8 #Data on D8, Clock on D9
make hxRawValue number

when start
.tell loadCell to "read"
.say join "Raw:" [ hxRawValue ]

All we need to do is tell the cell to "read", and we get back a value from the sensor.

However before we can do anything with that we need to calibrate the cell. There are two parts to this, and the first is done automatically. If you've used kitchen scales then you know that you can put the empty bowl on the scales and reset them to zero, so that the weight of the bowl is ignored in future measurements. We do the same thing, so when you run the program make sure there's nothing on the load cell that shouldn't be. The code will measures the weight of anything thats on the cell when its reset, and subtracts that from future measurements, so you don't need to worry about it.

Now that we've got our "zero" we now need to set our units:

.say "Apply the Calibration Weight now"
.ask "How heavy is the test load?" and wait
.tell loadCell to "read"
.set scaleFactor to value of answer/hxRawValue

We need to apply something of known weight to the cell. It doesn't matter exactly what it is, but it should be a sensible weight for the load cell you're using. We then get the raw value from the sensor and that gives us a scale factor.

..tell loadCell to "read"
..say join "Raw:" [ hxRawValue ]
..say join "Weight:"  [hxRawValue*scaleFactor]
..say ""
..wait 1 secs

From then on we can just read the raw value and multiply by the scale value to get the weight. 

You only really have to do this calibration step once - you can just print it out, and then use that number in future code. Once calibrated you don't really need the computer anymore, so it would be easy to replace the onscreen output with an LCD display. However each load cell (or at least each type of cell) needs to be calibrated at least once.

In primary school children learn about measuring by starting with alternative units - how many hand spans is the desk? How many strides is the playground? While kids this age aren't going to be coding this example themselves, you could have some fun by making a set of scales that weigh in alternative units. The calibration stage doesn't care what you put on the scale - the obvious thing is a 1Kg weight and tell it that it weighs 1 unit, but get creative: The hamster is a perfectly good unit of weight! 

At the calibration stage just put 1 hamster on the scale, and tell the program that it weight 1 unit. From then on your scale weighs in hamsters!

Sniffpad Secrets

SniffPad is our simple IDE for Sniff. While its not the most advanced IDE  in the world, it serves the basic function of letting new users write code, and compile it quickly, without having to learn a whole load of extra stuff. It has the added bonus of being written in Sniff, which means its portable, and if you don't like the way it behaves, you can always edit the source code and change it!

It's not really suitable for writing larger programs, but we don't really recommend that anyway. There are plenty of good text editors that you can use, and Sniff is really designed to be driven from the command line - SniffPad is just the first taste before you move on to whatever tools you want to use to drive Sniff.

However in R21 we've added a couple of nice features, and there are a few other things that you might have missed. Together they do make SniffPad a whole lot nicer to use.

Lets start with the popup load/save/quit type dialogs. The most important trick is that you can use the up/down cursor keys to scroll through the existing files in the current folder. If you used the 'ClickMe' Script this will be the SniffProjects folder in your home directory. When I run workshops I drop a few helpful examples in here so they're ready to go if I need them. The other trick is that you can use Return and Escape to have the same effect as pressing yes or no.

Cut/Copy/Paste work as you'd expect (though only within Sniffpad, as we don't use the system clipboard), so you can use this to move blocks of code around. You can activate them with Ctrl-X, Ctrl-C and Ctrl-V.

One of the frequent complaints was that the Sniffpad Font was too small, so now we've made it much bigger (by adding a displayFontScale variable you can use in your own code too), but now its perhaps too big. To give you more flexability you can now use Ctrl-B to flip between Big text and the older small text.

The other thing that's new is the ability to indent blocks of code. Quite often you have a long section of code that is working fine, but now you want to only execute it conditionally. That means you have to indent it all by one dot. Now you can just select the lines (or even just a single line if you want) and press Ctrl-I to Indent every line. This is a lot quicker than the old way of going down a line at a time and inserting dots manually.

Similarly if you need to Unindent you can use Ctrl-U, which is conveniently to the left of I on the keyboard.

None of these shortcuts are essential, but they will make using SniffPad a little bit easier.

Thursday, 10 September 2015

SVG Files in Sniff

You might not have come across SVG files very much but they're pretty handy - it stands for "Scalable Vector Graphics", which means they consist of a bunch of coordinates and lines, rather than a set of pixels. This makes them resolution independent, so we can draw them any size and they stay looking sharp. However the downside is that we actually have to draw them, which can be quite tricky.

In Sniff R21 we've added a simple "device" to read SVG files. The files consist of a series of "paths", where each path is a series of line segments. Internally its actually a bit more complex, but we handle that for you, and you just get a series of points you need to connect up. Draw each path in turn, and you get your image.

We start by making a window device to draw on, and handling the events:
make display window device
make displayX number
make displayY number
make displayColor number

when start
..tell display to "get event"
..wait 0.1 secs

Now we're ready to make an svgFile device:

make svgFile device
make fileData string
make fileOK boolean
make svgPointsX list of numbers
make svgPointsY list of numbers

And then we're ready to go:

when start
.set fileData to "pirate.svg"
.tell svgFile to "start read"
.if not fileOK
..say "Can't Read File"
..stop script

We start reading the file just like we would if it was a text file device, so here I've got a file called "pirate.svg". Then we're going to read paths from the file as long as there are some left:

.repeat until not fileOK
..tell svgFile to "read path"

Read path loads the points from a path into the two lists svgPointsX and svgPoints.

Now we just need to draw the path:

..set displayX to item 1 of svgPointsX
..set displayY to item 1 of svgPointsY
..tell display to "move"
..set count to 2
..repeat until count>length of svgPointsX
...set displayX to item count of svgPointsX
...set displayY to item count of svgPointsY
...tell display to "draw"
...change count by 1

Not all SVG files work so well - we've only got the outline info. The SVG Format also supports thick lines, filled areas, including colours and gradients, and a lot of other complex stuff that's not currently supported in Sniff. We may add that in the future, but for now we've got the all important coordinates.

It's appropriate that our test image is a pirate symbol as I often tell students to "think like a pirate" when getting to grips with transformations and coordinates. Start at the dead tree, and walk 10 paces north...

We can write a simple "transform" script to apply any kind of transformation on the points before we draw them:
when transform
.repeat length of svgPointsX using count
..set displayX to item count of svgPointsX*scale
..set displayY to item count of svgPointsY*scale
..change displayX by 100
..change displayY by 0
..replace item count of svgPointsX with displayX
..replace item count of svgPointsY with displayY

This moves the whole image to the right. To incorporate it into our main script we just add the line:

.repeat until not fileOK
..tell svgFile to "read path"
..if fileOK
...broadcast transform and wait

[Technical Aside: There's actually a minor quirk in the behaviour of "read path" at the moment in that that last time round when it reaches the end of the file it correctly sets fileOK to "no", but doesn't delete the old path, so the svgPoints list still contain the previous path. This means its actually getting drawn twice, which would be OK but if we transform it twice, it gets drawn in the wrong place - this will be fixed but for now we check fileOK, which is sort of what we should be doing anyway]

With that in place we can learn all about transformations by just editing the transform script. For example we could add a sheer:

..change displayX by 0.4*displayY
..change displayY by 0

I'm sure you can think of all sorts of educational fun and exciting things you could do with this... how would you animate the prirate so it looks like he's rippling around like on a flag?

Of course the real reason for implementing SVG files was to get them working with the laser engraver! Once we've got our pirate drawn on the screen, all we need to do is replace the window device with the gcode device, and our pirate will be send to the CNC machine! 

SVG files are ideally suited to this as CNC machines are designed to move the head around, along paths. The result of sending SVG files is much better than we get using the supplied software which sent regular image files, and because we only draw the stuff we have to its much faster too!

Wednesday, 9 September 2015

Sniff and the Laser Engraver

I guess a couple of things at Scratch2015AMS led me to this... they first was TurtleStitch which lets you control an embroidery machine using Snap. That's pretty cool. The second thing was more of an accident. Steve Holmes had brought some pretty nice laser beam breakers, which I thought might work pretty well in Sniff, so I started trying to find where he got them.

I still haven't found them, but I did find some almost affordable laser engravers. These look a LOT of fun, but these ones are a little too expensive for a first step, take up a bit more room than I have on my desk, and some of those lasers are a little more powerful than is safe without serious precautions.

A bit more searching turned up one of these for under £50 (eBay UK seller, free delivery within a few days):

The working area is limited to about 4cmX4cm and the laser is much less powerful less powerful which means you can do less with them but actually is a win in for me as I can try it out more easily.

So a few days later it arrived. It's a pretty amazing but of construction, that looks like someone comercialised a really cool DIY project. The mechanical transport is made from a couple of CD drives, and the electronic control is an Arduino - not a custom AVR board based on Arduino but an actually Arduino Pro Mini, connected to a couple of driver boards for the steppers and lasers. The rest of the hardware is laser cut Acrylic sheet. While the parts may be recycled, the actually assembly is really nice, and the over all design is excellent.

So plugging it in we hit a few snags. The supplied software is Windows only. I'm not planning to use it, but we should at least get it working before we throw everything out and write our own code. Unfortunately the Arduino Pro Mini doesn't include USB support, so you need a USB->Serial converter. That's OK as they supply one, but its based on the Prolient Chipset which doesn't work in Windows 10. It works fine on Mac/Linux but Prolient don't support it any more, so we have Windows only software, and everything except Windows hardware!

Fortuanatly a few months ago I bought a few USB-Serial converters - they cost about £3 on eBay. You need a 5V one. With that fixed, we're up and running. The supplied software isn't great, but it gets the job done, and I was able to burn some images onto some scraps of leather. I've mainly been using leather as we had a bag of leather scraps that were ideal (again from eBay for not much money). Old credit cards work great too!

The other upgrade I made was to get an A4 sheet of translucent green perspex. The laser is about 200mW Red. Compared to "real" laser based CNC machines that's pretty wimpy,  but for comparison your average laser pointer is about 5mW. Safety glasses are provided with machine, but they're uncomfortable, and they're so dark that you can't actually see anything except the laser. Glasses are good practise, and are essential if you're going to be staring at the beam, but it was impractical to wear them just because I was in the room with the machine, and in fact would be a serious hazard if I was walking round in them. Adding the Perspex as a guard around the machine mean that the machine was safe and non-distracting for anyone in the room (inverse square law!) unless they were actively inspecting it.

My next upgrade is going to be some green LED's to light the work, so its easier to see how the design is progressing.

With everything working we can now ditch the provided software and do something more interesting... CNC machines are programmed using G-Code. This is a simple set of text based commands. Our machine is running a program called GRBL, which is an arduino implementation of this. While G-Code supports a number of advanced commands we just need a few:

  • G00 - move the tool as fast as possible
  • G01- move the tool at a specified feed rate
  • M03 - turn on the laser
  • M04 - turn off the laser
The Move commands take X,Y, and Z parameters, though for now we only use the X and Y.

We've wrapped all of this up in a "gcode"  device which behaves rather like a display, so we can draw stuff on the Window device, and see what it looks like, then just replace window with gcode, check that everything is the right size and then burn the pattern.

If you check back through the blog posts you've find we wrote some turtle code, so lets take the simple spiral example from that:

make display gcode device
make displayX number
make displayY number
make displayColor number

make direction number
make distance number
make penDown boolean

when move
.change displayX by distance* cos of direction
.change displayY by distance  * sin of direction
.if penDown 
..tell display to "draw"
..tell display to "move"

when start
.set displayColor to 200
.set displayX to displayX/2
.set displayY to displayY/2
.tell display to "move"
.ask "ready to burn?" and wait
.if not answer ="yes"
..stop script
.set direction to 0
.set distance to 0.1
.repeat 300
..broadcast move and wait
..change direction by 9.5
..set distance to 1.01 * distance
..set penDown to not penDown

The turtle code is handled in the "move" script which moves the turtle and either moves or draws depending on if the pen is up or down. To draw a spiral we turn the turtle a little each step, and increase the size of the step.

The main script starts by moving the laser head to the centre of the bed, and asks if we're ready - this is pretty good practise if we're about to start firing lasers that can serisouly hurt you! Then it simply draws the spiral.

displayColor is used to control the speed of the tool, in mm/minute. I've used 200 as a good baseline. Moving faster means that less power hits each spot, so there isn't as much burning. This produces lighter marks, but also thinner marks. As it also has the advantage of getting the job one quicker, we generally want this to be bigger if possible. However the correct value is very dependant on your machine, and the material your marking.

When we run this nothing happens... That's because the gcode device has a number of modes. The default mode (or mode 3) outputs the gcode to a file, and doesn't include any commnds to turn the laser on! In that repect its pretty safe. It's best to run your code in this mode first and check that it works before you start messing round with stuff that can actually injure you. The gcode device has the engravers size built into it, (39mmx39mm), so running in this mode checks that you're not trying to crash the engraver head into the side of the machine. More expensive machines have mechanisms to detect this, but our little machine doesn't so we're dependant on our software to not do anything silly. If you have access to a larger machine just edit lib/Hosted/Xgcode.c to increase the limits.

Once we're happy with our code we can change the device to mode 2:
make display gcode device 2
Now this will try to talk to the real hardware and start moving the head around. If it doesn't find the device automatically when you run setup, then you might need to tell it explicitly using something like:

Now you should start seeing the machine come to life and do its thing. However the laser is STILL TURNED OFF. We're now checking that the laser is moving over the right area of the material we're engraving - we don't want the laser to start engraving the table!! (I put a couple of sheets of white cardboard under the machine just in case - white materials reflect the light and don't burn as well as darker ones).

Once you're happy its time to burn! Set the mode to 0, make sure that you're wearing the safety glasses or have some other filter in place, and the run the code!

And here it is. This photo also shows evidence of where I got things a little wrong. The laser has a focusing lens, and its important that you focus the beam correctly. If not, then at first nothing will happen, which will encourage you to reduce the feed rate, so the laser moves more slowly - this will cause the material to burn, but over a much to large area. We want the focus as tight as possible so we can burn the smallest details.

Alternatively you can run the code in mode 1, which outputs to a file with the laser enabled. You can then take this file and download it into your machine using some other program (there's a Sniff program called Sender which can do this).

With our spiral burnt,  it was pretty trivial to get some of the other old Sniff programs burning leather! I've used Hilbert curves, and last weeks Spirograph example:

Overall I'm pretty impressed with the little gadget, and totally hooked on the whole idea of CNC. The code should work with more or less any laser cutter or engraver, with only minor tweaks. Now I'm seriously looking and CNC milling machines...

Release 21: Back to School

Release 21 is now live!

This contains a number of new devices, and improvements to some old ones. In particular we can generate G-Code to drive a laser cutter directly from Sniff. We'll be talking about that in the next few days, along with posts detailing each of the new features, but for now here's the highlights list:
  • GCode CNC support
  • SVG Support
  • Joysticks
  • Improved Compass Support (including MAG3110)
  • Improved editing in SniffPad
  • Load Cell support
Check the downloads page to grab Sniff21 for your system.

Thursday, 3 September 2015


We're always looking for fun little mathematical toys we can turn into Sniff programs, and if they look pretty then even better. I was going to do something on Lissajous figures, which are an easy way of drawing nice abstract curved shapes. If you've still got an oscilloscope and a signal generator (once staples of any high school electronics/physics lab) you can make them really easily. However when I went to check for some mathematical background on the Wikipedia page I found something interesting: The first line of the page says "Not to be confused with spirographs"

That's odd because it never occurred to me before to confuse them with Spirographs, but now that I have "confused" them, Spirographs seem far more interesting!

Just in case you missed the '70s we have a ring around the outside, and a disk which spins inside it. We put a pen through a hole in the disk, and rotate it around to get a funky pattern. You can still buy new Spirographs very cheaply, and they're lots of fun!

Clicking over to the Spirograph page we find the mathematical derivation of the path of a Spirograph. We'll skip over most of that, and cut to the final result which is:

This is something we can easily work with! 

These are equations for a "parametric curve". We have a parameter t  which represents how far along the line we are. If we were drawing this, then as we move the pen, each position would represent an increase in t. We start with t=0 and increase t until we've traced out the whole path. We have two equations, so for a value of t we get an x and y value.

The R, l and k represent constants which select the different spirograph shapes. R is the simplest and just represents size of the outer ring.

k represents the size of the disk that spins round inside the outer ring. However they've done a little bit of a trick - the pattern doesn't really depend on the size of the inner disk, but rather on the relative sizes of the disk and the ring. So rather than using R and r to represent the sizes they use k=r/R, so k is always between 0 and 1, and we can make the whole pattern bigger or smaller just by changing R.

If you look at the equations closely we can see that if k=0 then the first part of the equation is multiplied by 1, and the second by 0, which gives the much simpler equations x=R cos(t) and y=R sin(t). This is just the equation of a circle, which is exactly what we'd expect if instead of using a disk we just moved a point around the inside of the ring.

The final parameter is l which represents the distance the pen is from the centre of the disk. We can again see that if l=0  we're back to a circle, which is pretty obvious if you think about it. Big values of l (up to 1) make the pattern more loopy, while smaller values make it less eccentric.

So lets code it:

make display window device
make displayX number
make displayY number
make displayColor number

when start
..tell display to "get event"

make R number
make l number
make k number
make t number

We start with some basic setup - make a window device we can draw in. As we're running on a desktop computer we also need to call "get event" to keep the windowing system happy. Then we make some variables to represent the constants.

Now we're ready to actually do the work:

make t number
when start
.set R to 300
.set l to 0.3
.set k to 0.7
.set displayColor to 700
.set t to 0
.set displayX to (1+(l-1)*k)*R+320
.set displayY to 240
.tell display to "move"
.repeat 360
..change t by 7
..set displayX to (1-k)*(cos of t) + l*k*cos of ((1-k)*t/k)
..set displayY to (1-k)*(sin of t) - l*k*sin of ((1-k)*t/k)
..set displayX to displayX*R+320
..set displayY to displayY*R+240
..tell display to "draw"

I picked values of  l and k which produce a generic spirograph pattern, and set R so that pattern would  fill most of the screen. 

We start with a value of 0 for t. While we could just dump that into the full equation infact if t=0 then we can precalculate the sin/cos terms and end up with the much simpler value for the starting point for the curve. We move there and we're ready to go.

The main loop is pretty simple - just increment t and use the values in the equations. We add 320 and 240 to centre the image.

The only tricky part is working out how many times we need to go around to get back to our starting point. The final value of t has to be an exact multiple of 360 so that the disk itself is back to its starting point, but it may not be oriented correctly. For that to happen (1-k)/k has to be a whole number to that that the orientation of the disk is also an exact multiple of 360.

In our case k=0.7, or 7/10 so we have (3/10)/(7/10) or 3/7. From that we can see that if t=7*360 then those terms become 3*360 and we're back where we started.

We could go around 360*7 times in steps of 1, but instead I've made it go around 360 times in steps of 7. This captures some of the strucuture - the outer loop will always bring us back to the same place on the ring and we can just adjust the step length to make sure we complete the curve.
And here it is! There's lots more we could do with this code - Try changing all the parameters to produce different curves. We should really move the drawing code into a separate script, so we can draw multiple curves in different colours. Could you change the loop to actually check if we've closed the curve?

I've got special plans of how we can use this code for something even more fun, but for now just try drawing some fun pictures!

[update: extra hint/idea... circumference is proportional to radius, so k=r/R could equally be written k=c/C. In the case of real spirographs, circumference is replaced with number of teeth in the wheel which is always an integer. This changes things slightly, so the number of times you need to go around is now the lowest common multiple of the two numbers]