Strange error in my code?!!

rebecca91rebecca91 Malta
edited March 2011 in Science & Tech
Hey guys,

Im making use of this code but i keep getting the error: "Warning: Matching failure in format." What does this mean?
[I've got an arduino connected serially to my matlab in which my arduino is giving out 6 continuous outputs to be displayed on a graph].
Can you tell me which part of my code needs to be changed please?
SerialPort='com6';   %serial port
MaxDeviation = 3;  %Maximum Allowable Change from one value to next 
TimeInterval=0.2;    %time interval between each input.
loop=120;   %count values
 
%%Set up the serial port object
s = serial(SerialPort)
fopen(s);
time =now;
voltage = 0;
 
%% Set up the figure 
figureHandle = figure('NumberTitle','off',...
    'Name','Voltage Characteristics',...
    'Color',[0 0 0],'Visible','off');
 
% Set axes
axesHandle = axes('Parent',figureHandle,...
    'YGrid','on',...
    'YColor',[0.9725 0.9725 0.9725],...
    'XGrid','on',...
    'XColor',[0.9725 0.9725 0.9725],...
    'Color',[0 0 0]);
hold on;
plotHandle = plot(axesHandle,time,voltage,'Marker','.','LineWidth',1,'Color',[0 1 0]);
xlim(axesHandle,[min(time) max(time+0.001)]);
 
% Create xlabel
xlabel('Time','FontWeight','bold','FontSize',14,'Color',[1 1 0]);
% Create ylabel
ylabel('Voltage in V','FontWeight','bold','FontSize',14,'Color',[1 1 0]);
% Create title
title('Real Time Data','FontSize',15,'Color',[1 1 0]);
%% Initializing variables
voltage(1)=0;
time(1)=0;
count = 2;
k=1;
while ~isequal(count,loop)
 
%%Re creating Serial port before timeout      
      k=k+1;  
      if k==25
          fclose(s);
  delete(s);
  clear s;        
  s = serial('com6');
  fopen(s)
  k=0;
      end      
 
%%Serial data accessing 
invalues = fscanf(s,'%f'); 
for k= 1 : length(invalues) 
voltage(count) = invalues(k); 
if voltage(count)-voltage(count-1) > MaxDeviation 
voltage(count) = voltage(count-1) 
end 
time(count) = count; 
count = count + 1; 
end 
set(plotHandle,'YData',voltage,'XData',time); 
pause(TimeInterval);
 
 

Thanks for any help!!

Comments

  • rebecca91rebecca91 Malta
    edited March 2011
    The error is somewhere here i think what i dont know what needs to be adjusted!

    %%Serial data accessing
    invalues = fscanf(s,'%f');
    for k= 1 : length(invalues)
    voltage(count) = invalues(k);
    if voltage(count)-voltage(count-1) > MaxDeviation
    voltage(count) = voltage(count-1)
    end
    time(count) = count;
    count = count + 1;
    end
    set(plotHandle,'YData',voltage,'XData',time);
    pause(TimeInterval);
  • shwaipshwaip bluffin' with my muffin Icrontian
    edited March 2011
    usually when you get an error, it tells you what line is causing it. knowing the exact line would help.

    also, if you type in:

    dbstop if error

    before running your script, it will drop into the debugger when the error occurs, rather than erroring out. that might allow you to troubleshoot a little more.
  • rebecca91rebecca91 Malta
    edited March 2011
    Yes, i just did that. It told me i have an error with my "fscanf". Does that mean it is having problems reading my data? How can i change that please?
  • shwaipshwaip bluffin' with my muffin Icrontian
    edited March 2011
    it probably means that the data file is not in the format it's expecting. you might take a look at the data file after you see that error to see if there is an unexpected value in it.
  • rebecca91rebecca91 Malta
    edited March 2011
    shwaip wrote:
    it probably means that the data file is not in the format it's expecting. you might take a look at the data file after you see that error to see if there is an unexpected value in it.

    Hrmm, this is where it gets confusing then because all my data is coming from 3 gyros and 3 accelerometers so i cant look into a file to see the values they output. Do you know any websites or online topics about serial data sent to matlab to be put in a continuous graph?
    I really need some help here :sad2:
  • ErrorNullTurnipErrorNullTurnip Illinois Icrontian
    edited March 2011
    You should know what kind of data the arduino is spitting out at you. Arduino's IDE has a serial monitor which you can use to check the serial data. It's probably 6 floating point numbers separated by tabs with a newline after.
  • rebecca91rebecca91 Malta
    edited March 2011
    Yes, in that case i know what arduino's giving me - 6 variables constantly changing according to the position of my device (my arduino's connected to a 6DOF IMU, therefore it gives me the values of 3 accelerometers and 3 gyros).
    What i mean is that i dont have any unexpected values so i dont understand why my matlab gives me that warning :/
  • drasnordrasnor Starship Operator Hawthorne, CA Icrontian
    edited March 2011
    Several things: you've got your format set to just a single floating point number. If you're using ASCII encoding from your IMU (i.e. you can see numbers in your serial console) those are actually coming in as char data, so you need to be capturing those in strings and then performing some kind of string-to-number conversion. If your IMU is sending binary, check to see whether they're really IEEE754-encoded floating-point numbers (float) and not fixed-point represented with integers. Also, you don't have any way of telling which frame you're looking at so when your data read starts up you might be in the middle of a packet and not at the beginning. Typically, a serial sensor will end each packet with an end-of-line character (carriage return and/or line feed) if it's using ASCII output and a specific binary sequence if using BIN. What you may want to do is make a buffer twice as long as the packet you're trying to capture and have it clear the buffer and enter the read loop on an end-of-packet detect.

    If you don't mind my asking, which IMU are you using? I may be able to duplicate your experimental setup.
  • rebecca91rebecca91 Malta
    edited March 2011
    drasnor wrote:
    If you don't mind my asking, which IMU are you using? I may be able to duplicate your experimental setup.

    Im using the Razor 6DOF IMU (http://www.sparkfun.com/products/9431).
    drasnor wrote:
    What you may want to do is make a buffer twice as long as the frame you're trying to capture and have it clear the buffer and enter the read loop on an end-of-frame detect.

    How can i do this? Or maybe you know a link which has an example please? As i have no idea what you mean and im so desperate to fix this code!
    drasnor wrote:
    If you're using ASCII encoding from your IMU (i.e. you can see numbers in your serial console) those are actually coming in as char data, so you need to be capturing those in strings and then performing some kind of string-to-number conversion.

    Yes im using ASCII encoding, so the numbers im seeing are char going into my matlab? How can i do a string-to-number conversion? Or if you know a web page that would be very helpful too.
  • drasnordrasnor Starship Operator Hawthorne, CA Icrontian
    edited March 2011
    I don't have a Razor, but it looks like it's just sensors-only so you're sampling and doing data reduction on the Arduino? If that's the case, the format you're using for your packets is important.

    MathWorks has a help document on serial port I/O that discusses how it works in detail, found here: http://www.mathworks.com/help/techdoc/matlab_external/f62852.html. They show an example of parsing ASCII input with textscan which will probably work for you. However, the examples they show are for a simple query-response problem whereas your problem requires you to continuously parse an incoming bitstream. This is important because they can assume their communication session begins at the beginning of a packet while you can't. You can change your communication session format to a query-response type or develop an algorithm similar to what I mentioned earlier that allows you to detect individual packets within a data stream.

    A note on terminology: I incorrectly used "frame" to describe the group of data forming a complete transmission from your Arduino. The correct term for this is "packet" and I'm going to go back and edit my previous post to reflect that. A "frame" is the smallest unit of data that can be transmitted over a serial interface.
  • drasnordrasnor Starship Operator Hawthorne, CA Icrontian
    edited March 2011
    Regarding what data capture algorithm to use:
    The ones that occur to me immediately are query-response, clear-capture-process, and clear-capture-store. There are others out there, just look around for serial read methods on Google and you'll find plenty though not necessarily MATLAB-portable. Quick overview:

    Query-response:
    The Arduino firmware is designed to loop continuously, checking the serial port for input and sampling the ADC. When a query packet is received, the Arduino sends back a packet containing the current IMU data. MATLAB maintains an input buffer the same size as or slightly larger than the packet size. The buffer then contains a string containing one complete packet which is then parsed. After parse, clear the buffer, process your data, and query Arduino again.

    This approach has low latency from MATLAB's point of view but you can't be assured of collecting the data at any particular rate.

    Clear-capture-process:
    The Arduino firmware is designed to continuously capture, process, and transmit IMU data either at a fixed rate or as fast as possible. MATLAB maintains an input buffer of twice the frame size and continuously checks the buffer for an end-of-packet character. When MATLAB finds one, it clears the buffer and receives frames until another end-of-packet character is found. The buffer is copied to a string variable and cleared. Parse the string variable, process the result, and return to the end-of-packet detection loop.

    This approach has higher latency on MATLAB's side and doesn't guarantee the data at any particular rate. However, it's workable when you need the data "as it comes in" and for some reason you can't or don't want to change the device firmware to a query-response type.

    Note, if Arduino is configured to transmit at a fixed rate and your processing is fast enough to complete before the next packet begins transmitting, you can skip straight to reading the next packet instead of trying to detect the end of the previous packet (and losing a packet in the process.) In this way, you can collect all the transmitted data and process it in real time. You'll know if this won't work for you because you'll get a packet size mismatch error when you try to parse an incomplete packet (because you missed the first part of it.)

    Clear-capture-store:
    The Arduino firmware is designed to continuously capture, process, and transmit IMU data at a fixed rate. MATLAB maintains an input buffer of twice the frame size and a string array large enough to contain every packet over your desired sampling period. MATLAB continuously checks the buffer for an end-of-packet character and when found, clears the buffer and receives frames until another end-of-packet character is found. The buffer is copied to the first element of a string array and then cleared. Loop continuously and copy each packet to successive elements of the string array until the sampling period is over. Parse each element of the string array and process the resulting data.

    This approach is an offline algorithm which guarantees the data is collected at the rate Arduino sends it because the operations between packets being collected are very fast. However, you don't get to see the results until the end of data collection. This works fine when you only need to collect data for a few seconds on demand but won't work for anything that requires real time response.
  • rebecca91rebecca91 Malta
    edited March 2011
    drasnor wrote:
    I don't have a Razor, but it looks like it's just sensors-only so you're sampling and doing data reduction on the Arduino?
    Yes, thats exactly what im doing...well, what im trying to do anyway!
    drasnor wrote:

    I have gone through this web page before already, and i had used the following code to try get the graphs from my arduino instead:
    s = serial('COM9');
    fopen(s)
    fprintf(s,'*IDN?')
    out = fscanf(s)
    [COLOR=red]out = t[ms]   gy   gx   gz   az   ay   ax[/COLOR] //from arduino code
    s.ReadAsyncMode = 'continuous';
    fprintf(s,'*IDN?')
    s.BytesAvailable
    [COLOR=red]ans = 512[/COLOR] //from arduino
    fprintf(s,'CURSOR?')
    fprintf(s,'DISPLAY?')
    val = char(out)'
    [COLOR=red]val =[/COLOR]
    [COLOR=red]45 401 399 374 865 632 386 [/COLOR]
    [COLOR=red]44 401 400 375 865 632 385 [/COLOR]
    [COLOR=red]44 402 401 374 865 632 386 [/COLOR]
    [COLOR=red]45 403 400 373 865 632 386 [/COLOR]
    [COLOR=red]44 401 401 374 864 633 385 [/COLOR]
    [COLOR=red]44 401 400 374 865 632 386 [/COLOR]
    [COLOR=red]44 401 400 374 864 632 386 [/COLOR]
    [COLOR=red]44 401 400 374 864 633 386[/COLOR]  //results from arduino
    

    The results above are the same ones i had seen in my arduino when i was looking over the serial monitor, the only difference is that my arduino ran real-time whilst matlab only gave me one sample. Maybe there's something in the code above that needs to be altered and then displayed on a graph? Or should i refer to the code i gave u earlier and add these "packets" that u mentioned?
  • drasnordrasnor Starship Operator Hawthorne, CA Icrontian
    edited March 2011
    That's pretty strange output from the Arduino code. It answers *IDN? with "t[ms] gy gx gz az ay ax"? What does writing "CURSOR?" and "DISPLAY?" to your Arduino do?

    I counted up the bytes here and including the header ("t[ms] ...") there's 512 bytes. What you're seeing here for val is the complete contents of the input buffer. You've got 8 packets in here, 9 if you count the header packet.
  • rebecca91rebecca91 Malta
    edited March 2011
    drasnor wrote:
    That's pretty strange output from the Arduino code. It answers *IDN? with "t[ms] gy gx gz az ay ax"? What does writing "CURSOR?" and "DISPLAY?" to your Arduino do?
    That output is actually writen in my arduino code as a header so that the continuous values appear below it so that everything's in order. I got the "cursor" and "display" from the matlab example, im not quite sure what they represent. All the page says is:

    For example, suppose you want to return the cursor and display settings for the oscilloscope. This requires writing the <TT>CURSOR?</TT> and <TT>DISPLAY?</TT> commands to the instrument, and then reading back the results of those commands.
    drasnor wrote:
    I counted up the bytes here and including the header ("t[ms] ...") there's 512 bytes. What you're seeing here for val is the complete contents of the input buffer. You've got 8 packets in here, 9 if you count the header packet.
    What are these packets you're counting? And what can i do with them?
    If you wish i can give you my arduino code, its very short, maybe you'll might understand better than I why my matlab isnt running the way i wish it to be :/
  • drasnordrasnor Starship Operator Hawthorne, CA Icrontian
    edited March 2011
    In the example, MathWorks is showing serial communication with a Tektronix oscilloscope. *IDN?, CURSOR?, and DISPLAY? have meaning in that instrument's instruction set. If you haven't implemented responses to those commands in your Arduino code then there's no need for you to issue them in MATLAB. They're meaningless in your application.

    As far as counting packets and frames goes, here's the output you collected:
    t[ms]   gy   gx   gz   az   ay   ax
    45 401 399 374 865 632 386 
    44 401 400 375 865 632 385 
    44 402 401 374 865 632 386 
    45 403 400 373 865 632 386 
    44 401 401 374 864 633 385 
    44 401 400 374 865 632 386 
    44 401 400 374 864 632 386 
    44 401 400 374 864 633 386
    
    Each character is two bytes because that's how many bytes you need to encode a single ASCII character. The first line is 72 bytes: 36 characters including white spaces and one end-of-line character. Each succeeding line is 54 bytes: 27 characters including white spaces and one end-of-line character. Each line is a packet, so you have one header packet and 8 data packets for a total of 9 packets. The byte count is 72 + 54 * 8 = 504. So not quite the full buffer, but certainly close. There may have been some more white space in there I didn't count. You stored the complete output there as a single string variable.
  • rebecca91rebecca91 Malta
    edited March 2011
    drasnor wrote:
    In the example, MathWorks is showing serial communication with a Tektronix oscilloscope. *IDN?, CURSOR?, and DISPLAY? have meaning in that instrument's instruction set. If you haven't implemented responses to those commands in your Arduino code then there's no need for you to issue them in MATLAB. They're meaningless in your application.

    You're right! No need for that at all here
    drasnor wrote:
    The byte count is 72 + 54 * 8 = 504. So not quite the full buffer, but certainly close. There may have been some more white space in there I didn't count. You stored the complete output there as a single string variable.

    The reason the byte count is 504 here is because i didnt paste the complete set here so as not to fill up too much space, so u didnt count them wrong, so at least i know my matlab is reading the right amount of bytes.
    So the question is, i need to tell matlab to store each data packet in a different string? How can i do that? If u have an example that would be so helpful!
  • rebecca91rebecca91 Malta
    edited March 2011
    I might be onto something here; i changed the last piece of my code to convert my values to characters, and in this way all my errors and warning go away. The only thing is, matlab shows me my answers through columns and rows not through a graph. is there some other line i need to add to my code?

    [FONT=Times New Roman]SerialPort='com9'; %serial port
    MaxDeviation = 3; %Maximum Allowable Change from one value to next 
    TimeInterval=1; %time interval between each input.
    loop=120; %count values
    
    %%Set up the serial port object
    s = serial(SerialPort)
    fopen(s);
    time =now;
    voltage = 0;
    
    %% Set up the figure 
    figureHandle = figure('NumberTitle','off',...
    'Name','Voltage Characteristics',...
    'Color',[0 0 0],'Visible','off');
    
    % Set axes
    axesHandle = axes('Parent',figureHandle,...
    'YGrid','on',...
    'YColor',[0.9725 0.9725 0.9725],...
    'XGrid','on',...
    'XColor',[0.9725 0.9725 0.9725],...
    'Color',[0 0 0]);
    hold on;
    plotHandle = plot(axesHandle,time,voltage,'Marker','.','LineWidth',1,'Color',[0 1 0]);
    xlim(axesHandle,[min(time) max(time+0.001)]);
    
    % Create xlabel
    xlabel('Time','FontWeight','bold','FontSize',14,'Color',[1 1 0]);
    % Create ylabel
    ylabel('Voltage in V','FontWeight','bold','FontSize',14,'Color',[1 1 0]);
    % Create title
    title('Real Time Data','FontSize',15,'Color',[1 1 0]);
    %% Initializing variables
    voltage(1)=0;
    time(1)=0;
    count = 2;
    k=1;
    while ~isequal(count,loop)
    
    %%Re creating Serial port before timeout 
    k=k+1; 
    if k==25
    fclose(s);
    delete(s);
    clear s; 
    s = serial('com9');
    fopen(s)
    k=0;
    end<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p>[/FONT]
    [FONT=Times New Roman]
    [/FONT][FONT=Times New Roman][COLOR=red]instring = fread(s,512); <o:p></o:p>[/COLOR][/FONT]
    [FONT=Times New Roman][COLOR=red]data = uint8(instring);<o:p></o:p>[/COLOR][/FONT]
    [FONT=Times New Roman][COLOR=red]mystring = char(data);<o:p></o:p>[/COLOR][/FONT]
    [FONT=Times New Roman][COLOR=red]whos data mystring<o:p></o:p>[/COLOR][/FONT]
    [FONT=Times New Roman]
    [COLOR=red]invalues = sscanf(mystring, '%f');<o:p></o:p>[/COLOR][/FONT]
    [FONT=Times New Roman]
    for k= 1 : length(invalues) 
    voltage(count) = invalues(k); 
    if voltage(count)-voltage(count-1) > MaxDeviation 
    voltage(count) = voltage(count-1) 
    end 
    time(count) = count; 
    count = count + 1; 
    end 
    set(plotHandle,'YData',voltage,'XData',time); 
    pause(TimeInterval);<o:p></o:p>[/FONT]
    [FONT=Times New Roman]end<o:p></o:p>[/FONT]
    
  • drasnordrasnor Starship Operator Hawthorne, CA Icrontian
    edited March 2011
    You're re-plotting all the data each time you go through the loop. Since you have "hold on" set, you may only want to plot the most recent point each time through the loop.
  • rebecca91rebecca91 Malta
    edited March 2011
    how can i only plot the new data every time it runs through the loop though? by removing "hold on" nothing seems to change in my output. and i still cant seem to plot the graph. Or maybe it seems like im re-plotting data but im actually not since i cant see the real-time graph?
  • drasnordrasnor Starship Operator Hawthorne, CA Icrontian
    edited March 2011
    Scratch my last comment. You've found MathWorks's real-time plotting example and copied it verbatim.

    What follows is not intended to be discouraging so please don't take it that way. What you're trying to do here is in a single stroke write a driver for an external instrument, collect data from that instrument, and display the results in an intelligible fashion. What you may want to do is break this program down into chunks and work on each one in order, adding complexity to your problem like layers on an onion. The main tasks here are:
    1. Reliable serial comms with IMU. This is as simple as being able to get a single, complete packet on-demand from your serial connection.
    2. Reliable data collection from serial comms. Once you can get one packet, see about collecting several over a period of time and storing them.
    3. Real-time plotting from data. The MathWorks example is alright but has one serious deficiency that inhibits function at high speeds with large packets. Can you find it?
    What you have now is a collection of examples that weren't intended for your application. Each example contains clues that will make your task easier but you still need to understand exactly what each one does to make sense of which parts need to be changed for your problem. As it stands, you can't isolate which features in your software are causing problems.
Sign In or Register to comment.