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.

Monday, 3 November 2014

Spirit of Radio: RF24 wireless comms!

There are a bunch of ways of communicating with an Arduino running Sniff. You could use ethernet, but you'd need cables. You could use a RC transmitter or IR, but but they're only one way. Wifi on Arduino is expensive. It's never a one size fits all - something cheap, fast, simple and bi-directional, so that for example I could set up the weather station at the bottom of the garden, and collect the results in the house...

Enter the RF24. These amazing little radio transceivers cost about $1 on eBay, and contain everything you need to do some pretty nifty communications. The only downside that was holding them back was that they need 7 wires to connect them to an arduino - not a problem in principle, but a pain to hook up two or three of them for me to test. Then I found the Funduino Joystick shield - about $5 from the Asian electronics online superstore of your choice. For some reason that's not clear these have an RF24 socket!?! Odd if you want a joystick, but really handy if you need to hook up several RF24's...

With the boards aquired and RF24's plugged in we're good to go. I set up two boards: one called server which listens for a message, and sends a reply back (just confirming all was well), and the other as a client which sends a message when a button is pressed.

Here's the client first:
make spi device
make transmitter rf24 device
make message string
make radioChannel number

make buttonA digital input 2

make receivedMessage string
when start
.set radioChannel to 2
.tell transmitter to "setReceiveChannel"
.forever
..tell transmitter to "readString"
..if not message = ""
...set receivedMessage to message
...say receivedMessage

Here's the first part of the program where we set up the RF24 device and tell it to listen on channel 2. Internally rf24's support multiple frequencies, and allow multiple senders and receivers to share the same channel without their messages getting mixed, but for Sniff we simplify that - when you listen on channel 2, you will receive all the messages sent on channel 2.

Having set the channel we go into a loop, and tell the transmitter to try and read the a string. If it does, then it makes a copy, and prints out the received string.

Transmitting is just as easy:
make messageToSend string
when start
.set radioChannel to 1
.tell transmitter to "setTransmitChannel"
.forever
..if not buttonA
...set messageToSend to [ timer ]
...set message to messageToSend
...tell transmitter to "writeString"
...say messageToSend
...wait until buttonA

We select channel 1 as the transmit channel, then wait for the user to press one of the buttons on the Funduino JS shield (buttons always come in handy). When the button is pressed we copy create a messageToSend, and assign it to the variable message, which we transmit using the writeString command. Then we print out the message and wait until the user stops pressing the button. The messages you send are limited to 32 characters, so keep your messages short.

All that messing around copying message to and from the other strings is because we have two scripts changing message at the same time - If one sets it to something, then the other changes it, then the first script might get confused. The way Scratch and Sniff handle this means that normally we don't have to worry about it, but occasionally it can trip you up, so to be safe we've created and displayed the message using a different variable.

Setting up the server is easier:
make spi device
make transmitter rf24 device
make message string
make radioChannel number

when start
.set radioChannel to 1
.tell transmitter to "setReceiveChannel"
.set radioChannel to 2
.tell transmitter to "setTransmitChannel"
.
.forever
..tell transmitter to "readString"
..if not message = ""
...say message
...set message to join "echo: " message
...#The other end has just finished transmitting
...#Give it 20mS to start listening again
...wait 20 millisecs
...tell transmitter to "writeString"

We set up the send and receive channels (noting we're now listening on 1 and sending on 2). We wait until we receive a message, we add the word "echo" on the begining and then send it back.

The only gotcha here is that strictly the rf24 can't be both a transmitter and a receiver... but it can switch back and forth pretty quick. Normally we set it up to listen, but when it needs to transmit it has to stop listening for a while, send the message, the switch back to listening. In this case the other end has just sent us a message, so at the instant we receive it, the transmitter is probably, desperately trying to get back into listening mode asap. It we send a message straight back, then it might not be ready, so we wait just a little while to give it a chance to get ready for us.

When you press the button on the client, it will send the current timer value to the server, which prints it out. The server then sends an acknowledge "echo" back to the client.




You can get more fancy and have multiple clients. They can both send messages to the server, and because both are listening on the same channel both see the echo replies. You could experiment with different receive channels for each client to avoid this, or simply add something into the echo, so the client can see if its intended for it.

And that's it - I'm sure we'll have lots more fun with these now that we've got device support and an easy way to hook them up.

No comments:

Post a Comment