Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update sensor code with speed and filespace improvements. #3

Merged
merged 3 commits into from
Feb 19, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 118 additions & 135 deletions accelerometer/sensor_logger.ino
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
/**
* Created by Ammolytics
* License: MIT
* Version: 1.0.0
* Version: 2.0.0
* URL: https://github.com/ammolytics/projects/
* Inexpensive firearm accelerometer based on the Adafruit LIS3DH breakout board.
*/

#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>
#include "RTClib.h"
#include "SdFat.h"

// Used for software SPI
#define LIS3DH_CLK 13
#define LIS3DH_MISO 12
#define LIS3DH_MOSI 11
// Used for hardware & software SPI
#define LIS3DH_CS 10

// Battery pin
#define VBATPIN A7

// I2C clock speed
#define I2C_SPEED 1000000

// Enable debug logger.
// Note: Comment out before running in real-world.
#define DEBUG
Expand All @@ -39,19 +37,18 @@ RTC_PCF8523 rtc;
// change this to match your SD shield or module;
// Adafruit SD shields and modules: pin 10
const int chipSelect = 10;
// 19 digits plus the null char
char DateTimeString[20];

// Filename format: 20180710.csv
char filename[13];

char dataRow[10000];
String strRow;
int counter = 0;
// Filename format: YYYYMMDDHHmm.csv
char filename[17];


int lastX;
unsigned long begin_us;
unsigned long begin_epoch;
unsigned long start_us;
unsigned long stop_us;
unsigned long counter = 0;

File dataFile;

// software SPI
//Adafruit_LIS3DH lis = Adafruit_LIS3DH(LIS3DH_CS, LIS3DH_MOSI, LIS3DH_MISO, LIS3DH_CLK);
Expand All @@ -60,29 +57,30 @@ File dataFile;
// I2C
Adafruit_LIS3DH lis = Adafruit_LIS3DH();

// set up variables using the SD utility library functions:
// File system object.
SdFat sd;
// Log file.
SdFile dataFile;


void setup() {
#ifdef DEBUG
Serial.begin(9600);
Serial.begin(115200);
while (!Serial); // will pause Zero, Leonardo, etc until serial console opens
#endif

float measuredvbat = analogRead(VBATPIN);
measuredvbat *= 2; // we divided by 2, so multiply back
measuredvbat *= 3.3; // Multiply by 3.3V, our reference voltage
measuredvbat /= 1024; // convert to voltage
DEBUG_PRINT("VBat: " ); DEBUG_PRINTLN(measuredvbat);

DEBUG_PRINTLN("Initializing SD card...");

if (!SD.begin(chipSelect)) {
DEBUG_PRINTLN("Card failed, or not present");
// don't do anything more:
while (1);
}
DEBUG_PRINTLN("Card initialized.");
#ifdef DEBUG
float measuredvbat = analogRead(VBATPIN);
measuredvbat *= 2; // we divided by 2, so multiply back
measuredvbat *= 3.3; // Multiply by 3.3V, our reference voltage
measuredvbat /= 1024; // convert to voltage
DEBUG_PRINT("VBat: " ); DEBUG_PRINTLN(measuredvbat);
#endif


/**
* Initialize the Real Time Clock.
*/
DEBUG_PRINTLN("Initializing RTC...");
if (! rtc.begin()) {
DEBUG_PRINTLN("Couldn't find RTC");
Expand All @@ -92,127 +90,112 @@ void setup() {
DEBUG_PRINTLN("RTC is NOT running!");
}
DEBUG_PRINTLN("RTC initialized.");
begin_us = micros();
DateTime now = rtc.now();
begin_epoch = now.unixtime();


DEBUG_PRINTLN("Initializing LIS3DH Sensor...");
if (! lis.begin(0x18)) { // change this to 0x19 for alternative i2c address
DEBUG_PRINTLN("Couldnt start");
/**
* Initialize the SD card and log file.
*/
DEBUG_PRINTLN("Initializing SD card...");
if (!sd.begin(chipSelect, SD_SCK_MHZ(50))) {
DEBUG_PRINTLN("Card failed, or not present");
// don't do anything more:
while (1);
}
lis.setRange(LIS3DH_RANGE_4_G); // 2, 4, 8 or 16 G!
DEBUG_PRINTLN("LIS3DH initialized.");


DEBUG_PRINTLN("Ready!");

DateTime now = rtc.now();
sprintf_P(DateTimeString, PSTR("%4d-%02d-%02d %d:%02d:%02d"),
now.year(), now.month(), now.day(), now.hour(), now.minute(), now.second());
sprintf_P(filename, PSTR("%4d%02d%02d.csv"), now.year(), now.month(), now.day());

DEBUG_PRINTLN(DateTimeString);
DEBUG_PRINTLN("Card initialized.");

// Set filename based on timestamp.
sprintf_P(filename, PSTR("%4d%02d%02d%02d%02d.csv"), now.year(), now.month(), now.day(), now.hour(), now.minute());
DEBUG_PRINT("Filename: ");
DEBUG_PRINTLN(filename);

dataFile = SD.open(filename, O_CREAT | O_WRITE);
dataFile.println("timestamp, accel x, accel y, accel z, accel unit, sensor range, millis, micros, voltage");
DEBUG_PRINTLN(dataFile);
if (! dataFile) {
if (! dataFile.open(filename, O_CREAT | O_APPEND | O_WRITE)) {
DEBUG_PRINTLN("Could not open file...");
while (1);
}
dataFile.close();

DEBUG_PRINTLN("timestamp (s), start (µs), delta (µs), accel x (G), accel y (G), accel z (G)");
// Write header row to file.
dataFile.println("timestamp (s), start (µs), delta (µs), accel x (G), accel y (G), accel z (G)");
dataFile.flush();

// Check to see if the file exists:
if (SD.exists(filename)) {
DEBUG_PRINTLN("Log file exists.");
} else {
if (! sd.exists(filename)) {
DEBUG_PRINTLN("Log file doesn't exist.");
while (1);
}

/**
* Initialize the accelerometer.
*/
DEBUG_PRINTLN("Initializing LIS3DH Sensor...");
if (! lis.begin(LIS3DH_DEFAULT_ADDRESS)) { // change this to 0x19 for alternative i2c address
DEBUG_PRINTLN("Couldnt start");
while (1);
}
// Set I2C high speedmode
Wire.setClock(I2C_SPEED);
// Set range to 8G
lis.setRange(LIS3DH_RANGE_8_G);
// 5khz data rate
lis.setDataRate(LIS3DH_DATARATE_LOWPOWER_5KHZ);
DEBUG_PRINTLN("LIS3DH initialized.");

// Leave the file open for writing.
dataFile = SD.open(filename, O_CREAT | O_APPEND | O_WRITE);
DEBUG_PRINTLN("Ready!");
}



// Main Loop
void loop() {
float measuredvbat = analogRead(VBATPIN);
measuredvbat *= 2; // we divided by 2, so multiply back
measuredvbat *= 3.3; // Multiply by 3.3V, our reference voltage
measuredvbat /= 1024; // convert to voltage
//DEBUG_PRINT("VBat: " ); DEBUG_PRINTLN(measuredvbat);
// Read from the accelerometer sensor and measure how long the op takes.
start_us = micros();
lis.read();
stop_us = micros();

// Roughly equivalent to calling rtc.now().unixtime(), without 1ms latency.
DEBUG_PRINT(begin_epoch + ((stop_us - begin_us) / 1000000));
DEBUG_PRINT(',');
// Write timestamp to file.
dataFile.print(begin_epoch + ((stop_us - begin_us) / 1000000));
dataFile.print(',');

DEBUG_PRINT(start_us);
DEBUG_PRINT(',');
DEBUG_PRINT(stop_us - start_us);
DEBUG_PRINT(',');
// Write timers to file.
dataFile.print(start_us);
dataFile.print(',');
dataFile.print(stop_us - start_us);
dataFile.print(',');

lis.read(); // get X Y and Z data at once
// Then print out the raw data
/*
DEBUG_PRINT(lis.x); DEBUG_PRINT(", ");
DEBUG_PRINT(lis.y); DEBUG_PRINT(", ");
DEBUG_PRINT(lis.z); DEBUG_PRINT(", ");
*/

/* Or....get a new sensor event, normalized */
sensors_event_t event;
lis.getEvent(&event);

int rangeVal = 2 << lis.getRange();

DateTime now = rtc.now();

/*
sprintf_P(dataRow, PSTR("%d, %d, %d, %d, %s, %s, %d"),
now.unixtime(), event.acceleration.x, event.acceleration.y, event.acceleration.z, "m/s^2", rangeVal, millis());

DEBUG_PRINTLN(dataRow);
*/

/* Display the results (acceleration is measured in m/s^2) */
strRow = String(now.unixtime()) + ", ";
strRow += String(event.acceleration.x) + ", ";
strRow += String(event.acceleration.y) + ", ";
strRow += String(event.acceleration.z) + ", ";
strRow += "m/s^2, ";
strRow += String(rangeVal) + ", ";
strRow += String(millis()) + ", ";
strRow += String(micros()) + ", ";
strRow += String(measuredvbat);

DEBUG_PRINTLN(strRow);

// Open the file if it's closed.
if (!dataFile) {
dataFile = SD.open(filename, O_CREAT | O_APPEND | O_WRITE);
}
// if the file is available, write to it:
if (dataFile) {
dataFile.println(strRow);
} else {
// if the file isn't open, pop up an error:
DEBUG_PRINTLN("error opening file");
}

// Determine if the unit is actively recording important motion to prevent delays from writing ops.
// X-Axis is inline with bore. Least likely to detect acceleration of gravity.
bool inMotion = false;
if (max(event.acceleration.x, lastX) > 1.0 || min(event.acceleration.x, lastX) < -1.0) {
inMotion = true;
}

DEBUG_PRINT(lis.x_g);
DEBUG_PRINT(',');
DEBUG_PRINT(lis.y_g);
DEBUG_PRINT(',');
DEBUG_PRINT(lis.z_g);
// Write acceleration to file.
dataFile.print(lis.x_g);
dataFile.print(',');
dataFile.print(lis.y_g);
dataFile.print(',');
dataFile.print(lis.z_g);

DEBUG_PRINTLN();
// Write newline.
dataFile.println();
counter++;
// write the data to prevent loss.
if (counter >= 20 && !inMotion) {
DEBUG_PRINTLN("Data file write/flush.");

/**
* Flush buffer, actually write to disk.
* This can take between 9 and 26 milliseconds. Or ~10ms with SDfat.
*/
if (counter >= 800) {
DEBUG_PRINTLN("Writing to SD card");
unsigned long pre_write = micros();
dataFile.flush();
unsigned long post_write = micros();
DEBUG_PRINT("Write ops took: "); DEBUG_PRINTLN(post_write - pre_write);
counter = 0;
} else {
DEBUG_PRINTLN(inMotion);
}
if (counter >= 100) {
DEBUG_PRINTLN("Data file write/close.");
dataFile.close();
counter = 0;
}

lastX = event.acceleration.x;

//delay(1);
}