serialEvent for high frequency for closed loop control - Arduino & Processing

Hi guys, (reposting from my issue in Arduino Forum)

I’m writing some code in Processing that interacts with an Arduino to control a robot arm. I need the closed-loop control code to run Processing with the highest frequency possible, reaching the Arduino side’s physical limit.

For that purpose, I want to use serialEvent once a data frame from Arduino is received which will trigger calculations and commands to be sent on serial back to the Arduino. The principal is illustrated in the code below (Arduino + Processing)

My problem is that somehow serialEvent is no longer triggered after several seconds and I don’t know why

Arduino Code:

char pcOutBuffer[] = "Motorboard:Present_Posistion 1 20093774343;Present_Posistion 2 20093774343;Present_Posistion 3 20093774343;"; //typical payload

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

void loop() {
  SerialUSB.readStringUntil('\n');
  delay(1); //here the arduino would apply commands from PC and fill pcOutBuffer with motor data
  SerialUSB.write(pcOutBuffer);
  SerialUSB.write('\n');
}

Processing Code:

import processing.serial.*; //Include Processing Serial

Serial myPort;                       

void setup() {
  size(256, 256);
  printArray(Serial.list());
  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 9600);
  myPort.bufferUntil('\n');
  myPort.write('\n');
}

void draw() {
}

void serialEvent(Serial myPort) {
  String strIn = myPort.readString();
  print(strIn);
  //close loop control would happen here
  println(second());
  myPort.write('\n');//command to arduino would fit here as well
}

I would like to understand what is going on to implement the highest-performance approach for my needs.

My setup :
Target is OpenCM9.04 from Robotis
Arduino IDE is the lastest 1.8 version
Processing IDE 4.3

I there anything I’m doing wrong?

Many thanks for your help

1 Like

You may not be keeping up at the receiving end.
Do the math for your BAUD rate and the size of your payload.
It is worthwhile to do some research on this.

I tested your code with a hardware serial port (not SerialUSB) and it worked with a BAUD as high as 2000000 (for testing only!)

If you want higher performance, throughout and control:

  • Increase BAUD rate. Only as high as required and testing!
  • Reduce size of your payload
  • Optimize code on receiving end
  • Consider handshaking between Arduino and Processing
  • print() to console can impact performance; only use for development
//char pcOutBuffer[] = "Motorboard:Present_Posistion 1 20093774343;Present_Posistion 2 20093774343;Present_Posistion 3 20093774343;"; //typical payload

char pcOutBuffer[] = "20093774343,20093774343,20093774343"; //typical payload

Payload can be reduced further if necessary but work on above first.

serialEvent() that I tested with:

int t, tLast;

void serialEvent(Serial myPort) 
  {
  String strIn = myPort.readString();
  print(strIn);

  //close loop control would happen here
  
  t=millis();
  println(t-tLast);
  tLast = t;
  myPort.write('\n');//command to arduino would fit here as well
  }

At some point you may need these:

:)

1 Like

Hi @glv,

Thanks a lot for your feedback! What is weird though is that my code is working fine on your setup using hardware serial instead of SerialUSB

Is there anyway you could test with SerialUSB to reproduce my error? That will defenitely pinpoint a bug in SerialUSB on Arduino side

Kind regards

Which Arduino board (other board?) are you using?

I do not have a board with native USB.

You could send me one of these and I will test it:

:)

1 Like

Hi @glv, I’m using the OpenCM9.04 from Robotis : OpenCM 9.04

Thanks for your proposal, I’ll defenitely consider it if I don’t manage to find someone on either forums :blush:

I will also try with one of my HW serial once I get a USB ftdi cable

1 Like

@glv I think I found where the problem comes from (on my side) :

I did some experiment and if have no problem sending any buffer up to 63 bytes (including ‘\n’) like :

char pcOutBuffer[] = "this is an example of a 62 characters payload which works fine";

However when reaching 64 bytes, no serialEvent are triggered on Processing side and above 64 bytes then my problem appears

Now I think can implement a proper workaround but I’m still unsure about the real explanation.

What do you think of that @glv ?

1 Like

Would it be possible to send data as comma separated values without redundant text? For example, have Processing split string to positionArray[3] ; To reinforce what has already been stated there is a lot of redundancy in

char pcOutBuffer[] = "Motorboard:Present_Posistion 1 20093774343;Present_Posistion 2 20093774343;Present_Posistion 3 20093774343;"; //typical payload

and could be shortened with comma separated values and sent as a much shorter string, eg

value1,value2,value3 followed by a line feed(accomplished by println())

The following is example Processing code which will run on an Arduino Due R3:

import processing.serial.*;

Serial myPort;    // The serial port
String inStr;    // Input string from serial port
int lf = 10;    // ASCII linefeed
String[] dataStr = new String[2];
int[] data = new int[2];

void setup() {
  surface.setVisible(false); // Output is in console at bottom of editor
  // List all the available serial ports:
  printArray(Serial.list());
  // Enter device number for your system
  myPort = new Serial(this, Serial.list()[1], 115200);
  myPort.bufferUntil(lf);
}

void draw() {
}

void serialEvent( Serial myPort) {
  //'\n' (line feed) is delimiter indicating end of packet
  inStr = myPort.readStringUntil('\n');
  //make sure our data isn't empty before continuing
  if (inStr != null) {
    //trim whitespace and formatting characters (like carriage return and/or line feed)
    inStr = trim(inStr);  //Data is sent as a string
    println("inStr =", inStr);
    String[] myData = split(inStr, ','); // String is split into array at comma
    println("array:");
    printArray(myData);
    for (int i = 0; i < myData.length; i++) {
      try {
        int parsedInt = Integer.parseInt(myData[i]);
        data[i] = parsedInt;
      }
      catch (NumberFormatException e) {
        println("Failed to parse the string as an integer.");
      }
    }
  }
}

Arduino code:

int num[2];

void setup() {
  Serial.begin(115200);
  SerialUSB.begin(115200);
}

void loop() {
  num[0] = random(255);
  num[1] = random(300, 900);
  SerialUSB.print(num[0]);
  SerialUSB.print(",");  // Comma separated values
  SerialUSB.println(num[1]); // Has a line feed.
  //Wait for a bit to keep serial data from saturating
  delay(10);
}

Note that there is no SerialUSB.write().

By the way, your code does run if you declare a baud rate on the Arduino side, eg

SerialUSB.begin(115200);

Output in my console log (macos):

And it didn’t hang; went to 59 and then reset to zero.

Great to see experimentation!
:)

Share the smallest version of code that you can so we are on the same page.
Would like to know the BAUD rate, delay between writes, etc.
Still SerialUSB?

There are Notes and Warnings here at the bottom of the page related to Serial:

I get the same results with an Arduino Uno R3 and Arduino Mega 2560 R3:

The above may not apply directly to SerialUSB and can’t test it.

I am sure you can! Serial communications can be a challenge at times.

Related:
Due - SerialUSB.write() issue - Programming Questions - Arduino Forum < some excellent suggestions in here!
Also take a look at Related Topics in topic above.

:)

Hello @Rouno,

Can you try this with your SerialUSB:

Just curious!

And I am getting an Arduino Due! Not any time soon but for future projects that would benefit from an upgrade.

:)

I get 511 on my system.