Search code examples
c++arduinoubuntu-16.04

How to capture and store sensor data from Arduino into C++


I am writing a code to capture serial readings from the Arduino to C++

Is there a way to capture the readings line by line and then store it into an array? I have read another post similar to mine, but I am still unable to apply it.

Any help is greatly appreciated, thank you.

Environment setup:

  • Arduino UNO
  • ADXL 335 accelerometer
  • Ubuntu 16.04
  • C++

[Updated] applied solution from Bart

Cpp file

The reason why I added the "for-loop with print and break" is to analyze the array contents.

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <unistd.h>

using namespace std;

char serialPortFilename[] = "/dev/ttyACM0";

int main()
{
    char readBuffer[1024];

    FILE *serPort = fopen(serialPortFilename, "r");

    if (serPort == NULL)
    {
        printf("ERROR");    
        return 0;
    }   

    while(1)
    {                           
        usleep(1000); //sync up Linux and Arduino       
        
        memset(readBuffer, 0, 1024);
        fread(readBuffer, sizeof(char),1024,serPort);       
    
        for(int i=0; i<1024; i++){
            printf("%c",readBuffer[i]);     
        }
        break;
    }
    
    return 0;
}

Ino file

Fetching data from the Accelerometer

#include <stdio.h>

const int xPin = A0;
const int yPin = A1;
const int zPin = A2;

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

void loop() {
  int x = 0, y = 0, z = 0;
  
  x = analogRead(xPin);
  y = analogRead(yPin);
  z = analogRead(zPin);
  
  char buffer[16];
  int n;
  n = sprintf(buffer,"<%d,%d,%d>",x,y,z);
  
  Serial.write(buffer);
}

Results

Running the code for three times Click Here

The ideal outputs should be

<a,b,c><a,b,c><a,b,c>...

but right now, some of the outputs has the values inside "corrupted" (please see the fourth line from the top).

Even if use the start and end markers to determine a correct dataset, the data within the set is still wrong. I suspect the issue lies with the char array from C++, due to it being unsynchronized with Arduino. Else I need to send by Bytes from Arduino (not really sure how)


Solution

  • When dealing with two programs running on different processors they will never start sending/receiving at the same time. What you likely see is not that the results are merged wrong it is more likely the reading program started and stopped half way through the data.

    When sending data over a line it is best that you:

    On the Arduino:

    1. First frame the data.
    2. Send the frame.

    On Linux:

    1. Read in data in a buffer.
    2. Search the buffer for a complete frame and deframe.

    1. Framing the data

    With framing the data I mean that you need a structure which you can recognize and validate on the receiving side. For example you could add the characters STX and ETX as control characters around your data. When the length of your data varies it is also required to send this.

    In the following example we take that the data array is never longer than 255 bytes. This means that you can store the length in a single byte. Below you see pseudo code of how a frame could look like:

    STX LENGTH DATA_ARRAY ETX
    

    The total length of the bytes which will be send are thus the length of the data plus three.

    2. Sending

    Next you do not use println but Serial.write(buf, len) instead.

    3. Receiving

    On the receiving side you have a buffer in which all data received will be appended.

    4. Deframing Next each time new data has been added search for an STX character, assume the next character is the length. Using the length +1 you should find a ETX. If so you have found a valid frame and you can use the data. Next remove it from the buffer.

    for(uint32_t i = 0; i < (buffer.size() - 2); ++i)
    {
      if(STX == buffer[i])
      {
        uint8_t length = buffer[i+2];
        if(buffer.size() > (i + length + 3) && (ETX == buffer[i + length + 2]))  
        {
          // Do something with the data.
    
          // Clear the buffer from every thing before i + length + 3
          buffer.clear(0, i + length + 3);
    
          // Break the loop as by clearing the data the current index becomes invalid.
          break; 
        }
      }
    }
    

    For an example also using a Cyclic Redundancy Check (CRC) see here