element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • About Us
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Experimenting with Vibration Sensors
  • Challenges & Projects
  • Design Challenges
  • Experimenting with Vibration Sensors
  • More
  • Cancel
Experimenting with Vibration Sensors
Blog Vibration Sensor - Data Capture Program
  • Blog
  • Forum
  • Documents
  • Polls
  • Files
  • Events
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: ralphjy
  • Date Created: 13 Jan 2021 5:43 AM Date Created
  • Views 1700 views
  • Likes 3 likes
  • Comments 1 comment
  • experimenting_with_vibration_sensors
  • kemet vibration sensor
  • edge impulse
  • wio terminal
  • SD card
Related
Recommended

Vibration Sensor - Data Capture Program

ralphjy
ralphjy
13 Jan 2021

I've been working on a program that would allow me to quickly capture and label data to upload to Edge Impulse.

 

Data capture program requirements

  • Fixed sample size
  • Fixed sample rate
  • Selectable data labels
  • Incrementable file name
  • Save to SD card

  

To make things easy, I'm not going to allow user entered parameters because I don't have a keyboard.  And I'm not going to get fancy and implement a GUI or pulldown selections (save that for another project image).  Because a lot of data needs to be taken at each sample size and sample rate, I'm going to cheat and update the program if I need to change those parameters (at least to start).

 

For a simple interface, I'm going to use the 3 user buttons at the top of the Wio Terminal

  1. Left button - Start the data capture (also stop display update to improve data rate - not using DMA yet)
  2. Middle button - increment file number (I may change to auto-increment)
  3. Right button - select data label (see below)

 

Data labels and filename format

The first requirement for training an ML model is to have a dataset with labelled data.  The labels correspond to the different categories that can be classified.  In my test case I'm going to try to identify footsteps of two different people, so I'll have the labels of Person1 and Person2.  It is recommended that 2 or 3 additional categories of data are provided.  The Idle label will be for "no input" data, sort of a noise floor for ambient sensor noise.  The Noise label will be for possible background noise sources (e.g. door opening and closing, refrigerator or other mechanical vibration).  And finally, the Unknown label for other people's footsteps.

 

I am going to capture time series data, so I am going to create a CSV file with TimeStamp and Vibration value pairs.  I'm initially going to try sampling at 500Hz, so I'm going to use the Arduino millis() function to generate the TimeStamp.  If I decide to try sampling at a higher frequency, I'll need to shift to using the micros() function.  I know with micros() works down to 4 microsecond resolution on faster Arduinos, but I haven't tried it with The WioTerminal.  I have a much faster MCU (120MHz M4F), so I would think that I could get 1 microsecond resolution.

 

The filename format will "Label" + "_" + "Sample Number" + ".csv", so for example Idle_0.csv, Person1_0.csv.  I originally did not have the "underscore" in the filename, but as I typed this I realized that I ended a couple of labels with a number and that would be confusing.

 

Separate data capture and SD card write functions

I had initially started sequentially capturing and writing each sample to the SD card.  However, when I examined the timestamps I realized that I was only capturing at between 50-60Hz because of the write time to the SD card.  Capturing the full set of data samples into a memory buffer and then writing to the SD card enables capturing at the 500Hz data rate.  If I start sampling into the KHz range, I'll probably need to start using DMA with the ADC,

 

Data capture program

The program is a bit "raw" at this point, but it functions well enough for me to capture sample data.  I'll need to go back and clean it up (I moved a bunch of stuff around and need to delete some of the commented out code).  I really should automate it, but I want to evaluate some data first.  Hate to take a bunch of bad data.

 

Here is the current program:

 

Wio_Terminal_Datalogger_Sample_new.ino

#include <SPI.h>
#include <Seeed_FS.h>
#include "SD/Seeed_SD.h"
#include"seeed_line_chart.h" //include the library

File myFile;
TFT_eSPI tft;
TFT_eSprite spr = TFT_eSprite(&tft);  // Sprite 

#define max_size 30 //maximum size of data
doubles data[3]; //Initilising a doubles type to store data


int vibration;
int dataCount;
int keyPressed = 0;
int keyUpdate = 0;
int sampleNumber = 0;
int typeIndex = 0;
String sampleType[] = {"Idle","Noise","Unknown","Person1","Person2"};
String fileName;
int fileHeader = 0;


// define logging interval and sample size
#define FREQUENCY_HZ        500
#define INTERVAL_MS         (1000 / (FREQUENCY_HZ + 1))
#define SAMPLE_SZ           2500   // 500 * 5 seconds 
int sampleData[SAMPLE_SZ];
unsigned long timeData[SAMPLE_SZ];

void setup() {
    Serial.begin(115200);
    if (!SD.begin(SDCARD_SS_PIN, SDCARD_SPI)) {
        Serial.println("initialization failed!");
        while(1);
    }
    pinMode(A0, INPUT);
    pinMode(WIO_KEY_A, INPUT_PULLUP);  // rightmost button
    pinMode(WIO_KEY_B, INPUT_PULLUP);  // center button
    pinMode(WIO_KEY_C, INPUT_PULLUP);  // leftmost button
    pinMode(WIO_5S_PRESS, INPUT_PULLUP);  // 5 way button
    
    tft.begin();
    tft.setRotation(3);
    spr.createSprite(TFT_HEIGHT,TFT_WIDTH);
    tft.setTextSize(2);
    
    dataCount = 0;


}

void loop() {
    static unsigned long last_interval_ms = 0;


//    if (millis() > last_interval_ms + INTERVAL_MS) {
//      last_interval_ms = millis();


      spr.fillSprite(TFT_WHITE);
      vibration = analogRead(A0);
      Serial.print("600,");
      Serial.print(vibration);
      Serial.println(",400");
   
      if (data[0].size() == max_size) {
        for (uint8_t i = 0; i<3; i++){
          data[i].pop(); //this is used to remove the first read variable
        }
        //data[0].pop();//this is used to remove the first read variable
      }
      data[0].push(vibration); //read variables and store in data
      data[1].push(530);  //top
      data[2].push(480);  //bottom


//      if (dataCount < SAMPLE_SZ){
//        saveData();
//        dataCount++;
//      }
   
      //Settings for the line graph title
      auto header =  text(0, 0)
                  .value(" Vibration Readings")
                  .align(center)
                  .valign(vcenter)
                  .width(tft.width())
                  .thickness(2);
   
      header.height(header.font_height() * 2);
      header.draw(); //Header height is the twice the height of the font
   
    //Settings for the line graph
      auto content = line_chart(20, header.height()); //(x,y) where the line graph begins
           content
                  .height(tft.height() - header.height() * 1.5) //actual height of the line chart
                  .width(tft.width() - content.x() * 2) //actual width of the line chart
                  .based_on(450.0) //Starting point of y-axis, must be a float
                  .show_circle(false) //drawing a cirle at each point, default is on.
                  .value({data[1],data[0],data[2]}) //passing through the data to line graph
                  .color(TFT_WHITE,TFT_RED,TFT_WHITE) //Setting the color for the line
                  .draw();
   
      spr.pushSprite(0, 0);


      checkpress();  // check for button press
      
//    }
}

void saveData(String fName,unsigned long tData, int sData){
//    fileName = sampleType[typeIndex];
//    fileName.concat(sampleNumber);
//    fileName.concat(".csv");  
//    tft.drawString(fileName,50,130);
    myFile = SD.open(fName,FILE_APPEND);
//    vibration = analogRead(A0);
//    Serial.println(vibration);
    if (fileHeader == 0) {
      myFile.println("timestamp,VSBV203");  // print file header if first pass
      fileHeader = 1;
    }
    myFile.print(tData);
    myFile.print(",");
    myFile.println(sData);
    myFile.close();
}


void captureData(unsigned long timeStamp, int count){
  vibration = analogRead(A0);
  timeData[count] = timeStamp;
  sampleData[count] = vibration;
}


// Check state of buttons
void checkpress(){
  char buffer[20];
  static unsigned long last_interval_ms = 0;


  if (digitalRead(WIO_KEY_A) == LOW) {
    if (keyPressed == 3) {
      keyUpdate = 0;
    } else {
      keyUpdate = 1;
      keyPressed = 3;
    }
  }
  else if (digitalRead(WIO_KEY_B) == LOW) {
    if (keyPressed == 2) {
      keyUpdate = 0;
    } else {
      keyUpdate = 1;
      keyPressed = 2;
    }
  }
  else if (digitalRead(WIO_KEY_C) == LOW) {
    if (keyPressed == 1) {
      keyUpdate = 0;
    } else {
      keyUpdate = 1;
      keyPressed = 1;
    }
  }
  else if (digitalRead(WIO_5S_PRESS) == LOW) {
      keyPressed = 0;
  }

  delay(200);


  if (keyUpdate) {
   
    switch (keyPressed) {
      case 1:
        tft.fillScreen(TFT_BLACK);
        tft.drawString("Start Sampling",25,90);
//        tft.drawString(fileName,50,130);
        while (dataCount < SAMPLE_SZ){
          if (millis() > last_interval_ms + INTERVAL_MS) {
            last_interval_ms = millis();  
            captureData(last_interval_ms,dataCount);
            dataCount++;
          }
//          if (dataCount >= SAMPLE_SZ) break;
        }   
        fileName = sampleType[typeIndex];
        fileName.concat("_");
        fileName.concat(sampleNumber);
        fileName.concat(".csv");  
        tft.drawString(fileName,50,130);
        for (int i = 0; i < SAMPLE_SZ; i++){
          saveData(fileName,timeData[i],sampleData[i]);
        }
        dataCount = 0;     
        break;
      case 2:
        sampleNumber++;
        Serial.println(sampleNumber);
        tft.fillScreen(TFT_BLACK);
        tft.drawString("Sample Number: ",25,110);
        tft.drawString(String(sampleNumber),200,110);
        break;
      case 3:
        if (typeIndex++ > 3) typeIndex = 0;
        Serial.println(sampleType[typeIndex]);
        tft.fillScreen(TFT_BLACK);
        tft.drawString("Sample Type: ",25,110);
        tft.drawString(sampleType[typeIndex],200,110);
        break;      
    }
    
    keyUpdate = 0;

  delay(2000);    
  
  }
    
}

 

Program Demo

The interface is a bit clunky, but it works.  I realized that I can increment the sample number, but not decrement or reset it.  I'll need to add those capabilities.

The data sampling starts as soon as you see the "Start Sampling" message and the SD card write starts as soon as you see the filename displayed.  So for 2500 data points (5 seconds of data), it takes about 30 seconds to write to the SD card.  I'm sure there are ways to reduce that time, but I'll work on that if I decide to automate data capture.

 

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

 

 

CSV File Idle_0.csv

Timestamps are 2 ms apart - 500Hz.

image

 

Plot of Data Sample (5 seconds - 2500 points)

Noise floor is around +/- 1.5 mV.

image

 

 

Links to my other blogs for this challenge

Person Identification using Footstep Vibration Patterns

Vibration Sensor Setup

Vibration Sensor - First Look

Vibration Sensor - Data Capture Setup

  • Sign in to reply
  • mcfryday
    mcfryday over 4 years ago

    Cool project, I am exited to see if this is possible to really "name" a person in the room and perhaps also if pets are present, i.e the quiet walk of a cat may be the biggest challenge... however as someone mentioned in the other blog interesting to see a human presence in a room and i.e. how many people are in by the number of different "step fingerprints" or which kind of shoes they wear ;-), cheers Michael

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube