Controlling an Arduino wirelessly from Pd/Max
I’ve been way too focused on writing up research lately to have made any blog posts but I’m now working on some more hands-on stuff (as well as some new music) so here’s hoping I can make the effort to write a few more blog posts. I’m hoping to have a hybrid-BCI finished in the next couple of weeks, the working title is joybeat; a drum machine that is controlled by cognitive thought as well as emotional measures read via the brain. The best thing about it is that it uses a new SSVEP stimuli device made from hardware as opposed to flashing lights on a computer screen. The brain wave response from this is so much better. I’m performing my piece Flex in next month in Liverpool and I hope to have the new hardware setup ready. We’re commissioning a slick looking casing to house it all as well but at the moment it’s all wires, screens and lights.
Anyway, this post is about how to control an Arduino wirelessly via brain signals. I usually use a combination of Pure Data and Matlab for brainwave and music processing but this could just as easily be applied to Max/MSP as well. There’s no one place online that houses this info (but it is all out there) so I’m compiling it here, mostly for my memory’s sake.
Mention wireless control signals and performance and usually I start shivering. I think I flirted with the idea for Open Outcry but grabbed the nearest router as soon as I started doing any networking stuff. But for Activating Memory I began using a master wireless clock to sync four wired laptops during development, as my router only had four ports. I managed to get a really stable system going and kept it going for performances. To keep things looking neat on stage I’m going to stick with wireless (until it comes back to bite me).
So, for a wireless Arduino connection I’m using the Adafruit CC3000, a small breakout board. After a few days of initial head/wall banging I discovered that these boards can’t run on the same hardware SPI bus as other devices (I was using LED matrices and TFT screens). The usually helpful Adafruit guys who run their great forums were useless in letting me know this was the case until they announced that the new 1.1 version did support this feature. Money wasted I picked up the new one and all was well. To send continuous data to the Arduino without having to check it’s IP address everytime it connects to a network I needed to set a static IP to the wireless board and set it to continuously listen to data on specified ports. That way I could have multiple Arduinos listening to a master clock signal and feedback signals from associated BCI laptops or a global laptop. Using UDP I could open a socket and send data from Matlab or Pd.
These are the steps involved in setting this up.
1. Download and install the CC3000 library.
2. In the Adafruit_CC3000.cpp file add the following code:
/**********Static IP Address**************************************************/
/*!
@brief Sets a new Static IP address
@param IP Address, Subnet Mask, Default GW, DNS Server
@returns False if an error occured!
*/
/**********Static IP Address**************************************************/
long Adafruit_CC3000::setStaticIPAddress(unsigned long *aucIP, unsigned long *aucSubnetMask,unsigned long *aucDefaultGateway, unsigned long *aucDNSServer)
{
if (!_initialised)
{
return false;
}
CHECK_SUCCESS(netapp_dhcp(aucIP, aucSubnetMask, aucDefaultGateway, aucDNSServer),”Failed setting Static IP address!”, false);
wlan_stop();
delay(200);
wlan_start(0);
return true;
}
3. In the Adafruit_CC300.h file the following code in between the lines shown.
class Adafruit_CC3000 {
public:
Adafruit_CC3000(uint8_t csPin, uint8_t irqPin, uint8_t vbatPin, uint8_t spispeed = SPI_CLOCK_DIV128);
bool begin(uint8_t patchReq = 0, bool useSmartConfigData = false);
void reboot(uint8_t patchReq = 0);
void stop(void);
bool disconnect(void);
bool deleteProfiles(void);
void printHex(const byte * data, const uint32_t numBytes);
void printHexChar(const byte * data, const uint32_t numBytes);
void printIPdots(uint32_t ip);
void printIPdotsRev(uint32_t ip);
uint32_t IP2U32(uint8_t a, uint8_t b, uint8_t c, uint8_t d);
bool getMacAddress(uint8_t address[6]);
bool setMacAddress(uint8_t address[6]);
//Static IP Address Start
long setStaticIPAddress(unsigned long *aucIP, unsigned long *aucSubnetMask,unsigned long *aucDefaultGateway, unsigned long *aucDNSServer);
//Static IP Address End
bool connectToAP(const char *ssid, const char *key, uint8_t secmode);
bool connectSecure(const char *ssid, const char *key, int32_t secMode);
bool connectOpen(const char *ssid);
bool checkConnected(void);
bool checkDHCP(void);
bool getIPAddress(uint32_t *retip, uint32_t *netmask, uint32_t *gateway, uint32_t *dhcpserv, uint32_t *dnsserv);
bool checkSmartConfigFinished(void);
Adafruit_CC3000_Client connectTCP(uint32_t destIP, uint16_t destPort);
Adafruit_CC3000_Client connectUDP(uint32_t destIP, uint16_t destPort);
#ifndef CC3000_TINY_DRIVER
bool getFirmwareVersion(uint8_t *major, uint8_t *minor);
status_t getStatus(void);
uint16_t startSSIDscan(void);
void stopSSIDscan();
uint8_t getNextSSID(uint8_t *rssi, uint8_t *secMode, char *ssidname);
bool listSSIDResults(void);
bool startSmartConfig(bool enableAES);
bool getIPConfig(tNetappIpconfigRetArgs *ipConfig);
4. This allows you to set a static IP address for the CC3000. In the Arduino sketch you have to write the IP (and other network) address as reverse HEX, thankfully this website does that for you: http://www.adman.net/cisco/hexip.asp.
5. To receive data you need to set up a UDP port, bind to the socket and listen for incoming messages using recvfrom() to get packets.
6. Connect to the same network in Pd/Matlab, start sending data and you’re away.
Download the example files here. Enclosed is an Arduino sketch that receives data from a Pd patch on the same network. Voila. Check the code’s comments for how to set it all up.
This is mostly an amalgamation of info on these two online forums threads, here and here. Credit and thanks to those who made this possible.