MATLAB Answers

0

Arduino serial read bug

Asked by Jonathan on 8 Oct 2015
Latest activity Commented on by Kiki
on 29 Mar 2016
What I want to do is to sample an analog voltage from an Arduino pin (0 to 5 V, read as integer values from 0 to 1024), and transmit these samples to Matlab to be plotted. The code below is for the Arduino, it sets up the serial port and then in the loop it reads the voltage from pin 1, sends it to the serial port using "Serial.println", pauses and then keeps repeating this. The sample rate is set by the pause length.
int analogPin = 1; // Analog read pin. This is the e.g. photodiode input
int result;
int sample = 100; // Sampling period (ms)
int Baud = 9600; // Serial baud rate
void setup() {
pinMode(analogPin,INPUT);
Serial.begin(Baud); // Setup serial port
delay(1000); // 1 sec delay
}
void loop() {
result = analogRead(analogPin); // read the analog pin
Serial.println(result);
delay (sample);
}
The following Matlab code configures and opens the serial port, and reads the serial port 100 times and saves these sample values to "y". The results are then plotted.
clear all
clc
baud = 9600;
arduino=serial('COM3','BaudRate',baud);
fopen(arduino);
x=linspace(1,100);
y=zeros(1,100);
for i=1:length(x)
y(i) = fscanf(arduino,'%d');
end
fclose(arduino);
disp('making plot..')
plot(x,y);
When I have a relatively long delay between sampling the pin (say, 100 ms), everything works perfectly. I switch the input to pin 1 between the 3.3 V and 5 V pins on the Arduino, and the correct values are plotted in Matlab. The problem I encounter is when I decrease the sampling rate (to, say 1 ms). I get the following error:
Warning: Unsuccessful read: Matching failure in format.. In an assignment A(I) = B, the number of elements in B and I must be the same. Error in Testexample (line 12) y(i) = fscanf(arduino,'%d');
I guess I'm having a problem with reading the serial data, either Matlab is reading in more than one value, or there's no value to read, and the error occurs because the array y(i) will only accept one entry per column? The data looks fine on the Arduino serial monitor, it looks the same there regardless of the sampling rate.
I don't really know how to troubleshoot this further, so any pointers would be appreciated. Thanks!

  2 Comments

Walter Roberson
on 8 Oct 2015
Is it a real serial port, or is it Serial over USB?
Jonathan on 9 Oct 2015
Hi walter,
It's serial over USB.

Sign in to comment.

3 Answers

Answer by Madhu Govindarajan on 8 Oct 2015

If you are using one of the latest releases of MATLAB, try using the support package for the same - http://www.mathworks.com/hardware-support/arduino-matlab.html

  0 Comments

Sign in to comment.


Answer by Jonathan on 9 Oct 2015

Hello again,
I found something that works for me:
I changed the line in my Matlab script:
From
[Select]
y(i) = fscanf(arduino,'%d');
To
y(i) = fread(arduino,1,'uint8');
On my Arduino code, I changed the "void loop" so that the AnalogRead value (which is usually a value from 0 to 1023) is now mapped to a value between 0 and 255. The idea behind that is to map the AnalogRead value to a single byte - I copied the idea from: here
New void loop code:
void loop() {
result = analogRead(analogPin); // read the analog pin
outputValue = map(result, 0, 1023, 0, 255);
Serial.write(outputValue);
delay (sample);
}
It's now working (at least, working as well as I need it to work), but of course if anyone else has some more elegant solutions or improvements I'd be happy to hear them :)

  3 Comments

Kiki
on 25 Mar 2016
Hi Jonathan
Would you mind explaining what the "%d" means in your original code?
y(i) = fscanf(arduino,'%d');
Your new codes worked perfectly. However, I want to send float point numbers to the Matlab and plot. In my Matlab script, I have
y(i) = fread(arduino,1,'float');
But I don't know what to write in my arduino code. If I use print(), what the Matlab read is totally wrong. Would you have any idea how to do this?
Thank you very much! Kiki
Walter Roberson
on 25 Mar 2016
%d means parse a decimal number (that is, an integer base 10)
fread with 'float' is a binary read.
Use %f format or %g format to format floating point output as string, and use %f format to read floating point input as string.
Kiki
on 29 Mar 2016
Hi
So if I use print() in my arduino code, I should use %f in my matlab code as follows to read it, right?
y(i) = fscanf(arduino,'%f');
Thank you.

Sign in to comment.


Answer by Walter Roberson
on 9 Oct 2015

USB is not a dedicated channel. USB is a system whee a master device goes around polling the attached devices asking each one in turn if they have any data to send. If they do and it is a relatively small amount of data they might reply with the data, but if it is more data they they are just to reply Yes and the master will get back to them when there is time for them to send the data.
Because of this behaviour, when data is ready to send, it cannot just be sent: the device has to wait for the master to tell it to go ahead.
In documents I read a few years ago but am having difficulty locating now, I found that furthermore, for serial-port emulating devices, USB is designed to wait until either a complete packet is full or else that no data has been received for a time before it will release the packet. This is good for efficient use of shared bandwidth but it is not good for latency. If your bytes are available more slowly than the wait for data then you don't really notice much (provided that your data is not too time sensitive), but after a point you get stuck: before the end of the wait period you get another byte and since the packet isn't full yet the timer restarts.... only to be interrupted by the next packet. And so on, until the packet is full. This can end up with longer latency than if the data rate was slower. But, hey, it is efficient use of the bandwidth and that is what is important, right?
So... you might not get data for a while. And you might time-out if you are not set to handle the worst-case of the timer being reset just as it was due to expire, over and over again. And even if that does not happen, batches of bytes arrive rather than single bytes and your code might not expect that...
Serial over USB is... Bovine Growth Hormone... for data acquisition unless both sides know how to trigger immediate data sending (which requires talking to the master device, and which MATLAB does not provide an interface for.)

  0 Comments

Sign in to comment.