Matlab Arduino slow serial communication

Hello everybody! I am trying to do a real-time communication with matlab and an arduino Uno. The idea is to send motor commands in PWM, and read the sensor values. But first I would want to have a real-time communication on the serial/USB.

For this reason the arduino code is waiting for the call from matlab, and depending on the type of the call the answer will be forwarded to the motor (control command) or the encoder value will be sent to the laptop (read command). The baud rate is 250000

In the matlab part I used the serial object, and I opened at a high baudrate. When I checked the timing in matlab using the profiler, it looks like the problem is not from the matlab side, but from the arduino/ or serial communication.

The problem is that for some reason I need a very small sampling time around 0.004 s. but I could not achive this, no matter how big is the baud rate. What should I change in order to have a faster communication? It is important to mention that I need a real-time control. I attached a figure, where the sampling time was 0.005, and the time differences can be seen.

For a better understanding here is the arduino code:

// Receive with an end-marker

const byte numChars = 8;
char receivedChars[numChars]; // an array to store the received data
int numb = 0;
boolean newData = false;

void setup() {
Serial.begin(250000);
Serial.setTimeout(100);
//Serial.println("");
}

void loop() {
recvWithEndMarker();
showNewData();
}

void recvWithEndMarker() {
static byte ndx = 0;
char endMarker = ‘>’;
char rc;

while (Serial.available() > 0 && newData == false) {
rc = Serial.read();

if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = ‘\0’; // terminate the string
ndx = 0;
newData = true;
}
}
numb = atoi(receivedChars);
}

void showNewData() {
if (newData == true) {
if (numb==256)
Serial.println(numb);
newData = false;
}

}

And here is the MATLAB code

for k = 1:N,
% time(k)
alpha(k) = utread;
%simple constant input, here goes the control algorithm
% u(k) = (-1 + k/255);
u(k) = sign(mod(k,5)-2);
% for aaa=1:100
% 1+2;
% end
utwrite(u(k));
%synchronize, wait for next sample time
time(k+1) = toc;
while(time(k+1)<(time(k)+Ts))
time(k+1) = toc;
end
end

for simplicity I put just the most important part.
and utread is a function having the form:

global utip

% read angular position
fprintf(utip.s,‘256>’);
dat = fscanf(utip.s,’%d’);
while (isempty(dat)) % wait for data on the serial
fprintf(utip.s,‘256>’);
dat = fscanf(utip.s,’%d’);
end

I modified your code a little to do a timing of the receive

// Receive with an end-marker

const byte numChars = 8;
char receivedChars[numChars];   // an array to store the received data
int numb = 0;
boolean newData = false;

void setup()
{
  Serial.begin(250000);
}

void loop()
{
  recvWithEndMarker();
  showNewData();
}

unsigned long startTime, endTime;

void recvWithEndMarker()
{
  static byte ndx = 0;
  char endMarker = '>';
  char rc;

  while (Serial.available() > 0 && newData == false)
  {
    if (ndx == 0)
    {
      startTime = micros();
    }
    rc = Serial.read();

    if (rc != endMarker)
    {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= numChars)
      {
        ndx = numChars - 1;
      }
    }
    else
    {
      receivedChars[ndx] = '\0'; // terminate the string
      ndx = 0;
      endTime = micros();
      newData = true;
    }
  }
}

void showNewData()
{
  if (newData == true)
  {
    Serial.print("Duration = ");
    Serial.println(endTime - startTime);
    newData = false;
  }

}

Sending 256> from serial monitor and the resulting duration for the receive is 124 (also saw 128) microseconds; far faster than your requirement of 4 milliseconds.

You basically should move numb = atoi(receivedChars); to if block in showNewData(). Or at least wait till you have the full string received in the receive routine.

ZoltanN:

// Receive with an end-marker

const byte numChars = 8;

///.........

void recvWithEndMarker() {
  //.........
   numb = atoi(receivedChars);
}

You should not put that sort of thing in the recvWithEndMarker() function. You should only parse the data after recvWithEndMarker() sets newData = true to signal that the complete message has been received. You could but it into the showNewData() function but, logically, it should really be in a function that clearly describes its purpose such as

void convertData() {
   if (newData == true) {
       numb = atoi(receivedChars);
   }
}

which should be called from loop() before calling showNewData()

...R

EDIT to add a test for newData == true which I had foolishly forgotten until reminded by @PaulS

which should be called from loop() before calling showNewData()

Since that function, unlike showNewData(), does not test that there IS new data to process, be sure to test that there IS new data before calling that function.

PaulS:
Since that function, unlike showNewData(), does not test that there IS new data to process, be sure to test that there IS new data before calling that function.

Thanks for that Paul. I have updated Reply #2

...R

Thanks for all of you for the answers!

Based on the first comment (sterretje), I tested what you were suggesting, but the problem is that, you only measure how much time is necessary for the serial read from the arduino part. What I would like to do is to have 4 ms for an entire cycle, which contains the followings:

  1. starts from the matlab side, matlab sends a read command (256>)
  2. matlab receives a message (encoder value)
  3. based on that calculates a command for the motor on the matlab side
  4. matlab sends the motor command to the arduino

So that is how a full cycle should look like. And it should only take 4ms.

I read somewhere that Arduino Uno not uses FTDI but an atmega16u chip for serial-USB conversion, which has a latency about 4 ms. Is it possible to hack that and reduce it to 1ms? There are plenty of possiblities with the FTDI, but not with the Atmega16u.

Thank you for the other comments, this is just a skeleton from the actual code, only including the serial communication part. The main purpose will be to control a Maxon motor, and read the encoder values.

The main issue now, what I am focusing on, is that if I only use the serial communication (not including the motor control, encoder read part) by default it doesen't have a fast enough sampling.

ZoltanN:

  1. starts from the matlab side, matlab sends a read command (256>)
  2. matlab receives a message (encoder value)
  3. based on that calculates a command for the motor on the matlab side
  4. matlab sends the motor command to the arduino

[....]

that if I only use the serial communication (not including the motor control, encoder read part) by default it doesen't have a fast enough sampling.

That sounds like you want to build a system with closed-loop speed control.

I would not involve Matlab in that. Put all the speed control code in the Arduino and then all Matlab needs to do is occasionally send the data for the speed the motor needs to run at. In other words put all the parts 2, 3 and 4 within the Arduino.

...R

I suspect that your timing cycle could be controlled by matlab, not by the Arduino.

sterretje:
I suspect that your timing cycle could be controlled by matlab, not by the Arduino.

? ?

...R

As far as I understand it. OP wants to send a command to Arduino from matlab every 4 ms.

sterretje:
As far as I understand it. OP wants to send a command to Arduino from matlab every 4 ms.

Indeed.

And it is my opinion that that is not the correct way to approach this problem - which seems to be closed-loop control of motor speed.

...R