MATLAB - Arduino Serial Communication

Hi all?

Firstly, I really hope that all of you guys are safe and healthy due to this emergency that we are facing up.

I'm writing about a problem with the Interfacing Arduino with MATLAB. For some reasons I need to reach really high sampling rate in MATLAB, in particular, because I'm going to record some EMG data through 2 Arduino analogue channels, and EMG signal needs to sampled at 10KHz for good quality, which means 10000 samples/sec.

Currently, I'm using Arduino Nano or M0. For the last one, I've uploaded some code that needs to get Data from IMUs (inertial measurements unit) and send data to MATLAB and there I'm able to reach 100 Hz that is good enough for motion extraction.
The idea is to send a trigger from the M0 (using as a Master) to the Nano one (as Slave) in order to start the EMG recording when the user asks for that.
For this, I have no still clear idea of how to reach this problem, but for now is not the main topic. Of course, if you have any suggestions, please let me know.

Now the problem is that I set up TCCR1A and TCCR1B registers in Arduino nano in order to overflow the interrupt over 10KHz, and I even modified ADC's Prescaler in order to have the availability to transduce analog data when needed. Here the code, please if you have any suggestions to improve let me know:

const unsigned char PS_2 = (1 << ADPS0) ;
const unsigned char PS_4 = (1 << ADPS1) ;
const unsigned char PS_8 = (1 << ADPS1) | (1 << ADPS0) ;
const unsigned char PS_16 = (1 << ADPS2);
const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0);
const unsigned char PS_64 = (1 << ADPS2) | (1 << ADPS1);
const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);

void setup()
{
   TCCR1B = 0;
   TCCR1A = 0;
   TCCR1B |= (1<<CS10); // prescaler 1
   TIMSK1 |= (1<<TOIE1); // enable timer overflow
   TCNT1 = 63936; // (65536-(f_clock/(prescaler*f_target))
   ADCSRA &= ~PS_128;
   ADCSRA |= PS_4;
   Serial.begin(115200);
   pinMode(A0, INPUT);
}

ISR(TIMER1_OVF_vect) {
    Serial.println(analogRead(A0));
    Serial.println(analogRead(A1));
    TCNT1 = 63936;
  }

Then, the problem is in Serial.println() function, I guess. This is the part that should take a lot and decrease the speed of my communication.

To sort out that do you have guys any suggestions? Is there any possibility to communicate directly with MATLAB and increase the velocity? I'd like to try Serial.write(), but I think doesn't change a lot more.

I'm happy to hear another possibility to save data (avoiding MATLAB it's fine) provided to have synchronized Data between EMG and IMUs.

Please if something else to understand the situation is needed, feel free to let know.
Your help would be really appreciated.

Thanks a lot.

Using an 8-bit, 16MHz Nano with a 10-bit ADC probably isn't ideal for fast data sampling. You'd probably be better off with something like a 32-bit, 120MHz Teensy 3.5 with a 16-bit ADC. I've been able to get analog data with a Teensy 3.5 at rates over 20KHz.

You'll probably also want to use a higher, baud.

All things considered, however, I can't seem to find your actual question... Is there something specifically you are having trouble with? What is currently going wrong with your project?

Power_Broker:
Using an 8-bit, 16MHz Nano with a 10-bit ADC probably isn't ideal for fast data sampling.

Actually I'm fine with this resolution and with this velocity of the ADC. I mean, changing Prescaler I have one conversion each 8us more or less, which is good enough. The problem, I think, is not regarding the features of the velocity operations in Nano.

Power_Broker:
All things considered, however, I can't seem to find your actual question... Is there something specifically you are having trouble with? What is currently going wrong with your project?

The problem is the following: How can I do to transfer Data to MATLAB at 10KHz? Or maybe saving Data in other ways provided that could be recalled through MATLAB for off-line analysis?
The problem is about the Serial Communication, I need to reach 10KHz.

Thank you a lot.

Hi all?

Firstly, I really hope that all of you guys are safe and healthy due to this emergency that we are facing up.

I'm writing about a problem with the Interfacing Arduino with MATLAB. For some reasons I need to reach really high sampling rate in MATLAB, in particular, because I'm going to record some EMG data through 2 Arduino analogue channels, and EMG signal needs to sampled at 10KHz for good quality, which means 10000 samples/sec.

Currently, I'm using Arduino Nano or M0. For the last one, I've uploaded some code that needs to get Data from IMUs (inertial measurements unit) and send data to MATLAB and there I'm able to reach 100 Hz that is good enough for motion extraction.
The idea is to send a trigger from the M0 (using as a Master) to the Nano one (as Slave) in order to start the EMG recording when the user asks for that.
For this, I have no still clear idea of how to reach this problem, but for now is not the main topic. Of course, if you have any suggestions, please let me know.

Now the problem is that I set up TCCR1A and TCCR1B registers in Arduino nano in order to overflow the interrupt over 10KHz, and I even modified ADC's Prescaler in order to have the availability to transduce analog data when needed. Here the code, please if you have any suggestions to improve let me know:

const unsigned char PS_2 = (1 << ADPS0) ;
const unsigned char PS_4 = (1 << ADPS1) ;
const unsigned char PS_8 = (1 << ADPS1) | (1 << ADPS0) ;
const unsigned char PS_16 = (1 << ADPS2);
const unsigned char PS_32 = (1 << ADPS2) | (1 << ADPS0);
const unsigned char PS_64 = (1 << ADPS2) | (1 << ADPS1);
const unsigned char PS_128 = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);

void setup()
{
   TCCR1B = 0;
   TCCR1A = 0;
   TCCR1B |= (1<<CS10); // prescaler 1
   TIMSK1 |= (1<<TOIE1); // enable timer overflow
   TCNT1 = 63936; // (65536-(f_clock/(prescaler*f_target))
   ADCSRA &= ~PS_128;
   ADCSRA |= PS_4;
   Serial.begin(115200);
   pinMode(A0, INPUT);
}

ISR(TIMER1_OVF_vect) {
    Serial.println(analogRead(A0));
    Serial.println(analogRead(A1));
    TCNT1 = 63936;
  }

Then, the problem is in Serial.println() function, I guess. This is the part that should take a lot and decrease the speed of my communication.

To sort out that do you have guys any suggestions? Is there any possibility to communicate directly with MATLAB and increase the velocity? I'd like to try Serial.write(), but I think doesn't change a lot more.

I'm happy to hear another possibility to save data (avoiding MATLAB it's fine) provided to have synchronized Data between EMG and IMUs.

Please if something else to understand the situation is needed, feel free to let know.
Your help would be really appreciated.

Thanks a lot.

You're sending 8-bit values. So Serial.write() should do.

10,000 8-bit samples equals 100,000 bits per second. So a baudrate of 115200 should be sufficient.

In the Serial Monitor you have the option to set a baudrate of 2,000,000. So your Arduino board is (should be) able to send at 2MB/sec; this equals 200,000 8-bit samples / second. Not sure what is supported by MatLab.

If you use text (Serial.println()), the maximum number of characters in a packet representing the 8-bit value is 5 characters. So 200,000 / 5 = 40,000 samples / second.

Overlapping/duplicate/inappropriately posted topics moved and merged

Cross-posting is against the rules of the forum. The reason is that duplicate posts can waste the time of the people trying to help. Someone might spend 15 minutes (or more) writing a detailed answer on this topic, without knowing that someone else already did the same in the other topic.

Repeated cross-posting will result in a timeout from the forum.

In the future, please take some time to pick the forum board that best suits the topic of your question and then only post once to that forum board. This is basic forum etiquette, as explained in the sticky "How to use this forum - please read." post you will find at the top of every forum board. It contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.

UKHeliBob:
Thanks in advance for your cooperation.

Sorry so much. Really sorry, I'm very sorry. This won't happen anymore. I had just realized that the Data Storage was more appropriate section for my topic. Sorry again.

sterretje:
You're sending 8-bit values. So Serial.write() should do.

10,000 8-bit samples equals 100,000 bits per second. So a baudrate of 115200 should be sufficient.

In the Serial Monitor you have the option to set a baudrate of 2,000,000. So your Arduino board is (should be) able to send at 2MB/sec; this equals 200,000 8-bit samples / second. Not sure what is supported by MatLab.

If you use text (Serial.println()), the maximum number of characters in a packet representing the 8-bit value is 5 characters. So 200,000 / 5 = 40,000 samples / second.

I think my explanation was not the best. I need to send 2 analogue reading each time. So basically, based on datasheet I changed prescaler of ADC in order to get one conversion in 8us more or less.
I already settled up the TCTNT counter to reach overflow with 10KHz.
Until here, is all right in my code?

Now the problem is with the communication with MATLAB. 2 analogue conversion means that each reading has 10bit and then to transfer through Serial.Write() I need to split the register in High and Low because serial.write() only is able to transfer 8 bit each time. Is that right?

So, I have H and L for each reading which means 4 byte to be transfered every overflow (iteration). To have a consistent communication along time, I need to transfer at 400000 bits per second (4bytes every 10000 times in a second) so the Baud that I need should be greater than 400000. Is that right?

And, is that possible?

Please let me know if something in my description was wrong.
Your help is very really appreciated.

valerio101010:
I need to split the register in High and Low because serial.write() only is able to transfer 8 bit each time. Is that right?

Yes

valerio101010:
So, I have H and L for each reading which means 4 byte to be transfered every overflow (iteration). To have a consistent communication along time, I need to transfer at 400000 bits per second (4bytes every 10000 times in a second) so the Baud that I need should be greater than 400000. Is that right?

4 bytes = 32 bits. Total throughput = 32 bits * 10,000 Hz = 320,000 bps (minimum baud)

Power_Broker:
4 bytes = 32 bits. Total throughput = 32 bits * 10,000 Hz = 320,000 bps (minimum baud)

Then 115200 as Baud rate is not enough?
Do you think is it possible to communicate with 400000 with MATLAB?

Do you have any other suggestions?

I'd use 1 Million baud and give it a test. MATLAB serialport objects can be configured with any baud you want.

My previous suggestions still stand.

Power_Broker:
I'd use 1 Million baud and give it a test. MATLAB serialport objects can be configured with any baud you want.

Actually I tried, but I don't know how to verify the quality of the communication. Any suggestions?

Power_Broker:
My previous suggestions still stand.

Do you mean to use another Arduino? Yes, I have another Arduino 32 bit, 48MHz. The M0, that is very performant. But the problem is that there I have to communicate with some other sensors. Is there any way to kind of split the Serial communication? I'm trying to explain better.

So in M0, I have uploaded some code that has to get raw IMUs Data and transfer each 10ms (100Hz) 54 bytes + timestamp to MATLAB. That's because of I'using three 9-axis IMUs (3 axis acc + gyro + mag, and in total 27 measurements each iteration which means, dividing in High and Low register, 54 bytes each iteration, more the one for the timestamp).

Now, my idea is to leave loop cycle in that way (as explained above) and to use overflow interrupt(as I'm currently doing with the Nano one) to send EMG's data at 10 kHz.

Do you think could work guys? If yes, How can I do to say to MATLAB like: "Ok here you have the IMU data and in parallel, here you have EMG data". It's something like multithreaded process, as a pipeline. And to be honest, I have no idea how to code that.

valerio101010:
Actually I tried, but I don't know how to verify the quality of the communication. Any suggestions?

What do you mean? Does the data in MATLAB make sense when printed real-time? NOTE: Without some sort of packet system, there's virtually no way to ensure 100% reliable serial communication. See Serial Input Basics and Serial Input Advanced.

An aside: Why use MATLAB when you can use Python?

valerio101010:
Do you think could work guys? If yes, How can I do to say to MATLAB like: "Ok here you have the IMU data and in parallel, here you have EMG data". It's something like multithreaded process, as a pipeline. And to be honest, I have no idea how to code that.

I don't understand your setup fully tbh. Are both Arduinos connected to MATLAB with one USB port each or does one report it's data to the "master" Arduino? Also, what exactly do you not know how to code - the MATLAB or Arduino portion?

I don't use real-time communication, but I need just to save Data for off-line analysis. So, I don't really know how to understand if these data are reliable.

For python, tbh I never used it. But, I can start. Which are the advantages? Is there any advantage of the reliability and the velocity of Serial Communication? However, I need to do analysis post-processing in MATLAB.

For my setup, yes. I can explain better.
So basically I have 3 IMUs connected to Arduino M0 and currently they send data at 100Hz (I2C protocol), in the close future I have to connect 2 more sensors (EMG sensors) which have one analogue output each. I'd like to connect these sensors to another Arduino, the nano one.
Now, the idea is to use the MATLAB as master and the two Arduino as slaves.
The idea is: Arduino M0 continuously sending data, and when MATLAB wants to start the communication opening the object serialport.

Now should be possible 2 ideas:

  1. Using Arduino M0 to send a trigger to Arduino Nano and then start another communication through the second serialport object in MATLAB. If I went for that I would have to create 2 object serialport in MATLAB. Is it right?
  2. Don't connect EMG sensors to Nano, but directly to M0. For this idea, I have to figure out a way to set a kind of code priority. So, I have the loop function (without using interrupt overflow but just play around with millis()) that works for IMU Data and send to SerialPort each 10 ms, and I should have interrupt overflow set up at 10KHz as sampling rate that sends EMG data to Serial Port each 100us (10KHz). Now, here the object is the same and even is the same the COM port because Arduino is properly the same. How can I do to understand data which belongs to in serial communication? Ideally, I'd have Arduino sends data using Serial.Write, but the bus of communication is the same, so practically how can I do to differ the that and assign, let's say: Ok you are from EMG, and you are from IMU.
    So, someone any suggestions? Because of course this is a more standalone solution, but I don't have idea how to sort out. I'm not able to sort out the code for both of them for this solution.

I don't know if now is clearer if no please feel free to ask any questions.

Thanks guys.

Ok, that makes sense.

valerio101010:
I don't use real-time communication, but I need just to save Data for off-line analysis. So, I don't really know how to understand if these data are reliable.

You'll have to do some real-time testing to be sure unless you can create some sort of "truth profile" that you can test against. For instance, if you're testing an IMU output, your "truth profile" could be:

  • Points up for 1 second
  • Points left for 2 seconds
  • Points down for 1 second

In which case you would move the IMU during the test with your hands or servos and read the saved data to see if it matches what you expect.

valerio101010:
For python, tbh I never used it. But, I can start. Which are the advantages? Is there any advantage of the reliability and the velocity of Serial Communication? However, I need to do analysis post-processing in MATLAB.

Python can most likely handle the post-processing, but I won't derail the thread with it.

valerio101010:

  1. Using Arduino M0 to send a trigger to Arduino Nano and then start another communication through the second serialport object in MATLAB. If I went for that I would have to create 2 object serialport in MATLAB. Is it right?

Yes, if you have 2 USB ports, you should use 2 serialport objects.

valerio101010:
2. Don't connect EMG sensors to Nano, but directly to M0. For this idea, I have to figure out a way to set a kind of code priority. So, I have the loop function (without using interrupt overflow but just play around with millis()) that works for IMU Data and send to SerialPort each 10 ms, and I should have interrupt overflow set up at 10KHz as sampling rate that sends EMG data to Serial Port each 100us (10KHz). Now, here the object is the same and even is the same the COM port because Arduino is properly the same.

This is probably the best out of the two solutions IMHO. It might be easier for you to not worry about interrupts and simply use a software timer. You can then use the timer to figure out when to sample the sensors of all types and send a consolidated packet to MATLAB every 100us. This is assuming that polling all the sensors and transmitting the packet will take less than 100us to accomplish (combined). If not, your Arduino/comm methods are too slow.

valerio101010:
Ideally, I'd have Arduino sends data using Serial.Write, but the bus of communication is the same, so practically how can I do to differ the that and assign, let's say: Ok you are from EMG, and you are from IMU.
So, someone any suggestions? Because of course this is a more standalone solution, but I don't have idea how to sort out. I'm not able to sort out the code for both of them for this solution.

That's why I suggested using a packet system. Did you read through the two tutorials I linked in my previous reply?

valerio101010:
Ideally, I'd have Arduino sends data using Serial.Write, but the bus of communication is the same, so practically how can I do to differ the that and assign, let's say: Ok you are from EMG, and you are from IMU.
So, someone any suggestions? Because of course this is a more standalone solution, but I don't have idea how to sort out. I'm not able to sort out the code for both of them for this solution.

I did not read Power_Broker's serialtransfer; quite sure that the below is what he's / she's referring to.

The basics are simple; you send an identifier followed by the data e.g.

for data from the one source

01 aa bb cc dd

for data from the other source

02 aa bb cc dd

The 01 and 02 identify the source and your PC application can determine what the source of the data is based on that.

In theory, it would be better to consolidate all the data into a single packet if all sensors will be read at the same interval. You would have a packet that looks like this:

<Sensor 1 Data LSB> <Sensor 1 Data MSB> (etc. for n number of sensors)

Assuming you get a full and "uncorrupt" packet, you can figure out what data is which based on their byte position alone. Adding an 8-bit CRC field would also help. Again, I can't stress enough the importance of learning and understanding both tutorials I linked - they have better explanations than you can find here, lol.

Power_Broker:
In which case you would move the IMU during the test with your hands or servos and read the saved data to see if it matches what you expect.

I did that and actually looks that IMU data are fine, quite good.

Power_Broker:
It might be easier for you to not worry about interrupts and simply use a software timer.

Do you think this library is quite robust to transfer data at 100 Hz and 10KHz from the same board but different kind of data? I mean, I went through your library (and I think it's very useful for who hasn't such an important need to pay high attention in timing) and what I saw is that you commonly use mills() and micros() functions, which is good, but do these functions itself increase delays along time? For my application, one microsecond of delay means 100 samples of error (sampling at 10 kHz). I don't think is the most robust solution. What do you think you guys? Does make any sense for you?

Power_Broker:
That's why I suggested using a packet system. Did you read through the two tutorials I linked in my previous reply?

Yes, I went through. Maybe I'll re-go. But still, no clear idea how to send Data through the same SerialPort object at different timing.

sterretje:
The 01 and 02 identify the source and your PC application can determine what the source of the data is based on that.

That's a good start, but now the questions are:

  1. How can I do to use different timing for different data?
  2. In MATLAB, I have to use just one big matrix to save data? Because, as I mentioned in #10 I have to transfer Data from IMU (54 bytes per iteration) and from EMG (4 bytes for iteration).

Power_Broker:
In theory, it would be better to consolidate all the data into a single packet if all sensors will be read at the same interval. You would have a packet that looks like this:

<Sensor 1 Data LSB> <Sensor 1 Data MSB> (etc. for n number of sensors)

Assuming you get a full and "uncorrupt" packet, you can figure out what data is which based on their byte position alone. Adding an 8-bit CRC field would also help. Again, I can't stress enough the importance of learning and understanding both tutorials I linked - they have better explanations than you can find here, lol.

The sensors have to be read at different timing, that's the point. (EMG 10KHz and IMU 100Hz).
What do you mean with 8-bit CRC.

Guys, I need to underline. I'm not the best in embedded programming and I'm still improving my skills about that. And then, sorry if sometimes my questions are stupid, but something that for you is immediate, for me maybe isn't.
Your help is really appreciated and I think that at the end of this thread I'll sort out my problem.
Thank you a lot.

  1. How can I do to use different timing for different data?

So every 100us you send EMG data starting with a 0x01 from (4 plus 1 byte) and every 10ms you send IMU data with a 0x02 (54 plus 1 byte). As Power_Broker explained, a well defined protocol with e.g. a checksum is preferable.

  1. In MATLAB, I have to use just one big matrix to save data? Because, as I mentioned in #10 I have to transfer Data from IMU (54 bytes per iteration) and from EMG (4 bytes for iteration).

When you receive a packet starting with a 0x01, you store it in one array/matrix; when you receive a packet starting with a 0x02, you store it in another array/matrix;

I understood to use kind of label to save properly data, but what I meant is:

raw_data(count,:) = (read(SerialPort,54,'uint8'));

when MATLAB read Serial Data needs to know how many bytes have been sent. The number 54 means, in that case, are regarded to the IMU data, as I explained to three 9 axis IMU (high and low register).
For EMG, ideally, I have to put 4 instead of 54. Do you understand what I mean? Is it a problem, right? Because I'll have this situation from ARDUINO:

This is what will going on when EMG interrupt OVF arrive:

int16_t sensorValue = analogRead(A0);
int16_t sensorValue1 = analogRead(A1);
byte H = highByte(sensorValue);
byte L = lowByte(sensorValue);
byte H1 = highByte(sensorValue1);
byte L1 = lowByte(sensorValue1);
byte reading [] = {H,L,H1,L1};    
Serial.write(reading, 4);

And this is what happens when are gone 10 ms referring the iteration for IMU data (where gyro is gyroscope, acc is accelerometer and mag is magnetometer and each one is numered:

 byte reading[] = {gyro_x_H, gyro_x_L, gyro_y_H, gyro_y_L, gyro_z_H, gyro_z_L, gyro_1_x_H, gyro_1_x_L, gyro_1_y_H, gyro_1_y_L, gyro_1_z_H, gyro_1_z_L,
                      gyro_2_x_H, gyro_2_x_L, gyro_2_y_H, gyro_2_y_L, gyro_2_z_H, gyro_2_z_L, mag_x_H, mag_x_L, mag_y_H, mag_y_L, mag_z_H, mag_z_L,
                      mag_1_x_H, mag_1_x_L, mag_1_y_H, mag_1_y_L, mag_1_z_H, mag_1_z_L, mag_2_x_H, mag_2_x_L, mag_2_y_H, mag_2_y_L, mag_2_z_H, mag_2_z_L,
                      acc_x_H, acc_x_L, acc_y_H, acc_y_L, acc_z_H, acc_z_L, acc_1_x_H, acc_1_x_L, acc_1_y_H, acc_1_y_L, acc_1_z_H, acc_1_z_L,
                      acc_2_x_H, acc_2_x_L, acc_2_y_H, acc_2_y_L, acc_2_z_H, acc_2_z_L
                     };
    SerialUSB.write(reading, 54);

Now, given that I have to put one more byte in each data transmission, for instance 0x01 for EMG and 0x02 for IMU, the question is: In Matlab I have to put a control about the first byte?
Something like this pseudocode:

first_byte = (read(SerialPort,1,'uint8'))

if first_byte == 0x02 {
raw_data(count,:) = (read(SerialPort,54,'uint8'))
} 
if first_byte == 0x01 {
raw_data(count,:) = (read(SerialPort,4,'uint8'))
}

This code I think will provide several delays. Am I wrong? Could it work? Is there any other possibility more reliable?
Your help is really appreciated, as always.

I'm not a MatLab user so have no idea. You have MatLab so you can test the implementation of your pseudo code in MatLab.

If you get stuck, you're now probably better of in a MatLab forum.