Thursday, 24 March 2011

Arduino to Max/MSP via OSC (Guide and Example Code)

"This Article is a guide complete with example code and downloads that allows you to send and receive data between an independent Arduino microcontroller (with no external Ethernet Shield) and Max/MSP using Processing software and the OSC protocol, as well as introducing alternative methods. This information can also be applied to using Arduino with other OSC-compatible software.

The reason for this guide? To save other people from many nights of painful internet searches and numerous coding trial and errors in order to get this working successfully."


A few months back... I purchased an Arduino Uno board after discovering its flexibility and simplicity in creating electronic systems that could communicate with software, which opens up a world of possibilities to people like me with little electronics or hardware experience. As a recent Audio Technology graduate, my main interest with using an Arduino board was connect it up to Max/MSP/Jitter in order to create interesting and interactive music systems, however it took me a while to find and settle on a communication method between the Arduino hardware and Max software that I was happy with. This article will go through the ultimate method I settled on, (which uses Processing and OSC (Open Sound Control)), as well as other and alternative methods I’ve discovered on the way.

A Brief Introduction to Arduino, Max, Processing, OSC and Making Them All Talk

When beginning my quest to get Arduino and Max talking to each other, the first and most useful place to start looking was on the Arduino Playground website. Here it lists several methods, Max patches, and Arduino code that enable communication between Arduino and Max, with some being a lot more useful than others.

The best system I found here was Maxuino, which uses Max's built-in serial object to implement OSC style communication to/from the Arduino-compatible hardware. The ‘StandardFirmata’ Arduino sketch (which is an example sketch installed with the Arduino IDE, which can be found under File>Examples>Firmata>StandardFirmata), is run on the Arduino board whilst the collection of Maxuino Max patches allows data to be read to and from the hardware. After extensively investigating and playing with the example Max patches, I managed to get it working fine, however I still couldn’t understand exactly how the patch was working and how I would easily go about incorporating this system into my own Max patches; the Maxuino patch is quite big with many sub-patches. Also it was round about this time I first discovered the OSC protocol, and this led my to believe there must be a simpler way.

If you’re not familiar with OSC, it is a protocol for communication among computers, sound synthesizers, and other multimedia devices that is optimized for modern networking technology. It can be seen as an alternative and updated version of the MIDI protocol, which has shown prominent limitations in recent years. After initially getting my head around it, I found OSC to be very simple to use and understand, and it can be implemented in Max by downloading the Max externals. OSC is starting to become a well-known protocol, so I thought it would be worth using in my projects.

Therefore I then started looking into Arduino-to-OSC communication. OSC is a network protocol, therefore it sends data using UDP over Ethernet or Wi-Fi. Embarrassingly, as I’m not experienced or knowledgeable in networking, it took me a while to understand this, which means that the Arduino can only communicate with other devices solely via OSC by using an Arduino Ethernet Shield. If you have or plan to get an Ethernet shield, there is an OSC library for Arduino. As I don’t have an Ethernet shield I haven’t tested it out, but apparently it works fine and allows easy communication between Arduino and other devices via OSC. However there are downsides to this method; an Ethernet shield is an extra cost, it adds size and weight to your hardware, and it means an extra lead is plugged into your computer if you still need to power the Arduino via USB. The cost was a major issue for me, so I decided to keep searching for other OSC methods.

I soon discovered this tutorial, that explains how to make a Teensy 2.0 microcontroller communicate with software using Processing as an OSC interface. Processing is an open source programming language and environment that is mainly used by artists and designers that don’t want to delve too deep into software programming, and the Arduino IDE is actually modeled on Processing, therefore the two work well together. After looking into this software, I soon discovered Processing has an Arduino library that allows you to control the Arduino directly from Processing over serial communication whilst the ‘StandardFirmata’ Arduino sketch is run on the hardware. There is also an OSC library for Processing that allows OSC data to be sent and received by Processing sketches. Therefore I saw Processing to be a perfect ‘middleman’ for making the Arduino and Max/MSP communicate via OSC.

An Implementation Guide With Example Processing Code & Max Patch

In case you’ve skipped the first section and jumped straight to here, here is the setup for this method of communication between the Arduino and Max/MSP via OSC:

Arduino to OSC communication diagram

Pro’s of this method?
1. It uses the OSC protocol. This is an advantage because it is simple to implement and use, and is a growing communication protocol within music and media applications. As well as Max/MSP/Jitter, there is a number of other music production and programming software, as well as a growing list of mobile apps, that support and implement OSC. Therefore this guide could be applied to using Arduino with other OSC-compatible software.
2. It uses OSC without needing an Arduino Ethernet Shield.
3. The Arduino and OSC Processing libraries mean that the code needed is short and easy to understand, and the Max OSC externals means that OSC can be implemented in Max with only a few objects.
4. The sketch uploaded onto the Arduino never needs to be changed; everything can be directly controlled via Processing and Max/MSP.

Con’s of this method?
1. The data doesn’t go straight from the Arduino to Max/MSP; it needs the Processing sketch open as well. As mentioned before, to avoid needing this ‘middleman’ software you can either use an Arduino Ethernet shield with the Arduino OSC library, or boycott using OSC completely and use a system like Maxuino, which sends data directly from Arduino to Max/MSP via Arduino’s serial communication. But as mentioned above, both this alternative methods have their own pitfalls.

List of libraries/extras you will need:
Processing Arduino library:
http://www.arduino.cc/playground/Interfacing/Processing
Processing OSC library:
http://www.sojamo.de/libraries/oscP5/
Max OSC externals:
http://cnmat.berkeley.edu/downloads
Follow the instructions they provide to install these.

Below is a full Processing sketch needed to receive and send data between the Arduino and Max/MSP via OSC. In this example, data is being read from all the Arduino analog pins as well as digital pins 2, 4 and 7. The rest of the digital pins are then used as outputs; pins 3, 5 and 6 being used as PWM (pulse width modulation) outputs, with the rest of the digital pins (8-13) being used as regular digital outputs.

Copy & paste the code below into Processing, or download the sketch from here.


/**
Processing Arduino to OSC example sketch - written by Liam Lacey (http://liamtmlacey.tumblr.com)

This processing sketch allows communication to and from the Arduino (using the processing arduino library),
and then converts the data into/from OSC (using the oscP5 library) to communicate to/from other OSC compatible software/hardware, e.g. Max/MSP.

In this example sketch, all analog pins are being read, as well as digital pins 2, 4 and 7.
Digital pins 3, 5 and 6 are used as PWM pins, and the rest of the digital pins (8-13) are set to regular output pins.


* In order for this sketch to communicate with the Arduino board, the StandardFirmata Arduino sketch must be uploaded onto the board
(Examples > Firmata > StandardFirmata)

* OSC code adapted from 'oscP5sendreceive' by andreas schlegel
* Arduino code taken from the tutorial at http://www.arduino.cc/playground/Interfacing/Processing


*/


//libraries needed for arduino communication
import processing.serial.*;
import cc.arduino.*;

//libraries needed for osc
import oscP5.*;
import netP5.*;

//variables needed for arduino communication
Arduino arduino;

//variables needed for osc
OscP5 oscP5;
NetAddress myRemoteLocation;

//set/change port numbers here
int incomingPort = 12000;
int outgoingPort = 12001;

//set/change the IP address that the OSC data is being sent to
//127.0.0.1 is the local address (for sending osc to an application on the same computer)
String ipAddress = "127.0.0.1";





//---------------setup code goes in the following function---------------------
void setup()
{
size(400,400);
frameRate(25);

/* start oscP5, listening for incoming messages at port ##### */
//for INCOMING osc messages (e.g. from Max/MSP)
oscP5 = new OscP5(this,incomingPort); //port number set above

/* myRemoteLocation is a NetAddress. a NetAddress takes 2 parameters,
* an ip address and a port number. myRemoteLocation is used as parameter in
* oscP5.send() when sending osc packets to another computer, device,
* application. usage see below.
*/
//for OUTGOING osc messages (to another device/application)
myRemoteLocation = new NetAddress(ipAddress, outgoingPort); //ip address set above


//----for Arduino communication----
arduino = new Arduino(this, Arduino.list()[0], 57600); //creates an Arduino object

//set digital pins on arduino to input mode or output mode
arduino.pinMode(2, Arduino.INPUT);
arduino.pinMode(4, Arduino.INPUT);
arduino.pinMode(7, Arduino.INPUT);
//digital pins are set to output by default, so only the rest of the pins don't need to be manually set to OUTPUT
}





//----------the following function runs continuously as the app is open------------
//In here you should enter the code that reads any arduino pin data, and sends the data out as OSC
void draw()
{
int i;

//read data from all the analog pins and send them out as osc data
for (i = 0; i <= 5; i++)
{
int analogInputData = arduino.analogRead(i); //analog pin i is read and put into the analogInputData variable
OscMessage analogInputMessage = new OscMessage("/analog/"+i); //an OSC message in created in the form 'analog/i'
analogInputMessage.add(analogInputData); //the analog data from pin i is added to the osc message
oscP5.send(analogInputMessage, myRemoteLocation); //the OSC message is sent to the set outgoing port and IP address
}

//read data from the digitalinput pins (pins 2, 4 and 7 in this example) and send them out as osc data
for (i = 2; i <= 7; i++)
{
if(i == 2 || i == 4 || i == 7)
{
int digitalInputData = arduino.digitalRead(i); //digital pin i is read and put into the digitalInputData variable
OscMessage digitalInputMessage = new OscMessage("/digital/"+i); //an OSC message in created in the form 'digital/i'
digitalInputMessage.add(digitalInputData); //the digital data from pin i is added to the osc message
oscP5.send(digitalInputMessage, myRemoteLocation); //the OSC message is sent to the set outgoing port and IP address
}


background(0);

}
}




//--------incoming osc message are forwarded to the following oscEvent method. Write to the arduino pins here--------
//----------------------------------This method is called for each OSC message recieved------------------------------
void oscEvent(OscMessage theOscMessage)
{
/* print the address pattern and the typetag of the received OscMessage */
print("### received an osc message.");
print(" addrpattern: "+theOscMessage.addrPattern());
print(" typetag: "+theOscMessage.typetag());
print(" value: "+theOscMessage.get(0).intValue() +"\n");
//-----------------------------------------------------------------------

int i;
int oscValue = theOscMessage.get(0).intValue(); //sets the incoming value of the OSC message to the oscValue variable




//write data to the selected digital output pins (pins 8-13)
for(i = 8; i <= 13; i++)
{
if(theOscMessage.addrPattern().equals("/digital/"+i) == true) //if the osc message = /digital/i/ (i represents the pin number)
{
if(oscValue == 0)
{
arduino.digitalWrite(i, Arduino.LOW); //turn pin OFF
print("pin turned off\n");
}
else
{
arduino.digitalWrite(i, Arduino.HIGH); //turn pin ON
print("pin turned on\n");
}
}
}




//write data to the selected PWN output pins (digital pins 3, 5 and 6 in this example)
for(i = 3; i <= 6; i++)
{
if (i == 3 || i == 5 || i == 6)
{
if(theOscMessage.addrPattern().equals("/pwm/"+i) == true) //if the osc message = /pwm/i/ (i represents the pin number)
{
arduino.analogWrite(i, oscValue); //sets the pin to the incoming osc data
}
}
}
}



I’ve thoroughly commented the code above, so it should be fairly simple to understand. For further information on the Arduino methods and library, go here, and for further information on the OSC methods and library, open the ‘index.html’ file that comes in the ‘references’ folder with the download of the library.

Below is a screenshot of the Max/MSP patch for communicating with the Processing sketch via OSC.

MaxMSP OSC patch screenshot

Download the patch from here

As you can see, it is very minimal and is a lot easier to understand and use than other systems such as Maxuino.

For more information on the OSC objects, right-click/control-click on them in edit mode and go to ‘Help’.

If you have found this guide useful, please go to http://x.nu/desine and support and promote the project that the company I currently work for is developing. It is an innovative new electronic musical instrument (pictured below) that uses an XMOS board (a more powerful microcontroller) along with OSC to send data to Max/MSP.

AlphaSphere

Please contact me (via comments below or on the original page that you found this post on) with any comments or queries.