supercolliderArduino_sendAndReceive
2014-09-26 01:34
supercollider
clean-up: #33
Below is some SuperCollider code for sending and receiving data from an Arduino. It is a good example I think and worth sharing. It can be used as a template for when you want to read and write at the same time.
As the example is written SuperCollider writes data to six PWM channels (0-255) and reads data from six analogue inputs (also 0-255). The sliders are the PWM output controllers, and the sensor input data is just posted as an array.
//supercolliderArduino_sendAndReceive /f0
// controlling 6 PWM channels and reading 6 analogue inputs at the same time
// use with SC code supercolliderArduino_sendAndReceive.scd
//--serial protocol
// PWM SC->Arduino: 10 nn nn nn nn nn nn 11 (nn bytes 1-6= PWM channels 0-5)
// ADC Arduino->SC: 20 nn nn nn nn nn nn 21 (nn bytes 1-6= analogue channels 0-5)
//--settings
byte pwmPins[]= {5, 3, 9, 6, 11, 10};
byte adcPins[]= {0, 1, 2, 3, 4, 5}; //A0-A5
//--variables
boolean changed;
byte val, cnt= 0;
byte pwmData[]= {0, 0, 0, 0, 0, 0, 0, 0};
byte adcData[]= {0, 0, 0, 0, 0, 0, 0, 0}; //for detecting change and filter out repetitions
void setup() {
Serial.begin(38400); //baud rate must match in SC
for(byte i= 0; i<6; i++) {
pinMode(pwmPins[i], OUTPUT);
pinMode(adcPins[i], INPUT);
}
}
void loop() {
//--from SC
while(Serial.available()) {
val= Serial.read();
if(cnt==0) {
if(val==10) { //beginning of message found
cnt= 1; //start counter
}
} else if(cnt<7) { //between 1 and 6 means message started and that bytes should be saved
pwmData[cnt-1]= val; //saving incoming bytes in temporary data array
cnt++;
} else {
if(val==11) {
for(byte i= 0; i<6; i++) {
analogWrite(pwmPins[i], pwmData[i]); //output read message to PWM pins
}
} else {
//serial read error
}
cnt= 0; //reset byte counter
}
}
//--to SC
changed= false;
for(byte i= 0; i<6; i++) {
val= analogRead(adcPins[i])>>4; //scale from 10 to 8 bits
if(val!=adcData[i]) {
adcData[i]= val;
changed= true;
}
}
if(changed) { //check if any sensor changed
Serial.write(20);
Serial.write(adcData[0]);
Serial.write(adcData[1]);
Serial.write(adcData[2]);
Serial.write(adcData[3]);
Serial.write(adcData[4]);
Serial.write(adcData[5]);
Serial.write(21);
}
delay(10); //wait 10 milliseconds
}
//--use with supercolliderArduino_sendAndReceive.ino
//SuperCollider code for reading 6 analogue sensors and sending out to 6 PWM channels
SerialPort.listDevices; //run this and see post window for the name of serial device
//--GUI code for sending 6 PWM
(
var name= "/dev/tty.usbserial-A101NB76"; //edit to match your serial device
var port= SerialPort(name, 38400, crtscts: true);
var pwm= [10, 0, 0, 0, 0, 0, 0, 11];
var win= Window("pwm", Rect(99, 99, 260, 200), false);
Slider(win, Rect(10, 10, 30, 170)).action_{|view| pwm.put(1, (view.value*255).asInteger); port.putAll(pwm.postln)};
Slider(win, Rect(50, 10, 30, 170)).action_{|view| pwm.put(2, (view.value*255).asInteger); port.putAll(pwm.postln)};
Slider(win, Rect(90, 10, 30, 170)).action_{|view| pwm.put(3, (view.value*255).asInteger); port.putAll(pwm.postln)};
Slider(win, Rect(130, 10, 30, 170)).action_{|view| pwm.put(4, (view.value*255).asInteger); port.putAll(pwm.postln)};
Slider(win, Rect(170, 10, 30, 170)).action_{|view| pwm.put(5, (view.value*255).asInteger); port.putAll(pwm.postln)};
Slider(win, Rect(210, 10, 30, 170)).action_{|view| pwm.put(6, (view.value*255).asInteger); port.putAll(pwm.postln)};
win.front;
CmdPeriod.doOnce({port.putAll([10, 0, 0, 0, 0, 0, 0, 11]); port.close; win.close});
//press cmd+. to stop and close window and serial port
s.waitForBoot{
var byte, num= 6, index= 0, data= Array.newClear(num);
Ndef(\arduino, {|data= #[0, 0, 0, 0, 0, 0]| Splay.ar(SinOsc.ar(data.lag(0.02)+500, 0, 0.4))}).play; //temp sound
Routine.run({
inf.do{
while({byte= port.read; byte.notNil}, {
//byte.postln; //debug
if(index==0 and:{byte==20}, { //check if first byte is 20
index= 1;
}, {
if(index>=1 and:{index<(num+1)}, { //ok, now start collecting bytes
data[index-1]= byte;
index= index+1;
}, {
if(index==(num+1) and:{byte==21}, { //until last data byte
data.postln; //debug
Ndef(\arduino).setn(\data, data);
index= 0; //done. reset index to prepare for new message
}, {
//something broke or beginning - restart
"restart".postln; //debug
index= 0;
});
});
});
});
};
});
};
)
I also attached the complete example as a zip file.