How To Maintain Frequency Sampling in Data Acquisition Using Teensy 3.5 and Saving it

Status
Not open for further replies.
I have an ongoing project using Teensy 3.5 as a DAQ and I would like to acquire values of two sensors and its time stamp/ millis(). The sensors I'm using is Olimex Shield-EKG/EMG Rev. B for my EMG data and optical encoder (Yumo E6B2 -CWZ3E 1024P/R). I need to save the data to a csv files with a consistent frequency sampling and within a certain range of time like 60s, 120s, or so on. I've succeeded in reading the sensor values but I haven't find a way to save the data well.

I have tried the Processing but it didn't save the data accurately (like the values produce isn't accurate, there's s since the frequency sampling for the Teensy 3.5 is around 3000-ish Hz. Is there any suggestion how I should the data, what app I should use or so on?

Below is my Arduino code to read the data an send it to Processing

Code:
/*
  pengambilanData - Remake

  Data taken from encoder and EMG and send to Processing. 
  Sensor values data type is INT
  
*/
#include <SoftwareSerial.h>
#include <FrequencyTimer2.h>
#define outputA 5 //untuk encoder
#define outputB 6 
#define RawEMG A0 //analog pin for EMG
int counter = 0;
int derajat = 0;
int EMG;
int aState;
int aLastState;

void setup() {
  pinMode (outputA, INPUT_PULLUP);
  pinMode (outputB, INPUT_PULLUP);
  Serial.println("CLEARDATA"); //clear all rows and columns
  Serial.println("LABEL,Computer Time,Milisec,Counter, Derajat, EMG");
//  FrequencyTimer2::setPeriod(500);
//  FrequencyTimer2::enable();

  Serial.begin(9600);
  //Reads the initial state of the outputA
  aLastState = digitalRead(outputA);
}

void loop() {
  int waktu = millis();
  EMG = analogRead (RawEMG); //reads EMG sensor
  //float EMG = EMG * (5.0 / 1023.0);
  aState = digitalRead(outputA); //reads the 'current' state of the outputA
  //if outputB state is different to the outputA state, that means the encoder is rotating clockwise
  if (aState != aLastState){
    //if outputB state is different to the outputA state, that means the encoder is rotating clockwise
    if (digitalRead(outputB) != aState){
      counter ++;
    } else {
      counter --;
    }
    if (counter > 2048 or counter < -2048) //omron sebelumnya 1200 yang 600ppr, resolusi x 2
    {
      counter = 0;
    }
    derajat = counter * 360/2048;

    //print over the serial line to send to Processing. To work with the processisng sketch we provide, 
    //follow this easy convention: separate each sensor value with a comma, and separate each cycle of loop with a newline character.
    //Remember to separate each sensor value with a comma. Print every value and comma using Serial.print(), except the last sensor value. 
    //For the last sensor value, use Serial.println()
  }
   aLastState = aState;
   Serial.print(counter);
   Serial.print(",");
   Serial.print(derajat);
   Serial.print(",");
   Serial.println(EMG);
   
  }

While this is the Processing code I use, it work well but it didn't save the data the way I wanted it to be. I would be grateful for any suggestions.

Code:
import processing.serial.*;
Serial myPort; //creates a software serial port on which you will listen to Arduino
Table dataTable; //table where we will read in and store values. You can name it something more creative!

int numReadings = 12000 ; //keeps track of how many readings you’d like to take before writing the file.
int readingCounter = 0; //counts each reading to compare to numReadings.
int atime = millis(); //waktu awal
int btime = 0; //waktu yang akan dicompare
int batas = 15000;


String fileName, val;
void setup()
{
  String portName = Serial.list()[1]; //teensy port 1, Arduino port 5
  //CAUTION: your Arduino port number is probably different! Mine happened to be 1. Use a “handshake” sketch to figure out and test which port number your Arduino is talking on. A “handshake” establishes that Arduino and Processing are listening/talking on the same port.
  //Here’s a link to a basic handshake tutorial: https://processing.org/tutorials/overview/

  myPort = new Serial(this, portName, 9600); //set up your port to listen to the serial port
  dataTable = new Table();

  dataTable.addColumn("id"); //This column stores a unique identifier for each record. We will just count up from 0 – so your first reading will be ID 0, your second will be ID 1, etc.

  //the following adds columns for time. You can also add milliseconds. See the Time/Date functions for Processing: https://www.processing.org/reference/
  dataTable.addColumn("hour");
  dataTable.addColumn("minute");
  dataTable.addColumn("second");
  dataTable.addColumn("milisec");

  //the following are dummy columns for each data value. Add as many columns as you have data values. Customize the names as needed. Make sure they are in the same order as the order that Arduino is sending them!
  dataTable.addColumn("Counter");
  dataTable.addColumn("Sudut");
  dataTable.addColumn("EMG");
}

void serialEvent(Serial myPort) {
  try {
    val = myPort.readStringUntil('\n'); //The newline separator separates each Arduino loop. We will parse the data by each newline separator.
    if (val!= null) { //We have a reading! Record it.
      val = trim(val); //gets rid of any whitespace or Unicode nonbreakable space
      println(val); //Optional, useful for debugging. If you see this, you know data is being sent. Delete if you like.
      int sensorVals[] = int(split(val, ',')); //parses the packet from Arduino and places the valeus into the sensorVals array. I am assuming floats. Change the data type to match the datatype coming from Arduino.

      TableRow newRow = dataTable.addRow(); //add a row for this new reading
      newRow.setInt("id", dataTable.lastRowIndex());//record a unique identifier (the row’s index)

      //record time stamp
      newRow.setInt("hour", hour());
      newRow.setInt("minute", minute());
      newRow.setFloat("second", second());
      newRow.setInt("milisec", millis());

      //record sensor information. Customize the names so they match your sensor column names.
      newRow.setFloat("Counter", sensorVals[0]);
      newRow.setFloat("Sudut", sensorVals[1]);
      newRow.setFloat("EMG", sensorVals[2]);
      readingCounter++; //optional, use if you’d like to write your file every numReadings reading cycles
      btime = millis();
      
      //saves the table as a csv in the same folder as the sketch every numReadings.
      if (readingCounter % numReadings ==0)//The % is a modulus, a math operator that signifies remainder after division. The if statement checks if readingCounter is a multiple of numReadings (the remainder of readingCounter/numReadings is 0)
      {
        fileName = "DATA_odi2kg_(TEST3)"+ str(year())+"_" + str(month())+"_" + str(day()) +"_"+ str(dataTable.lastRowIndex()); //this filename is of the form year+month+day+readingCounter
        saveTable(dataTable, "G:/My Drive/Amelia's Data/KULIAH/. SKRIPSI/.PENGAMBILAN DATA/Data/"+ fileName + ".csv", "csv"); //Woo! save it to your computer. It is ready for all your spreadsheet dreams.
        exit();
      }
      //if (btime - atime > batas)
      //{
      //  fileName = "DATA_odi2kg_(9.1)test"+ str(year())+"_" + str(month())+"_" + str(day()) +"_"+ str(dataTable.lastRowIndex()); //this filename is of the form year+month+day+readingCounter
      //  saveTable(dataTable, "G:/My Drive/Amelia's Data/KULIAH/. SKRIPSI/.PENGAMBILAN DATA/Data/"+ fileName + ".csv", "csv"); //Woo! save it to your computer. It is ready for all your spreadsheet dreams.
      //  exit();
      //}
    }
   
  }

  catch(RuntimeException e) {
    e.printStackTrace();
  }
}

void draw()
{
  //visualize your sensor data in real time here! In the future we hope to add some cool and useful graphic displays that can be tuned to different ranges of values.
}
 
I did not try your code but if you want to use the print statement to send floats you need to be aware that by default it will only send 2 digits after the decimal point.
If you want more decimal places you need to specify how many.
Code:
float EMG;
Serial.println(EMG);    //print 2 decimal places
Serial.println(EMG, 8); //print 8 decimal places
 
I see, thank you for the suggestion. I will keep that in mind. Actually I should have establish EMG as an integer since the sensors reading didn't have any decimals.
 
Status
Not open for further replies.
Back
Top