Please disable AdBlock. CAN is an ad-supported site that takes hundreds of hours and thousands of dollars to sustain. Read More.
HOLO is a biannual magazine about emerging trajectories in art, science, and technology brought to you by the people behind CAN. Learn more!

Wireless + Arduino + oF [Tutorial]

In the last tutorial we used an openFrameworks application to control a process running on an Arduino board. In this tutorial we’re going to reverse that and use an Arduino board to control an openFrameworks application that’s playing back music and we’ll do it wirelessly and (relatively) inexpensively. The electronics in this tutorial are a little more involved than the previous one because we need an oF application to control and two Arduino controllers: one to send transmit data and one to receive data and communicate with the oF application. There are a whole bunch different ways to do wireless communication that we’ll outline in the section below on wireless but for this tutorial, to mitigate the cost of requiring two Arduinos, I’m going to use inexpensive Radio Frequency (RF) components to send and receive the data.

RF components tend to be around $10US for a transmitter and receiver pair and have a range of about 150 meters outdoors. While that’s not a huge distance, it’s oftentimes plenty to create simple wireless interactivity between different components. There are plenty of other options to create wireless communication or even small networks of devices and applications. For the sake here is a comparison of some of the ways to create wireless communication between two or more devices:

XBee

pros: no collision of messages, very specific addressing of messages, can be extremely long range, fast
cons: somewhat expensive, sometimes difficult to configure

Wireless Internet

pros: no collisions of messages, very specific addressing of messages, allows sending many different kinds of data (images, sounds, complex data formats), fast
cons: expensive, difficult to configure communication between another computer and a wireless card, depending on the network and router, limited to range of wireless network

Cellphone

pros: range unlimited, no collisions of messages, very specific addressing of messages
cons: requires either a SIM card with an account or prepaid credits, difficult to configure with the Arduino, can be comparatively slow, expensive, high power requirements

BlueTooth

pros: Allows large amounts of data, comparatively fast, doesn’t require much power
cons: difficult to configure, expensive

Radio

pros: inexpensive, easy to configure, requires little power
cons: can’t have more than one transmitter in an area, no addressing of messages, range limited, comparatively slow

In this tutorial, since we’re interested in inexpensive and easy to configure, we’re going to with the RF option since the limited range and transmitter collisions aren’t going to interfere with our application. In case you’re curious though, most of the code from this application can be re-used in an application that uses a different wireless solution than RF (a solution that uses a cellular module is probably the most different and won’t reuse much of the code). So then, what is RF?

Radio as a data medium

If you’re not up for a little theory, feel free to skip this section and look at the code below, you won’t miss anything that affects your understanding of how the application actually works. You’re most familiar with radio waves as being sound received by your car stereo, but those waves can just as easily communicate binary or RS-232 (that is, Serial data) protocol as well. To keep this explanation basic we’ll ignore the differences between Frequency Shift Keying and Amplitude Shift Keying and just focus on what data in a radio wave transmission looks like. The transmitter is constantly sending noise out but when you write a signal through it the wave simply represents each bit of the data as a peak or valley depending on whether it’s a 1 or 0. You can see what that signal looks like here:

At the left side you can see the noise that the transmitter is constantly sending out. In the center is the signal and on the right is the resumption of noise. Zoomed in closer you can see what the data actually looks like:

Each transmitter and receiver pair handles data at a specific number of bits per second and a specific number of bits in each byte, so transforming that wave into serial data is just a matter of translating those peaks into electrical signals using the RS-232 Serial protocol. Just like tuning a radio to a specific station, communication between a transmitter and receiver happens at a specific frequency and many transmitter/receiver pairs only operate at one frequency, for instance, 433Mhz. For more information on radio frequency communication you can look at the site Dave Houston runs on using RF and IR at davehouston.org.

What you’ll need:

2 x Arduino Compatible Devices
1 x RF Transmitter like this one
1 x RF Receiver like this one
1 x computer to run your OF application
2 x buttons or switches of any kind (as long as they only have 1 state)
1 x potentiometer

RF TransmitterRF ReceiverPotentiometerPush Button

The Radio Modules

The two RF modules that I’m using here have a range of about 160 meters outdoor with line of sight and about 70 meters indoors and can even travel through walls and windows. They’re quite light, inexpensive, and don’t require a great deal of power to function meaning that you can easily run them off of battery power for a long time. As I mentioned in the comparison of different techniques for wireless communication one of the problems with RF communication is that any transmitters signal will be received by any receiver within range, the same as radio. You can find transmitter/receiver pairs with changeable frequencies and though they’re more expensive they do allow you to change frequencies in the event of interference.

On the Arduino end of things the VirtualWire library allows you to write data using any Digital pin of your Arduino as the TX (transmit) data through the RF module and receive data using any PWM digital pin of your Arduino as the RX (receive). On my transmitter I have the data pin connected to my Arduino as shown here.

Note the transmitters data pin isn’t connected to a PWM pin, but a non-PWM digital pin, pin 2.

This diagram was made with Fritzing, a tool for laying out electronics for breadboards and for creating schematics for PCBs.

If you want to increase the range of your transmitter you can use a piece of wire attached to the RF output pin, which works just like a miniature version of a radio tower.

On my Arduino connected to the receiver I have the data pin of the receiver connected to pin 3 and the +5V and Ground connected to the ground pins of the Arduino controller. The Arduino is connected to my laptop by USB so that it can communicate with my oF application. You might be asking yourself: do I really need this other Arduino? The answer is: probably. Trying to connect the Arduino to an FTDI pin or cable like the one shown below is a little tricky because you the signals received from the RF Receiver aren’t “logic level”, that is, they’re not powerful enough to be registered by the FTDI chip as input. You’d need to increase the voltage substantially to 3.3V or 5V depending on the board and that’s a rather difficult proposition. For the curious, you can connect the transmitter directly to your computer using the FTDI chip and send messages directly from your computer on a serial port. There’s a section on doing this in Tom Igoes excellent book Making Things Talk.
Here’s the wiring diagram. Note that the receiver is connected to a PWM pin, unlike the transmitter:

The Arduino Code

These Arduino apps use the VirtualWire library which is developed by Mike McCauley and enables you send and receive RF wireless messages. It’s well documented and updated quite regularly and works with all the Arduino boards. You can find more info and download links here: http://www.open.com.au/mikem/arduino/. The most important methods of that library that we’re going to use are, in order:

vw_setup() – this sets the rate at which the library reads or writes. In the example below it’s used like this: vw_setup(2000). We’ll be using it in both the transmitter and receiver applicaitons.

vw_set_tx_pin() – this sets the pin that will be used to transmit RF data. This is only used in the Arduino application that sends the RF data. Notice the “tx_pin” part of the method name; the tx actually indicates that this is supposed to transmit and it’s on your Arduino and most devices that communicate over Serial.

vw_set_rx_pin() – this sets the pin that will be used to receive RF data. This is only used in the Arduino application that receives the RF data. As with above, the “rx_pin” part of the method name, indicates that it’s setting the receieving pin.

vw_send() – this sends the data over the VirtualWire library and it takes two values: an array of bytes to send, and the length of the message, like so: vw_send(msg, 3). This assumes that there is an array called msg and sends the first 3 values of that array.

vw_get_message() – This is the corollary to the send method and it’s used in the receiveing application to read data from the RF module. It takes two parameters, an array to write the data it receives and the length of the message that it’s expecting. One odd thing to note about this message is that the second parameter has to be the reference of a byte, so the call to vw_get_message() will look like: vw_get_message(buf, &buflen) where buf is an array of bytes and buflen is a byte indicating how long in bytes we’re expect the message to be.

The rest of the code is simply polling the two buttons and the potentiometer on the transmitter board and sending the RF values received to the oF application from the receiver board.

Here’s the code to poll the pins where the buttons and potentiometer are attached and then send it through the RF Transmitter attached to pin 3. Note that the pin used to connect the RF Receiver is a PWM enabled pin; any PWM enabled pin can be used to receive data.

transmitter.pde

// you must download and install the VirtualWire.h
// to your hardware/libraries folder
#include <VirtualWire.h>

byte msg[3];

void setup()
{
pinMode(2, INPUT);
pinMode(3, INPUT);
// Bits per sec
vw_setup(2000);
// pin 2 is used as the transmit data out into the TX
// Link module, change this to suit your needs.
vw_set_tx_pin(2);
}

void loop()
{
// flash a light to show the start of the
// transmission, nice to just make sure
// you know what's going on while it'd happening
digitalWrite(13, false);
msg[0] = map(analogRead(0), 0, 1023, 0, 255);
if(digitalRead(2) == 0) {
msg[1] = '0';
} else {
msg[1] = '1';
}

if(digitalRead(3) == 0) {
msg[2] = '0';
} else {
msg[2] = '1';
}

vw_send(msg, 3);
// Wait for message to finish
vw_wait_tx();
//delay(20);
// Flash a light to show transmitting
digitalWrite(13, true);
}

And here’s the Arduino application to receive the data from the RF Receiver and communicate with the oF application. We want to write the data to the serial port using a really simple protocol that looks like this: ‘s’ and the speed value, ‘a’ and whether to play the first sample, and finally ‘b’ and whether to play the second sample. We do that by just writing the commands and values in order. Note that the pin used to connect the RF Transmitter isn’t a PWM enabled pin. Sending data using VirtualWire doesn’t work connected to PWM pins, only non-PWM digital pins.

receiver.pde

// you must download and install the VirtualWire.h
// to your hardware/libraries folder
#include

byte buf[3];
byte buflen;

void setup()
{
buflen = 3;

Serial.begin(2400);
Serial.println("starting");

// This is how fast our Virtual Wire link
// will be receiving data
vw_setup(2000);
// We will be receiving on pin 3 ie the RX pin
// from the module connects to this pin.
vw_set_rx_pin(3);
// Start up the receiver
vw_rx_start();

}

void loop()
{
// check to see if anything has been received
vw_get_message(buf, &amp;buflen);
// ok we got something. Let's send it
// in our simple little protocol
// v is Volume
Serial.write('s');
Serial.write(buf[0]);
// a is the A sample. Turn the first
// sample on or off
Serial.write('a');
Serial.write(buf[1]);
// b is the B sample. Turn the first
// sample on or off
Serial.write('b');
Serial.write(buf[2]);
}

The openFrameworks Application

The oF application is not particularly complex, it simply reads the data being sent over the Serial port using an ofSerial object and according to the simple protocol that we outlined in the last section, plays or pauses the two files, and changes the speed of the files.

Loading and playing sounds in an openFrameworks application is done using the ofSoundPlayer class which provides pretty straightforward functionality with methods named: loadSound(), unloadSound(), play(), stop(). I’d imagine you can guess how these work. The only other method that this application will be using is the setSpeed() method that take a floating point value to control the speed of the files playing back. To use the value received from the potentiometer, which was originally 1024 but was then cut down to 255 possible values to make it easier to send the value over RF, 122 is taken as 1.0 or normal speed, anything lower slows the playback down and anything faster speeds it up.

The other important part of this code is reading the serial data from the Arduino and properly converting it to the necessary formats. The Serial code is almost identical to the code from the last tutorial so if you’re not familiar with how an openFrameworks application reads from the Serial port check out the previous tutorial. I’m going to highlight some of the most important parts of the code but not all of it. The commented code in the downloads for this tutorial

rfSoundApp.h

class rfSoundApp : public ofBaseApp{

public:

void setup();
void update();
void draw();

Here are our two ofSoundPlayer instances:

ofSoundPlayer beat;
ofSoundPlayer melody;

This is the object to handle the Serial port communication and a buffer to read all the values received from the Serial port into.

ofSerial serial;
unsigned char buffer[6];
};
#endif

Now the cpp file:

rfSoundApp.cpp

#include "rfSoundApp.h"

void rfSoundApp::setup(){

Here, load both of the audio files. Note that both audio file need to be stored in the data folder:

beat.loadSound("beat.wav");
melody.loadSound("melody.wav");

Now we set both files to play continuously until they’re stopped.

beat.loadSound("sounds/beat.wav");
melody.loadSound("sounds/melody.wav");

beat.setLoop(true);
melody.setLoop(true);

serial.enumerateDevices();
serial.setup("/dev/cu.usbserial-A6004nTt", 2400); // you'll need to change this
}

In the update() method there are two separate processes occurring. The first is that the underlying sound engine needs to be updated using the ofSoundUpdate() method. This loads data from the sound engine to your computers sound card.

void rfSoundApp::update(){
// update the sound playing system:
ofSoundUpdate();
if(serial.available() > 0) {

Read all the bytes from the Serial port into the buffer object:

serial.readBytes(buffer, 6);

Now the application can parse the data received from the Serial port and use it to set the speed of each ofSoundPlayer and control whether they are playing or not. Remember that the data being sent from the Arduino might look something like this s180a0b1, which would mean set the speed to 180, stop the first ofSoundPlayer and play the second. The oF application simply needs to parse those commands and change them appropriately:

if(serial.available() > 0) {

serial.readBytes(buffer, 6);

if(buffer[0] == 's') {
float speed = (float) buffer[1]/64.0f;
printf(" speed %f %i \n ", speed, buffer[1]);
beat.setSpeed(speed);
melody.setSpeed(speed);
}

if(buffer[2] == 'a') {
if(buffer[3] == '0') {
beat.stop();
} else {
if(!beat.getIsPlaying()) beat.play();
}
}

if(buffer[2] == 'b') {
if(buffer[3] == '0') {
melody.stop();
} else {
if(!melody.getIsPlaying()) melody.play();
}
}
}

In the draw() method of the application the ofSoundGetSpectrum() method is used to get a range of data representing the sound in the application that can be used to draw a waveform:

void rfSoundApp::draw(){

ofSetColor(0, 0, 0);
float* f = ofSoundGetSpectrum(512);

int i = 0;
int height = ofGetHeight();
while(i<512) {
ofRect(i*2, height - (f[i] * 1000), 2, f[i] * 1000);
i++;
}
}

The downloads for this tutorial can be found http://thefactoryfactory.com/ca_2_of_arduino.zip. Enjoy!

Joshua Noble is a writer, designer, and programmer based in Portland, Oregon and New York City. He’s the author of, most recently, Programming Interactivity and the forthcoming book Research for Living.

    • Arduino Fan

      great work man

      i have question if you do not mind

      im working with arduino UNO R3 and there is no plug for 9 v instead it got 2 pin for ground and Vin

      thx for reading my message looking forward for ansuwer

    • dolores

      Josh, your book is amazing. It has helped me so much. Thank you for writing it…I’m using it make my sculptures interactive – http://www.youtube.com/watch?v=6KfRLrTnwNM&list=UUkhX0r1dI9hspJG9fCQWeBw