‹ redAsciiSC2 Nostalgia ›

supercolliderArduino_sendAndReceive

2014-09-26 01:34:23 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.

Attachments:
supercolliderArduino_sendAndReceive.zip
‹ redAsciiSC2 Nostalgia ›