Accelerometer Data Logger with IR Trigger

A good example of how useful Arduino  libraries are is this IR triggered accelerometer logger that I made back in September of 2011.   The way the data logger works:

  • The user uses an IR remote control to start a data acquisition of given time and for a given axis.
  • The Arduino starts collecting the information being gathered by an ADXL345 accelerometer chip.
  • Data from the ADXL345 is dumped into a SPI SRAM chip for the given time interval.
  • At the end of the given time interval the contents of the  SRAM are written to a micro SD card in CSV format.

The entire package is slightly taller than a box of matches(35X50X20 mm)  and weighs about 36 grams.  To get the datalogger to work the way I wanted I used the following libraries:

  • Wire.h – for I2C communications.
  • SPI.h – for SPI communications .
  • SPISRAM.h – for communications to SPI SRAM chip.
  • SD.h – for reading and writing to the micro SD card.
  • IRremote.h – for decoding the start trigger from the IR remote.

The really amazing part is that most of the libraries managed to play nice together.

AccLogger_LoggerAndReomote

ADXL345 Data Logger

Here’ what the hardware looks like disassembled:

AccLogger_NoSkin

Data logger without skins.

AccLogger_NoSD

Micro SD card reader removed.

On picture below, parts clockwise from the top: Main Board, Arduino Pro mini, IR sensor, Battery Board, Micro SD Card Reader.  Main board carries the ADXL345 breakout and the SPI SRAM chip.

AccLogger_AllParts

Accelerometer Logger Disassembled

The data is written from SRAM to the SD card as a CSV file.  Below is an example of what a plot of the .csv data looks like in Excel.  The data represents me waving the data logger around with my hand after triggering an acquisition.

datlog for X

Here’s what the code looks like:

 Text |  copy code |? 
001
/****ADXL345 Accelerometer Data Logger*****/
002
/////Arduino Pin Assigments/////
003
/////SPI device assignments
004
/////Digital 13 = Clock
005
/////Digital 12 = MISO
006
/////Digital 11 = MOSI
007
/////Digital 10 = 23k256 SRAM Chip Select
008
/////Digital 7 = 23k256 SRAM Hold
009
/////Digital 9 = SD Chip Select
010
 
011
/////Other Arduino Pin Assigments/////
012
/////Digital 8 = IR sensor input
013
 
014
/////Digital 4 = X LED
015
/////Digital 5 = Y LED 
016
/////Digital 6 = Z LED
017
/////Digital 3 =
018
/////Digital 2 = GTrigger indicator //Feature addition
019
 
020
/////I2C device Assigments
021
/////Analog 5 = Clock
022
/////Analog 4 = SDA
023
 
024
 
025
///config ADXL///
026
#include <Wire.h>
027
#define I2C_ADXL345 (0x53)    //ADXL345 device address
028
 
029
 
030
byte buff2[2];//2 bytes buffer for saving data read from the device
031
byte buff6[6];//6 bytes buffer for saving data read from the device
032
char str[512];      
033
int regAddress = 0x32;   //first axis-acceleration-data register for: X=0x32, Y=0x34, Z=0x36
034
///config ADXL///
035
 
036
///config SRAM///
037
#include <SPI.h>
038
#include <SPISRAM.h>
039
SPISRAM myRAM(10); // CS pin
040
char buffer[128];
041
int SRAMHOLD=7;
042
///config SRAM///
043
 
044
///config SD///
045
#include <SD.h>
046
File logfile;
047
int CSSD=9;
048
///config SD///
049
 
050
///config IR///
051
#include <IRremote.h>
052
int RECV_PIN = 8;
053
IRrecv irrecv(RECV_PIN);
054
decode_results IRresults;
055
///config IR///
056
 
057
///config axis indicator LED///
058
const int XLED =  4;
059
const int YLED =  5;
060
const int ZLED =  6;
061
///config axis indicator LED///
062
 
063
///other prog variables
064
unsigned long starttime;
065
unsigned int reading;
066
unsigned int loops;
067
unsigned int AxisToRead; // 1,2,3,4 = x,y,z,xyz respectively
068
unsigned int Gs = 2;
069
int xram;
070
int yram;
071
int zram;
072
int x, y, z;
073
 
074
 
075
void setup()
076
{
077
  Serial.begin(115200);  // start serial for output
078
 
079
  ///Setup LED digital out///
080
  pinMode(XLED, OUTPUT); 
081
  pinMode(YLED, OUTPUT);
082
  pinMode(ZLED, OUTPUT);
083
 
084
  ///Setup LED digital out///
085
 
086
  ///Setup ADXL///
087
  Wire.begin();        // join i2c bus (address optional for master)  
088
  writeTo(I2C_ADXL345, 0x2D, 0);      
089
  writeTo(I2C_ADXL345, 0x2D, 16);
090
  writeTo(I2C_ADXL345, 0x31, 64); //set range of measurement 64=2g 65=4g 66=8g 67=16g
091
  writeTo(I2C_ADXL345, 0x2C, 14); //set data rate 14 = 800Hz 15 = 1600Hz
092
  writeTo(I2C_ADXL345, 0x2D, 8); //start
093
  ///Setup ADXL///
094
 
095
  ///Setup SRAM///
096
  SPI.begin();
097
  SPI.setBitOrder(MSBFIRST);
098
  SPI.setClockDivider(SPI_CLOCK_DIV2);
099
  SPI.setDataMode(SPI_MODE0);
100
  pinMode(SRAMHOLD, OUTPUT);
101
  digitalWrite(SRAMHOLD, HIGH);
102
  ///Setup SRAM///
103
 
104
  ///Start IR receiver///
105
  irrecv.enableIRIn(); 
106
  ///Start IR receiver///
107
 
108
  reading = 0 ;
109
  starttime = millis() ;
110
  Serial.println("*************************start");
111
}
112
 
113
void loop()
114
{
115
  if (irrecv.decode(&IRresults)) 
116
  {
117
    switch(IRresults.value)
118
    {
119
    //set one ir ir input to toggle active axis to measure setting
120
    //set up one ir input to read one axis for nloops 
121
    //set up one ir input to read three axis for n loops
122
      case 16187647: //IR Input button 1
123
        AxisToRead = 1;
124
        regAddress = 0x32; //Set address to start reading from adxl for Xonly
125
        SetLED();
126
        break; 
127
      case 16220287: //IR Input button 2
128
        AxisToRead = 2;
129
        regAddress = 0x34; //Set address to start reading from adxl for Yonly
130
        SetLED();
131
        break;
132
      case 16203967: //IR Input button 3
133
        AxisToRead = 3;
134
        regAddress = 0x36; //Set address to start reading from adxl for Zonly
135
        SetLED();
136
        break;        
137
      case 16236607: //IR Input button 4
138
        AxisToRead = 4;
139
        regAddress = 0x32; //Set address to start reading from adxl for XYZ
140
        SetLED();
141
        break;
142
      case 16195807: //IR Input button 5
143
        writeTo(I2C_ADXL345, 0x31, 64); //set range of measurement 64=2g 65=4g 66=8g 67=16g
144
        Gs=2;
145
        loops=2000;
146
        ReadToSRAM(); 
147
        CopyToFlash();
148
        break;        
149
      case 16228447: //IR Input button 6
150
        writeTo(I2C_ADXL345, 0x31, 64); 
151
        Gs=2;
152
        loops=4000;
153
        ReadToSRAM();
154
        CopyToFlash(); 
155
        break;         
156
      case 16212127: //IR Input button 7 
157
        writeTo(I2C_ADXL345, 0x31, 64); 
158
        Gs=2;
159
        loops=6000;
160
        ReadToSRAM();
161
        CopyToFlash(); 
162
        break;            
163
      case 16244767: //IR Input button 8
164
        if (AxisToRead != 4) //Do not acquire 3 axis xyz for 10 seconds because of memory limit
165
        {
166
          writeTo(I2C_ADXL345, 0x31, 64); 
167
          Gs=2; 
168
          loops=15000;
169
          ReadToSRAM();
170
          CopyToFlash();
171
        }    
172
        break;
173
      case 16191727: //IR Input button 9
174
        writeTo(I2C_ADXL345, 0x31, 65); //set range of measurement 64=2g 65=4g 66=8g 67=16g
175
        Gs=4;
176
        loops=2000;
177
        ReadToSRAM(); 
178
        CopyToFlash();
179
        break;        
180
      case 16224367: //IR Input button 10
181
        writeTo(I2C_ADXL345, 0x31, 65); 
182
        Gs=4;
183
        loops=4000;
184
        ReadToSRAM();
185
        CopyToFlash(); 
186
        break;         
187
      case 16208047: //IR Input button 11 
188
        writeTo(I2C_ADXL345, 0x31, 65); 
189
        Gs=4;
190
        loops=6000;
191
        ReadToSRAM();
192
        CopyToFlash(); 
193
        break;           
194
      case 16240687: //IR Input button 12
195
        if (AxisToRead != 4) //Do not acquire 3 axis xyz for 10 seconds because of memory limit
196
        {
197
          writeTo(I2C_ADXL345, 0x31, 65); 
198
          Gs=4; 
199
          loops=15000;
200
          ReadToSRAM();
201
          CopyToFlash();
202
        }    
203
        break;
204
      case 16199887: //IR Input button 13
205
        writeTo(I2C_ADXL345, 0x31, 66); //set range of measurement 64=2g 65=4g 66=8g 67=16g
206
        Gs=8;
207
        loops=2000;
208
        ReadToSRAM(); 
209
        CopyToFlash();
210
        break;      
211
      case 16232527: //IR Input button 14
212
        writeTo(I2C_ADXL345, 0x31, 66); 
213
        Gs=8;
214
        loops=4000;
215
        ReadToSRAM();
216
        CopyToFlash(); 
217
        break;         
218
      case 16216207: //IR Input button 15 
219
        writeTo(I2C_ADXL345, 0x31, 66); 
220
        Gs=8;
221
        loops=6000;
222
        ReadToSRAM();
223
        CopyToFlash(); 
224
        break;            
225
      case 16248847: //IR Input button 16
226
        if (AxisToRead != 4) //Do not acquire 3 axis xyz for 10 seconds because of memory limit
227
        {
228
          writeTo(I2C_ADXL345, 0x31, 66); 
229
          Gs=8; 
230
          loops=15000;
231
          ReadToSRAM();
232
          CopyToFlash();
233
        }    
234
        break;
235
      case 16189687: //IR Input button 17
236
        writeTo(I2C_ADXL345, 0x31, 67); //set range of measurement 64=2g 65=4g 66=8g 67=16g
237
        Gs=16;
238
        loops=2000;
239
        ReadToSRAM(); 
240
        CopyToFlash();
241
        break;        
242
      case 16222327: //IR Input button 18
243
        writeTo(I2C_ADXL345, 0x31, 67); 
244
        Gs=16;
245
        loops=4000;
246
        ReadToSRAM();
247
        CopyToFlash(); 
248
        break;         
249
      case 16206007: //IR Input button 19 
250
        writeTo(I2C_ADXL345, 0x31, 67); 
251
        Gs=16;
252
        loops=6000;
253
        ReadToSRAM();
254
        CopyToFlash(); 
255
        break;           
256
      case 16238647: //IR Input button 20
257
        if (AxisToRead != 4) //Do not acquire 3 axis xyz for 10 seconds because of memory limit
258
        {
259
          writeTo(I2C_ADXL345, 0x31, 67); 
260
          Gs=16; 
261
          loops=15000;
262
          ReadToSRAM();
263
          CopyToFlash();
264
        }    
265
        break;       
266
    }
267
    Serial.print(" IR decode=");
268
    Serial.println(IRresults.value, DEC);
269
    delay(100);
270
    irrecv.resume();    
271
  }
272
}  
273
 
274
 
275
void SetLED() 
276
{  
277
  switch(AxisToRead)
278
  {
279
    case 1:
280
      digitalWrite(XLED, HIGH);
281
      digitalWrite(YLED, LOW);
282
      digitalWrite(ZLED, LOW);
283
      break;
284
    case 2:
285
      digitalWrite(XLED, LOW);
286
      digitalWrite(YLED, HIGH);
287
      digitalWrite(ZLED, LOW);
288
      break;     
289
    case 3:
290
      digitalWrite(XLED, LOW);
291
      digitalWrite(YLED, LOW);
292
      digitalWrite(ZLED, HIGH);
293
      break;     
294
    case 4:
295
      digitalWrite(XLED, HIGH);
296
      digitalWrite(YLED, HIGH);
297
      digitalWrite(ZLED, HIGH);
298
      break;       
299
  }  
300
}
301
 
302
void SetLEDLow()
303
{
304
  digitalWrite(XLED, LOW);
305
  digitalWrite(YLED, LOW);
306
  digitalWrite(ZLED, LOW);  
307
}
308
 
309
 
310
 
311
void ReadToSRAM() 
312
{ 
313
  SetLEDLow(); //  turn off LED as indicator of acquisition
314
  if (AxisToRead != 4)
315
  {
316
    reading = 0 ;
317
    starttime = millis() ; 
318
    while (millis() <= (starttime+loops)) // adjust delay to get 1ms readings
319
    {
320
      readFrom(I2C_ADXL345, regAddress, 2, buff2); //read the acceleration data from the ADXL345   
321
      myRAM.write(reading,buff2[0]);
322
      reading = reading+1;
323
      myRAM.write(reading,buff2[1]);
324
      reading = reading+1;
325
      delayMicroseconds(690);
326
    }  
327
  }
328
  else
329
  {
330
    reading = 0 ;
331
    starttime = millis() ; 
332
    while (millis() <= (starttime+loops)) // adjust delay to get 3ms readings
333
    {
334
      readFrom(I2C_ADXL345, regAddress, 6, buff6); //read the acceleration data from the ADXL345
335
      myRAM.write(reading,buff6[0]);
336
      reading = reading+1;
337
      myRAM.write(reading,buff6[1]);
338
      reading = reading+1;
339
      myRAM.write(reading,buff6[2]);
340
      reading = reading+1;
341
      myRAM.write(reading,buff6[3]);
342
      reading = reading+1;      
343
      myRAM.write(reading,buff6[4]);
344
      reading = reading+1;
345
      myRAM.write(reading,buff6[5]);
346
      reading = reading+1;         
347
      delayMicroseconds(475);
348
    }
349
  }
350
  SetLED();
351
  delay(300);
352
  SetLEDLow();
353
  ///loop to readback values in SRAM////
354
  Serial.print("Number of Readings:");
355
  Serial.println((reading+1)/2, DEC);
356
  delay(2000);
357
//  Serial.println("Reading from SRAM");
358
//  for(int i=0; i < reading; i++) 
359
//    {
360
//      xram = (((int)myRAM.read(i+1)) << 8) | (int)myRAM.read(i);
361
//      Serial.println(xram,DEC);
362
//      i=i+1;
363
//      delay(10);
364
//    }   
365
}
366
 
367
 
368
void CopyToFlash() 
369
{  
370
  if (!SD.begin(9)) 
371
  {
372
    Serial.println("initialization failed!");
373
    for(int l=0;  l < 6; l++)//Blink slow for file write error
374
    {
375
      SetLEDLow();
376
      delay(1000);
377
      SetLED();
378
      delay(1000);
379
    }
380
    return;
381
  }
382
  //pinMode(10, OUTPUT);
383
  Serial.println("initialization done.");
384
  /// create a new file with incrementing filename
385
  char filename[] = "DATLOG00.CSV";
386
  for (uint8_t i = 0; i < 100; i++) 
387
  {
388
    filename[6] = i/10 + '0';
389
    filename[7] = i%10 + '0';
390
    if (! SD.exists(filename)) 
391
      {
392
      // only open a new file if it doesn't exist
393
      logfile = SD.open(filename, O_CREAT | O_WRITE); 
394
      break;  // leave the loop!
395
      }
396
  }
397
  if (! logfile) 
398
  {
399
    Serial.print("couldnt create file");
400
    for(int l=0;  l < 6; l++)//Blink slow for file write error
401
    {
402
      SetLEDLow();
403
      delay(1000);
404
      SetLED();
405
      delay(1000);
406
    }
407
    return;      
408
  }
409
  Serial.print("Logging to: ");
410
  Serial.println(logfile);
411
  if (logfile)
412
  {
413
    SetLEDLow();
414
    switch (AxisToRead)
415
    {
416
      case 1:
417
        logfile.println("X Axis");
418
        break;
419
      case 2:
420
        logfile.println("Y Axis");
421
        break;    
422
      case 3:
423
        logfile.println("Z Axis");
424
        break;      
425
      case 4:
426
        logfile.println("XYZ Axis");
427
        break;         
428
    }
429
    logfile.print("full scale (+/- 512) = +/- ");
430
    logfile.print(Gs);
431
    logfile.println("g");
432
    if (AxisToRead != 4)
433
    { 
434
      logfile.print(reading/2, DEC);
435
      logfile.print(" readings in ");
436
      logfile.print((loops/1000), DEC);
437
      logfile.println(" seconds");
438
      for(int j=0;  j < reading; j++) 
439
      {
440
        xram = (((int)myRAM.read(j+1)) << 8) | (int)myRAM.read(j);
441
        logfile.print((j/2)+1,DEC);
442
        logfile.print(", ");
443
        logfile.println(xram);
444
        j=j+1;
445
        //delay(10);
446
      }
447
    }
448
    else
449
    {  
450
      logfile.print(reading/6, DEC);
451
      logfile.print(" readings in ");
452
      logfile.print((loops/1000), DEC);
453
      logfile.println(" seconds");
454
      for(int j=0;  j < reading; j++) 
455
      {
456
        xram = (((int)myRAM.read(j+1)) << 8) | (int)myRAM.read(j);
457
        yram = (((int)myRAM.read(j+3)) << 8) | (int)myRAM.read(j+2);
458
        zram = (((int)myRAM.read(j+5)) << 8) | (int)myRAM.read(j+4);      
459
        logfile.print((j/6)+1,DEC);
460
        logfile.print(", ");
461
        logfile.print(xram);
462
        logfile.print(", ");
463
        logfile.print(yram);
464
        logfile.print(", ");
465
        logfile.println(zram);                
466
        j=j+5;
467
        //delay(10);
468
      }           
469
    }
470
    SetLED();  
471
  } 
472
  else 
473
    {
474
      // if the file didn't open, print an error:
475
      Serial.println("error opening test.txt");
476
      for(int l=0;  l < 6; l++)//Blink slow for file write error
477
      {
478
        SetLEDLow();
479
        delay(1000);
480
        SetLED();
481
        delay(1000);
482
      }
483
      return;      
484
    } 
485
  logfile.close();    
486
  Serial.println("Write Complete");
487
}
488
 
489
 
490
//---------------- Functions
491
//Writes val to address register on device
492
void writeTo(int device, byte address, byte val) {
493
   Wire.beginTransmission(device); //start transmission to device 
494
   Wire.send(address);        // send register address
495
   Wire.send(val);        // send value to write
496
   Wire.endTransmission(); //end transmission
497
}
498
 
499
//reads num bytes starting from address register on device in to buff array
500
void readFrom(int device, byte address, int num, byte buff[]) {
501
  Wire.beginTransmission(device); //start transmission to device 
502
  Wire.send(address);        //sends address to read from
503
  Wire.endTransmission(); //end transmission
504
 
505
  Wire.beginTransmission(device); //start transmission to device
506
  Wire.requestFrom(device, num);    // request 6 bytes from device
507
 
508
  int i = 0;
509
  while(Wire.available())    //device may send less than requested (abnormal)
510
  { 
511
    buff[i] = Wire.receive(); // receive a byte
512
    i++;
513
  }
514
  Wire.endTransmission(); //end transmission
515
}

Note: this code was probably compiled on a version of the Arduino compiler between 0018 and 0022.

12 comments on “Accelerometer Data Logger with IR Trigger
  1. MIles Scott says:

    What data rate into the SD card were you able to achieve?
    Is there more detail on your project available?

    • sgyoshida says:

      From what I can remember I could get about 800 readings per second. I wanted something like 1000 but couldn’t quite get there.

    • sgyoshida says:

      I posted an example of the data I can collect on an update of the web page – take a look. I haven’t worked on this project for a while.

  2. altafa89 says:

    hi, I tried to do a similar project, but without the IR sensor and with a 9V battery, but my sketch work only if I connect the arduino to pc usb…can you help me?

  3. altafa89 says:

    Hi, i tried to do a similar project but using an arduino micro and another microSD reader, but my application doesn’t work with an external power supply but only when the microcontroller is connected to pc usb…can you help me? do you have any suggestion?

  4. jacob says:

    I cannot find the SPISRAM Library anywhere online. I have only encountered SPI RAM library on the Arduino website. What are the major differences in these libraries, if any? If you have a link to the SRAM Library could you post it? I am trying to test your code in its entirety as a preliminary to ensure I can fit the code with some additions (maybe a display) and subtractions (no IR capability) before I buy parts. Thanks

  5. Alireza says:

    Thank you for your interesting project. I may be rather late reacting to it but if you are out there could you tell me whether the SPI SRAM is necessary? If one replaces arduino pro mini with MEGA do you think the memory problem could be solved?

    And my final question is whether you can combine this with RTC DS3231 which could in turn be adjusted periodically by a GPS module?

    Many thanks in advance for your attention.

    Alireza

    • sgyoshida says:

      I originally built the accelerometer data logger to take measurements while mounted to robotic systems – so I wanted to keep it compact. I don’t think I was aware of the Mega at the time – this project was a few years back. If the Mega has enough memory you may be able to just write the data into a big array and dump it to SD later.

      As for your second question, I’m sure integrating the RTC and GPS module wouldn’t be a problem. There are plenty of libraries supporting both. If you want to make life easier on yourself make sure there is a working library posted for the particular hardware you want to use. You also have to keep in mind your IO pin budget depending on how your components are going to talk to each other.

Leave a Reply to Alireza Cancel reply

Your email address will not be published. Required fields are marked *

*

* Copy This Password *

* Type Or Paste Password Here *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>


Hit Counter provided by orange county property management