Help with serial communication

Hi,
First post. I’m an intermediate level programmer but relatively new to Processing. I have a Processing program on my desktop that sends a sequence of commands to an Arduino board by the serial port (actually a Teensy 3.6, but I dont’ think that matters.) The Arduino, upon receiving the commands, executes a series of further commands to stepper motors and servos. Depending upon the state of the servo/stepper machine and the commands, execution time is variable.

I have had no difficulty with sending commands to the Arduino and having them execute correctly. However, I’m trying to write a method that uses stacked commands-- send first mechanical command, let it finish executing, then send the second command, let it finish executing, etc. On the Arduino side, I’d write code that sent the Processing sketch some form of “finished message” when mechanical execution was complete, and I could then proceed to the second command. I thought that if I wrote code along the lines of

sendFirstCommand();
while (myPort.available()==0) {
} //loops until it receives data from Arduino
sendSecondCommand();

I understand that the while loop can be problematic in that it can be blocking, but I really don’t have a better idea. I also thought that if I were querying the serial port to test for termination conditions, that it would force an update. I’ve been able to get the stacked commands to work by using a delay() call instead of the while loop, where the delay() parameter is the longest time it would realistically take for the mechanics to execute. Feels a bit heavyhanded and not portable. When no delay is inserted, the second command is simply lost.

Feels like there is something simple I’m missing… Help would be appreciated.
Thank you.

2 Likes

For what it is worth, I found an answer myself that is a little kludgy but works. After some experimentation, it became clear that the while() loop was interfering with event processing, including serial events. However, a for(…) loop does not. The following would not work in code that needed a rapid response to user input, but mine does not.
Assume for the purposes of this example that there is a boolean global variable, “ready”, that is controlled by actions outside the for() loop. In the specific instance here, if we receive a specific text string from the Arduino, we know that the action is complete and we are ready to move on to the next command. When the specific text string is received, ready is set to true.
We also know the longest that a response from the Arduino should or would take. In this case, maximum would be two minutes. There’s likely more elegant ways to do this, but here goes:

ready = false;  //set to false before entering loop
sendFirstCommand();
for (int i = 0; i < 2401; i++) {
if (ready == true) //affected by process outside the loop, serial data coming to processing
break;
delay(50);
if ( i == 2400) {
println("Procedure on Arduino timed out");
}
}
if (ready == true)
sendSecondCommand();
else
myHandleErrorRoutine();

Note that there is an added benefit of having a timeout that can be set. I hope this is of value to someone.

1 Like

Hello,

This discusses “handshaking” between Processing and Arduino:

https://learn.sparkfun.com/tutorials/connecting-arduino-to-processing/all

:)

2 Likes

Thank you, glv. I saw that too. After playing with it a bit, I decided to use the approach I outlined above because it gave me the time out advantage. That article, though is where I got started. It’s very clear and you are right that it’s a great starting point.
Cheers,
Ed

1 Like

Not an Arduino developer, but if I’m understanding your issue here…

The key thing is that Processing event handling happens each time draw() returns. draw() is your “while” loop. So take the things that you would put in a while, and put them in draw(). This will process commands at your frameRate() fps (e.g. 60/second). When nothing is available, it will keep looping. Your sketch will also stay responsive the whole time.

void draw() {
  if(myPort.available()!=0) sendNextCommand();
}

EDIT and/or, put your handing in the (library) event callback – and draw, which is your loop, will repeatedly call that handling.

Hello,

I wrote a simple example.

Arduino sends data every 1000ms +/- 200ms (random).

Arduino Code
void setup()
  {
  Serial.begin(9600);
  }

void loop()
  {
  for(int i=0; i<256; i++)
    {
    int ran = random(0, 200);   
    delay(1000 + int(ran));
    Serial.write(i);
    }
  }

Processing receives data and prints messages and changes background depending on time since last event.

Processing Code
// Receive serial data and visualize
// v1. 0. 0
// GLV 2020-05-03

import processing.serial.*;

Serial serialPort;

int timeNow, timeLast, timeDiff;
color col;

void setup()
  {
  size(200, 200);

  // List all the available serial ports:
  printArray(Serial.list());

  String portName = Serial.list()[4];
  serialPort = new Serial(this, portName, 9600);
  timeLast = millis();
  }

void draw() 
  {
  background(col);
  }

void serialEvent(Serial serialPort) 
  {
  int inByte = serialPort.read();

  timeNow = millis();
  timeDiff = timeNow - timeLast;
  
  println(inByte, timeDiff);
  
  if (timeDiff > 1000+100) 
    {
    println("time > 1100");
    col = color(255, 0, 0);
    }
    
  else if (timeDiff < 1000-100) 
    {
    println("time < 900");    
    col = color(255, 0, 0);
    }
  
  else 
     {
     println("900 <= time <= 1100"); 
     col = color(0, 255, 0); 
     }
  
  timeLast = timeNow;
  }
1 Like

Thanks for that link @glv - very helpful for the project I’m working on.

Thanks everyone for their thoughtful and helpful replies. I will need to explore the draw() loop more because I suspect I don’t understand it fully, and here’s why: I do understand a straightforward main event loop and use it extensively for event dispatching on Arduino. There seem to be two confounding issues for me. First, if one chooses to use it, there’s a second potential event loop based on serial events. This is invoked by putting a call to mySerialPort.buffer() or mySerialPort.bufferUntil() in setup() and then constructing an appropriate SerialEvent() function. This has proven to be quite useful for me in other parts of the program, and I’m reluctant to part with it.
The second, perhaps less esoteric issue is that I’m using Quark’s G4P library for a GUI. The control items that can receive user input (generally typing or mousing) handle actions with listener functions. I suspect I don’t fully understand how a listener function is triggered with respect to the draw() loop. More research and reading needed, I guess.
Again, thank you all.

1 Like

I would be tempted to use timers here rather than the delays.
The java.util.Timer and java.util.TimerTask classes.
Usage examples here : https://www.iitk.ac.in/esc101/05Aug/tutorial/essential/threads/timer.html

A system that I have running involves a large number of (not arduino) but AVR MCUs on a network, comms speed and reliability is important, I was finding the serialEvent() unreliable at speed.

So I use a “system tick” generated from timer.scheduleAtFixedRate(new task(), delay, period)
with an initial delay for comms to “start up and settle”, this then polls the serial port for new data (in the format expected).

Part possibly most relevant to your setup:
When data is sent out onto the network a “TimeOut” timer is started running using .util.TimerTask. If we don’t hear back within the expected period the timer task sets a timeout flag. Which can then be used to do whatever you need.

Hope that helps a bit…

1 Like