Hi, Everyone. I am currently working on a small project to measure the impact (accleration in Gs)when a dropping item hit on the ground.
The instrument I used are: Arduino UNO (with SD shield), ADXL326(it turned out exceeding its limit,didn`t use it), ADXL377. The expectation is to achieve high reading speed from sensor and high writing speed to the card so that the final data would clearly show the trending of changing acceleration during the moment. However, the real results I have got were inconsistent from each drop test and the reading and writing speed was relatively low. It was not able to capture the whole impact process.
I have no experiences of working with arduino before. Here are two sets of code I have learned from the internet and used for this project. I am looking forward to seeing at least 1000 readings per second either on the serial print or SD cards. Really hope someone here can point out the isssues or offer me some advices/recommendations. Thanks ahead of time!
Code 1
This code allow the final data (in Gs) to be printed through both Serial port and SD cards. However, the speed is extremely slow (or the amount of datas it got per second was so limited)
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"
RTC_DS1307 rtc;
const int xInput = A0;
const int yInput = A1;
const int zInput = A2;
const int buttonPin = 2;
const int chipSelect = 10;
const int groundpin = 18;
const int powerpin = 19;
File dataFile;
// Raw Ranges:
// initialize to mid-range and allow calibration to
// find the minimum and maximum for each axis
int xRawMin = 512;
int xRawMax = 512;
int yRawMin = 512;
int yRawMax = 512;
int zRawMin = 512;
int zRawMax = 512;
// Take multiple samples to reduce noise
const int sampleSize = 10;
void setup() {
analogReference(EXTERNAL);
Serial.begin(115200);
Serial.print("Initializing SD card...");
pinMode(SS, OUTPUT);
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
while (1) ;
}
Serial.println("card initialized.");
dataFile = SD.open("datalog.txt", FILE_WRITE);
if (! dataFile) {
Serial.println("error opening datalog.txt");
// Wait forever since we cant write data
while (1) ;
}
#ifdef AVR
Wire.begin();
#else
Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino Due
#endif
rtc.begin();
if (! rtc.isrunning()) {
Serial.println("RTC is NOT running!");
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}
}
void loop() {
int xRaw = ReadAxis(xInput);
int yRaw = ReadAxis(yInput);
int zRaw = ReadAxis(zInput);
// Read the state of the button to see if we need to calibrate.
// This button should probably be debounced.
if (digitalRead(buttonPin) == LOW)
{
AutoCalibrate(xRaw, yRaw, zRaw);
}
else
{
// Do all of the math first.
// Convert raw values to 'milli-Gs"
long xScaled = map(xRaw, xRawMin, xRawMax, -1000, 1000);
long yScaled = map(yRaw, yRawMin, yRawMax, -1000, 1000);
long zScaled = map(zRaw, zRawMin, zRawMax, -1000, 1000);
// re-scale to fractional Gs
float xAccel = xScaled / 1000.0;
float yAccel = yScaled / 1000.0;
float zAccel = zScaled / 1000.0;
// Start the printing portion. First with serial to print to the console.
// Note: When this code is eventually "Production Code", the printing to the
// serial console should be commented out to save some execution cycles.
Serial.print(" Raw Ranges: X: ");
Serial.print(xRawMin);
Serial.print("-");
Serial.print(xRawMax);
Serial.print(", Y: ");
Serial.print(yRawMin);
Serial.print("-");
Serial.print(yRawMax);
Serial.print(", Z: ");
Serial.print(zRawMin);
Serial.print("-");
Serial.print(zRawMax);
Serial.print(" Raw Values: ");
Serial.print(" X: ");
Serial.print(xRaw);
Serial.print(", Y: ");
Serial.print(yRaw);
Serial.print(", Z: ");
Serial.print(zRaw);
Serial.print(", ");
Serial.print(" :: ");
Serial.print(xAccel);
//Serial.print("G, ");
Serial.print(yAccel);
//Serial.print("G, ");
Serial.println(zAccel);
//Serial.print("G ");
DateTime now = rtc.now();
/*Serial.print(now.year(),DEC);
Serial.print('/');
Serial.print(now.month(), DEC);
Serial.print('/');
Serial.print(now.day(), DEC);
Serial.print(' ');
Serial.print(now.hour(), DEC);
Serial.print(':');*/
Serial.print(now.minute(), DEC);
Serial.print(':');
Serial.println(now.second(), DEC);
//Serial.print(':');
// Filter out any values of xRaw, yRaw or zRaw that are not greater than
// the thresholds. Basically, this statement is saying print to the SD card
// if xRaw OR yRaw OR zRaw are greater than the threshold.
//if( abs(xAccel) > 1 || abs(yAccel) > 1 || abs(zAccel) > 1 ) {
// Now print to the SD card.
dataFile.print(now.year(),DEC);
dataFile.print('/');
dataFile.print(now.month(), DEC);
dataFile.print('/');
dataFile.print(now.day(), DEC);
dataFile.print(' ');
dataFile.print(now.hour(), DEC);
dataFile.print(':');
dataFile.print(now.minute(), DEC);
dataFile.print(':');
dataFile.print(now.second(), DEC);
dataFile.print(",");
dataFile.print(xAccel);
dataFile.print(",");
dataFile.print(yAccel);
dataFile.print(",");
dataFile.println(zAccel);
dataFile.flush();
}
}
// Read "sampleSize" samples and report the average
int ReadAxis(int axisPin)
{
long reading = 0;
analogRead(axisPin);
delay(1);
for (int i = 0; i < sampleSize; i++)
{
reading += analogRead(axisPin);
}
return reading/sampleSize;
}
// Find the extreme raw readings from each axis
void AutoCalibrate(int xRaw, int yRaw, int zRaw)
{
Serial.println("Calibrate");
if (xRaw < xRawMin)
{
xRawMin = xRaw;
}
if (xRaw > xRawMax)
{
xRawMax = xRaw;
}
if (yRaw < yRawMin)
{
yRawMin = yRaw;
}
if (yRaw > yRawMax)
{
yRawMax = yRaw;
}
if (zRaw < zRawMin)
{
zRawMin = zRaw;
}
if (zRaw > zRawMax)
{
zRawMax = zRaw;
}
}
Code 2
Based on code 1, several changes has been made by removing, simplified codes in order to improve the reading speed. For example:
- only allowed to print through serial with much higher baud rate (115200)
- removed math calculation/conversion part (to calculate Gs) since this part can be done on excel
- use micro seconds as time scale and print all data by using datastring
This has dramactically increased the reading speed. Its about 600 readings but it
s still not fast enough. Here is the code.
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
String toprint;
const int xInput = A0;
const int yInput = A1;
const int zInput = A2;
const int buttonPin = 2;
const int chipSelect = 10;
const int groundpin = 18;
const int powerpin = 19;
File dataFile;
// Raw Ranges:
// initialize to mid-range and allow calibration to
// find the minimum and maximum for each axis
int xRawMin = 512;
int xRawMax = 512;
int yRawMin = 512;
int yRawMax = 512;
int zRawMin = 512;
int zRawMax = 512;
// Take multiple samples to reduce noise
const int sampleSize = 10;
void setup() {
analogReference(EXTERNAL);
Serial.begin(115200);
/*Serial.print("Initializing SD card...");
pinMode(SS, OUTPUT);
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
while (1) ;
}
Serial.println("card initialized.");
dataFile = SD.open("datalog.txt", FILE_WRITE);
if (! dataFile) {
Serial.println("error opening datalog.txt");
// Wait forever since we cant write data
while (1) ;
}*/
#ifdef AVR
Wire.begin();
#else
Wire1.begin(); // Shield I2C pins connect to alt I2C bus on Arduino Due
#endif
/*rtc.begin();
if (! rtc.isrunning()) {
Serial.println("RTC is NOT running!");
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// January 21, 2014 at 3am you would call:
// rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
}*/
}
void loop() {
//myMillis = millis();
int xRaw = analogRead(xInput);
int yRaw = analogRead(yInput);
int zRaw = analogRead(zInput);
// Read the state of the button to see if we need to calibrate.
// This button should probably be debounced.
if (digitalRead(buttonPin) == LOW)
{
AutoCalibrate(xRaw, yRaw, zRaw);
}
else
{
// Do all of the math first.
// Convert raw values to 'milli-Gs"
/*long xScaled = map(xRaw, xRawMin, xRawMax, -1000, 1000);
long yScaled = map(yRaw, yRawMin, yRawMax, -1000, 1000);
long zScaled = map(zRaw, zRawMin, zRawMax, -1000, 1000);
// re-scale to fractional Gs
float xAccel = xScaled / 1000.0;
float yAccel = yScaled / 1000.0;
float zAccel = zScaled / 1000.0;*/
/*DateTime now = rtc.now();
Serial.print(now.second(),DEC);
Serial.print (",");
Serial.print(xAccel);
Serial.print(", ");
Serial.print(yAccel);
Serial.print(", ");
Serial.println(zAccel);*/
//This is used for printing raw value of each axis into the serial print.
toprint = 0;
toprint += micros();
//toprint +=",";
toprint += (xRaw);
//toprint += (", ");
toprint +=(yRaw);
//toprint += (", ");
toprint +=(zRaw);
Serial.println(toprint);
//dataFile.println (toprint);
//dataFile.flush();
// Filter out any values of xRaw, yRaw or zRaw that are not greater than
// the thresholds. Basically, this statement is saying print to the SD card
// if xRaw OR yRaw OR zRaw are greater than the threshold.
//if( abs(xAccel) > 1 || abs(yAccel) > 1 || abs(zAccel) > 1 ) {
// Now print to the SD card.
/*dataFile.print(now.second(), DEC);
dataFile.print(",");
dataFile.print(xAccel);
dataFile.print(",");
dataFile.print(yAccel);
dataFile.print(",");
dataFile.println(zAccel);
dataFile.flush();*/
//This is used for recording the raw values from each axis onto the SD card.
/*dataFile.print(now.second(), DEC);
dataFile.print(",");
dataFile.print(xRaw);
dataFile.print(",");
dataFile.print(yRaw);
dataFile.print(",");
dataFile.println(zRaw);
dataFile.flush();*/
}
}
// Read "sampleSize" samples and report the average
int ReadAxis(int axisPin)
{
long reading = 0;
analogRead(axisPin);
delay(1);
for (int i = 0; i < sampleSize; i++)
{
reading += analogRead(axisPin);
}
return reading/sampleSize;
}
// Find the extreme raw readings from each axis
void AutoCalibrate(int xRaw, int yRaw, int zRaw)
{
Serial.println("Calibrate");
if (xRaw < xRawMin)
{
xRawMin = xRaw;
}
if (xRaw > xRawMax)
{
xRawMax = xRaw;
}
if (yRaw < yRawMin)
{
yRawMin = yRaw;
}
if (yRaw > yRawMax)
{
yRawMax = yRaw;
}
if (zRaw < zRawMin)
{
zRawMin = zRaw;
}
if (zRaw > zRawMax)
{
zRawMax = zRaw;
}
}
Besides coding problems I also have several questions as following:
Q1 How many readings per second I can get the most theoretically from Arduino UNO with ADXL 377 sensor ?
Q2 How to count data per second? Do I just need to count how many data shows either on serial port or SD cards with one second time frame? Or count the time difference between two sets of data then use one second to divide this. For example, here is a sets of data, the first column is time in micro-second, the next three comlumns are values of accelerations in 3-axis.
23172108 , a1,a2,a3
23172220 , a1,a2,a3
23172332 , a1,a2,a3
So, here the time between between samples is 112 microseconds. Is this mean the sample rate is 8300 [1s/(120microseconds)] ? Why the arduino did not display 8300 readings?
Q3 Will I get a fast reading speed if I switch Arduino UNO to Due?
Q4 Can I self replace the capacitors on the ADXL 377 sensors to achieve higher bandwith?or Can I order a customized accelerometer sensor from Ad fruit here?
Thanks for reading my post. Please feel free to let me know if there is anything that is unclear or confusing. Also, let me know if you have recommendations.