TouchDesigner to Arduino serial communication?

tl:dr How to parse multiple live-time changing variables send to Arduino?

Hello dear banana community!

Recently I worked on a project including TouchDesigner to Arduino communication.
I faced a problem with sending multiple live-changing data from CHOP to Arduino through serial.

I have two animations that runs independently for 10s after a different triggers (null1 on the screenshot). Ewentually there will be 5 independent animations triggered by different events.

Each animation is an analogWrite value of different motor connected to Arduino.

CHOP Execute sends data to serial1 on value change. Serial1 sends it to Arduino.
I’ve done the coding based on the example from TD docs (Arduino - Derivative).

Data send from TD are being parsed on Arduino side. Here is the problem - if I send constant value, they are saved in buffer and parsed correctly, but if I send changing values, they are changing positions in buffer, so the parsing is going wrong.
(On the screenshot first animation was triggered, so first message should be changing value and second should be 0).

Is there any other way I can send five independently changing values to Arduino through serial port? Or any other way to parse them?

I’m a begginer in Arduino and Python, any help appreciated!
:banana: :banana: :banana: :banana: :banana: :banana: :banana: :banana: :banana:

Arduino code (for debug purpose I print parsed values instead of sensor values I use to trigger animations):

char buffer[13];
int len = 0;

int sensorVal1 = 0;
int sensorVal2 = 0;

int motorPin1 = 5;
int motorPin2 = 6;

int sensorPin1 = A0;
int sensorPin2 = A1;


void setup() {
  // start serial port at 9600 bps:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);

  pinMode(sensorPin1, INPUT);
  pinMode(sensorPin2, INPUT);
  //establishContact();  // send a byte to establish contact until receiver responds
}

void loop() {

  sensorVal1 = analogRead(sensorPin1);
  sensorVal2 = analogRead(sensorPin2);

  //FINAL version prints sensor values!!!
  //Serial.print(sensorVal1); Serial.print(",");
  //Serial.print(sensorVal2);

  //Serial.println(); //terminate the line

  // if we get a valid byte, read analog ins:
  if (Serial.available() > 0) {
    // get incoming byte:
    int inByte = Serial.read();
    buffer[len++] = inByte;

    //resetting
    if (len >= 13) {
      len = 0;
    }

    //check for newline
    if (inByte == '\n') {

      int motorVal1, motorVal2;
      int n = sscanf(buffer, "%d %d", &motorVal1, &motorVal2);

      //write motor when two variables red
      if (n == 2) {

        analogWrite(motorPin1, motorVal1);
        analogWrite(motorPin2, motorVal2);

        //for DEBUG print parsed values
        Serial.print(motorVal1); Serial.print(",");
        Serial.print(motorVal2); Serial.print(",");
        Serial.print("over"); Serial.print(",");

      }

    }
  }

}

Hi.
To begin I would first make sure the message coming from the Arduino ends in a newline:

Serial.print(“over”); Serial.print(“,”); becomes:

Serial.println(“over”);

Then on the TouchDesigner side, make sure you are breaking up your messages by newlines:

Row/Callback Format: One Per Line

After this, we can tell if the received messages are what’s expected, etc.

Cheers.

Thanks for answer!
Now it looks like this:

Almost every second value is assigned to wrong variable. Please send help :’ )

Here I’ve printed inByte and buffer as well

One potential issue, your buffer may not be properly null terminated at times.
Also you don’t seem to reset the buffer after receiving the newline, but randomly based on
accumulated length:

I’d try this:

//check for newline
if (inByte == ‘\n’) {
buffer[len++] = 0; ← add this
len = 0; ← add this

Hi thanks a lot!

It still doesn’t work tho.
That’s the part of code I’ve changed:

  if (Serial.available() > 0) {
    // get incoming byte:
    inByte = Serial.read();
    buffer[len++] = inByte;

    //check for newline
    if (inByte == '\n') {

      Serial.print(inByte);
      Serial.println();

      buffer[len++] = 0;
      len = 0;
      
      int n = sscanf(buffer, "%d, %d, %d, 5d, %d", &motorVal1, &motorVal2, &motorVal3, &motorVal4, &motorVal5);

      Serial.print("n=");
      Serial.print(n);
      Serial.println();
      
      if (n == 5) {

        analogWrite(motorPin1, motorVal1);
        analogWrite(motorPin2, motorVal2);
        analogWrite(motorPin3, motorVal3);
        analogWrite(motorPin4, motorVal4);
        analogWrite(motorPin5, motorVal5);

        Serial.print(motorVal1); Serial.print(",");
        Serial.print(motorVal2); Serial.print(",");
        Serial.print(motorVal3); Serial.print(",");
        Serial.print(motorVal4); Serial.print(",");
        Serial.print(motorVal5); Serial.print(",");
        Serial.println("over");
      }
    }

  }

CHOP Execute code:

def onValueChange(channel, sampleIndex, val, prev):

	motorVal1 = str(math.floor(op('null1')['chan1']))
	motorVal2 = str(math.floor(op('null1')['chan2']))
	motorVal3 = str(math.floor(op('null1')['chan3']))
	motorVal4 = str(math.floor(op('null1')['chan4']))
	motorVal5 = str(math.floor(op('null1')['chan5']))
	
	print(motorVal1 + " , " + motorVal2 + " , " + motorVal3 + " , " + motorVal4 + " , " + motorVal5)
	
	op('serial1').send(motorVal1 + " " + motorVal2 + " " + motorVal3 + " " + motorVal4 + " " + motorVal5, terminator="\n")
	
	
	return

It didn’t print motor values at all, so I assume n never equals 5.
So I’ve printed buffer and int n, it looks like this:

serial buffer n

Is your buffer still only 13 bytes?
That’s much too short for the full 5 values, commas etc.

Also:
%d, %d, %d, 5d, %d

Is that 5 a typo?

Cheers

1 Like

No, I’ve changed it to 40 and I had a typo

Omg it works now, I cannot believe it was a typo
Thanks so much for help!

1 Like

Hi there, might be a little late but I’m trying to do the same thing as you have done, do you mind sharing your final code files? I tried to work off the code posted in this thread but seem to get an error in TD serial that says that “4 bytes pending” asking me to change the Roll/Callback to One per Byte but changing it makes no difference for me.

TouchDesigner code:

# me - this DAT
# 
# channel - the Channel object which has changed
# sampleIndex - the index of the changed sample
# val - the numeric value of the changed sample
# prev - the previous sample value
# 
# Make sure the corresponding toggle is enabled in the CHOP Execute DAT.

def onOffToOn(channel, sampleIndex, val, prev):
	return

def whileOn(channel, sampleIndex, val, prev):
	return

def onOnToOff(channel, sampleIndex, val, prev):
	return

def whileOff(channel, sampleIndex, val, prev):
	return

def onValueChange(channel, sampleIndex, val, prev):
	
	motorVal1 = str(math.floor(op('null4')['chan1']))
	motorVal2 = str(math.floor(op('null4')['chan2']))
	
	print(motorVal1)
	
	op('serial1').send(motorVal1 + " " + motorVal2, terminator="\n")
	
	return
	

Arduino code:


int pulse = 0;
int len = 0;
char buffer[40];

void setup() {
  Serial.begin(9600);
  while (!Serial) {
    ;
  }

  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {

  if (Serial.available() > 0) {
    Serial.println("begin");
    int inByte = Serial.read();
    buffer[len++] = inByte;

    if (inByte == '\n') {
      int motorVal1, motorVal2;
      Serial.println(inByte);
      buffer[len++] = 0;
      len = 0;
      int n = sscanf(buffer, "%d, %d", &motorVal1, &motorVal2);

      Serial.print("n=");
      Serial.print(n);
      Serial.println();
    }
  }
}