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, 12 January 2016

Measuring Cheese with the Esplora

One of the new features of Release 24 is support for the Arduino Esplora. This is essentially an Arduino Leonardo (so compile programs using leo-sniff), with a whole bunch of sensors, buttons, a joystick and a slider built onto the board, so you can start programming without having to hook up extra hardware. As such you could always compile programs to run on it using leo-sniff, but now we've added got hold of one we've added support for all of the sensors.



The foam is acting as a diffuser for the very bright RGB Led

make usb device
make usbConsole device

The main difference between the Esplora and the more common Uno is that they handle their usb communication to your computer completely differently. One the Uno there's a dedicated chip which does nothing but handle the USB, but on the Leonardo and Esplora this is all done in software. This is more flexible, but less reliable. If you have problems programming the board, then pressing the reset button just before you download the program will usually solve the problem.

We need to include the usb device to handle the core of the USB protocol, and then the usbConsole device so that "say" and "ask" get directed over the software USB implementation. These have been stable for some time, but we've recently seen some problems with OSX Mavericks. "ask" in particular seems to have become unreliable. Helpfully we'll get this resolved in the future.

Now for the interesting bits:

#Some of the HW is just atattched to pins:
make redLed analog output D5
make blueLed analog output D9
make greenLed analog output D10
make led digital output D13

when start
.forever
..set redLed to 0.5*((sin of (timer*100))+1)
..set greenLed to 0.5*((sin of (timer*110))+1)
..set blueLed to 0.5*((sin of (timer*120))+1)

The Esplora has a regular LED attached to D13 like most Arduino's but it also has an RGB led attached to pins 5,9 and 10. These support analog output so we have easily mix colours together.

make buzzer digital output D6


The buzzer is attached to pin D6. In fact the "buzzer" is simply a piezo speaker, and to play a sound we need to "push" the speaker in and out at specific speeds:

when start
.forever
...set buzzer to on
...wait 1000 microsecs
...set buzzer to off
...wait 1000 microsecs

There's an accelerometer attached to analog inputs (yes A11 is a real thing - not a typo), and a couple of spare pins D3, and D11 which are brought out on two "tinker kit" headers.

make accX analog input A5
make accY analog input A11
make accZ analog input A6

make tkOutA digital output D3
make tkOutB digital output D11

Though tkOutA and B are labelled as outputs they are direct pin connections and can be used as both inputs or outputs.

You can access all of the above using regular Sniff Arduino code, but the other hardware on the board is a bit more tricky, so we've bundled it up in the "esplora" device:

make esplora device
make temperature number
make joyX number
make joyY number
make joyButton boolean
make esploraSlider number
make esploraLight number
make esploraSound number
make switch1 boolean
make switch2 boolean
make switch3 boolean
make switch4 boolean
make tkInA number
make tkInB number

We've got access to the temperature (though in a previous post I expressed serious doubts about its accuracy) joystick, slider, light and sound levels, four switches and two generic tinker kit inputs (not that these ARE input only).

when start
.forever
..tell esplora to "read"
..say join [switch1] join ":" join [switch2] join ":" join [switch3] join ":" [s
witch4]
..say join "Temp:" [temperature]
..if joyButton
...say "Joy Pressed"
..say join "Joy:" join [joyX] join "," [joyY]
..say join "Slider:" [esploraSlider]
..say join "Light:" [esploraLight]
..say join "Sound:" [esploraSound]
..wait 1 secs


If you have the Esplora TFT screen you can also draw stuff on it, using the standard Sniff drawing methods, having first declared a display:

make spi device
make display esploraTFT device

With the basic stuff out of the way, lets actually do something useful with this...

 it's CHEESE TIME.

In addition to an Arduino Esplora, one of the residents of Snff Manor got a cheese making kit for Xmas. As I'm sure you all know, cheese needs to be matured in a cool place between 10 and 14 degrees. The cellars seemed ideal but some kind of monitoring system was clearly in order.



when start
.set maxTemp to -100
.set minTemp to 100
.
.set displayColor to 0000
.tell display to "clear"
.broadcast updateGraph and wait
.
.forever
..set slowAverage to 0
..repeat slowSampleTime
...set fastAverage to 0
...repeat 10
....tell explora to "read"
....change fastAverage by temperature
....wait 0.1 secs
...set temperature to fastAverage/10
...change slowAverage by temperature
...
...if temperature > maxTemp
....set maxTemp to temperature
...if temperature < minTemp
....set minTemp to temperature
...
...broadcast updateLed and wait
...broadcast updateText and wait
..
..set temperature to slowAverage/slowSampleTime
..add temperature to history
..repeat until not length of history>historyLength
...delete item 1 of history
...
..broadcast updateGraph and wait


There's a lot going on here, but if we start from the middle, you'll see that we repeat 10 times, measuring the temperature and averaging it over 1 second. This makes the built in sensor much more consistent (if not more accurate). Then we compare the measured temperature to the max and minimum, and fire off a couple of scripts to update the RGB led and some text on the display.

We do this 900 times, which is 15 minutes, and calculate an average over this longer period, which we add to a list called "history". This records the last 12 hours of data, and we call a script to plot it on the screen.

make lowestThresholdTemp number 6
make lowThresholdTemp number 10
make highThresholdTemp number 14
make highestThresholdTemp number 20

when updateLed
.if temperature <lowestThresholdTemp
..set blueLed to 1
..set greenLed to 0
..set redLed to 0
..stop script
.
.if temperature <lowThresholdTemp
..set blueLed to ((lowThresholdTemp-temperature)/(lowThresholdTemp-lowestThresholdTemp))
..set greenLed to 1-((lowThresholdTemp-temperature)/(lowThresholdTemp-lowestThresholdTemp))
..set redLed to 0
..stop script
.
.if temperature <highThresholdTemp
..set blueLed to 0
..set greenLed to 1
..set redLed to 0
..stop script
.
.if temperature <highestThresholdTemp
..set blueLed to 0
..set greenLed to ((highestThresholdTemp-temperature)/(highestThresholdTemp-highThresholdTemp))
..set redLed to 1-((highestThresholdTemp-temperature)/(highestThresholdTemp-highThresholdTemp))
..stop script
.
.set blueLed to 0
.set greenLed to 0
.set redLed to 1

I've set up four constants using the new Sniff R24 syntax. lowestThresholdTemp is 6, and using the word is exactly the same as using the number. This means we can push these definitions outside the code itself so if we need to change them, then we can see exactly where they need to be tweaked. In this first run, I've decided that the cheese should ideally be kept between 10 and 14, with a less ideal window of between 6 and 20.

When updateLED runs, it sets the RGB LED to blue if the cheese cave (thats what they call it!) is too cold, it then blends from blue to green as it warms up. When it reaches 10degrees it turns green. From 14 upwards it then starts turning red.


The TFT display on the Esplora is a really nice display. Unfortunately in some respects its too nice. Usually we use something like a Nokia5110 screen which is low resolution and each pixel is either on or off. Here we've got much higher resolution and full colour, which creates a real problem for us. With the smaller screens we can prepare the screen image in memory then push it out in a single blast, which minimises flicker. Here the screen is way to large to fit in the Arduino's minimal RAM, so we have to draw directly to the screen. Not only is this slower, but it means when we clear the screen to draw on it, the screen actually goes blank. Large amounts of flicker are unavoidable. To minimise it as best we can we're not going to clear the whole screen at once but rather clear off bits of it before redrawing:

make counter number
make minY number
make maxY number
when partialClear
.set displayColor to 000
.repeat (maxY-minY) using counter
..set displayY to minY-1+counter
..set displayX to 0
..tell display to "move"
..set displayX to 160
..tell display to "hfill"

when updateText
.set minY to 110
.set maxY to 118
.broadcast partialClear and wait
.set displayColor to 777
.set displayX to 0
.set displayY to minY
.set message to join "Temperature:" [temperature]
.tell display to "show"
.
.set minY to 100
.set maxY to 108
.broadcast partialClear and wait
.set displayColor to 777
.set displayX to 0
.set displayY to minY
.set message to join "Low:" [minTemp]
.tell display to "show"
.
.set minY to 90
.set maxY to 98
.broadcast partialClear and wait
.set displayColor to 777
.set displayX to 0
.set displayY to minY
.set message to join "High:" [maxTemp]
.tell display to "show"

The text is 8 characters high, so we use PartialClear to clear only the rows we're about to print on. Then we tell the screen to show the latest statistics.



when updateGraph
.set minY to (minTemp-graphOffset)*graphYscale-1
.set maxY to (maxTemp-graphOffset)*graphYscale+1
.broadcast partialClear and wait
.set displayColor to 007
.set displayY to (lowestThresholdTemp-graphOffset)*graphYscale
.set displayX to 0
.tell display to "move"
.set displayX to historyLength*graphXscale
.tell display to "hfill"
.
.set displayColor to 070
.set displayY to (lowThresholdTemp-graphOffset)*graphYscale
.set displayX to 0
.tell display to "move"
.set displayX to historyLength*graphXscale
.tell display to "hfill"
.
.set displayColor to 070
.set displayY to (highThresholdTemp-graphOffset)*graphYscale
.set displayX to 0
.tell display to "move"
.set displayX to historyLength*graphXscale
.tell display to "hfill"
.
.set displayColor to 700
.set displayY to (highestThresholdTemp-graphOffset)*graphYscale
.set displayX to 0
.tell display to "move"
.set displayX to historyLength*graphXscale
.tell display to "hfill"
.
.set displayColor to 777
.set displayX to 0
.set displayY to ((item 1 of history)-graphOffset)*graphYscale
.tell display to "move"
.repeat length of history using counter
..set displayX to counter*graphXscale
..set displayY to ((item counter of history)-graphOffset)*graphYscale
..tell display to "draw"

Finally we draw the graph, again using PartialClear to get rid of only the bit we need to. There are 4 horizontal lines on the graph, representing the 4 threshold temperatures, then we simply loop over "history" drawing the graph.

We placed this down in the cellars and were able to monitor temperature, and see how it varied. The graph was particularly handy, as it was able to reveal some large changes of temperature that happened when we weren't actually there.

As we had reservations about the accuracy of the Esplora's temperature sensor, we also attached a dht11 to on of the tinker kit outputs. Things still to do include logging data to the SD card, and sounding an alarm if the temperature gets to high - "quickly! To the Cheese Cave!!!!!"


No comments:

Post a Comment