Trashcan Accelerometer

 
The city that I live in provides weekly trash collection services. Customers typically have a 96 gallon trashcan which is left out by the curb early in the morning on a scheduled day. Sometime during the day a large truck arrives and the lone driver/operator activates a giant claw that reaches out, grabs the trash container, lifts it up into the air and empties the contents into the back collection area of the vehicle. Then the giant claw drops the container back down to the ground, retracts and moves on to the next house. The process is very quick and efficient. (See the video further down.)

Watching the truck manhandle my trash container week after week I began wondering what g-forces were exerted on the trashcan by that giant claw? So I decided this would be a good Arduino data collection project.

Hardware

Microcontroller

The microcontroller used in the project was the Arduino (Atmega328) which I have been using in various other projects.

Data Logging

To store the data during collection I ordered and built the AdaFruit Datalogging shield. It has the ability to write data directly to an SD card as well as providing an on board Real Time Clock. Construction was easy with the clear instructions and code samples AdaFruit provides.

Accelerometer

Having never used an accelerometer, I spent some surfing time looking at different types and finally settled on SparkFun's item number SEN-00252 which is a Freescale triple-axis MMA7260QT.

I picked this one because it was a triple-axis sensor on a single IC, because it has selectable ranges of (+/-) 1.5g, 2g, 4g, and 6g, and because it comes on a handy breakout board. For this experiment I set the accelerometer up to have a sensitivity of 2g.


Construction

I decided to create my own simple accelerometer shield to plug into the data logging shield. This would give me flexibility to reuse the accelerometer for other projects later on.

The top view in the image below shows how I attached the accelerometer to a larger circuit board using a nylon standoff. I installed a couple of jumper blocks to let me change the sensitivity of the sensor and also added a switch that the Arduino could read to determine if logging should be running or paused. The bottom view shows the simple point to point solder connections I used.























Here is the schematic of the accelerometer shield.















In total the project has three boards, (clockwise from top left)
The Arduino, the Data Logger shield and the accelerometer shield.



















When assembled the unit looks like this

















Operation


Powering the Arduino with a 9V battery, I then put the sensor package into a small padded box and secured the box to the side of the trashcan with black duct tape.

I had two concerns about this part of the project. The first was that the sensor package would detach from the trashcan and my project would end up in the back of the trash truck, lost forever. Excessive use of duct tape was my attempt to prevent that from happening. My second concern was that the driver might see the sensor box as a “suspicious package” and call authorities. Fortunately neither fear was realized.






















And this image shows the X,Y and Z orientation of the final data collected by the experiment in relation to the trashcan.























Knowing the truck would arrive at my location a few minutes after it entered the neighborhood I waited until the truck was close, activated the Arduino and retreated in order to video tape the experiment.


Note: Turn down the volume on your sound card before playing the video!






The truck and claw did their thing, the data logger and accelerometer did their thing and I was greatly relieved when my project survived intact and didn’t end up in some landfill.


Understanding the Data

An example of the data collected on the SD card is shown below. The first column is the current second of the Real Time Clock. I set up the software to record the X, Y and Z values eight times a second. The next three columns are the noise compensated voltage representations of the X, Y and Z outputs. The raw data is interesting but with a little post processing it can become more meaningful.

58 362.02 473.18 284.60
58 362.36 473.22 284.64
58 361.74 473.70 285.24
58 361.60 473.04 284.68
58 362.46 472.60 285.04
58 365.20 473.58 285.54
58 399.52 459.74 265.58
58 393.02 459.56 309.38
59 368.98 431.16 308.34
59 370.90 543.88 278.78
59 340.14 432.74 293.56

Noise compensation

I found that even just sitting stationary on my workbench the signals the accelerometer output were not noise free so I used a simple moving average algorithm in the Arduino code to compensate. It was simply a matter of taking 50 reading from each sensor and then averaging that value and writing it out to the card. (That is why the recorded values are a float numbers rather than the typical integer number the Arduino 10-bit analog to digital converter outputs.) This technique doesn’t remove all noise but it does smooth it out quite a bit.

All other post processing of the data was done by spreadsheet after the experiment was over.

Calibration

Since it was virtually impossible to orient the sensors to be exactly level in all three directions when attaching to the trashcan, it is important to use a calibration process to remove any tilt the sensors picked up as they sat quietly waiting for the truck.

To do this I averaged 1000 SD card readings for each axis as the sensor remained stationary. This value, converted into g-force (see formula description) when subtracted from each sample sample values (also converted into g-force) gave me a more accurate result of the forces on the trashcan.

Formula for Converting raw data to g-forces

I used the following formula to convert the raw data on the SD card to g force.

((Vref * (ADout / 1024)) – (Vdd / 2)) / Sensitivity

Vref = 5v and is the voltage reference used internally by the Arduino when doing analog to digital conversions.

ADout is the raw data (x, y or z) value recorded on the SD card.

1024 is the number of steps the Arduino 10-bit analog to digital converter splits a full voltage range into..

Vdd = 3.3v is the voltage input to the MMA7260QT accelerometer IC and it is divided by 2 because the sensor records both positive and negative forces. 3.3v/2 = 1.65v so values above 1.65v are positive force and values below 1.65v represent negative force.

Sensitivity is a value taken from the MMA7260QT data sheet. It represents how many mV/g the sensor will output based on the jumper settings inputs of the chip. I set my sensor to use a sensitivity of 2g so this value is 600 mV or 0.6v.

Formula Example

Say for example, from the SD card you find that the value on the X axis at some particular point in time is 602.64 Using the formula:

((5 * (602.62 / 1024)) – (3.3/2)) / 0.6 you get 2.15g the X axis.

The calibration value for the X axis (average of 1000 reading when the sensor was not moving) was 469.62 so using the same formula:

((5 * (469.62 / 1024)) - (3.3/2)) / 0.6 = 1.07 = X axis calibration value.

Subtracting the calibration value from the particular X reading gives the following 2.15g – 1.07g = 1.08g

This means that at that particular point in time, the trashcan was moved in a positive X direction with the force of 1.08g.

It is easy to setup a spreadsheet to list all the raw data, the calibration data for each axis and then have the spreadsheet run the conversion to g-force formula on each data value of raw input.

Finally, again using the spreadsheet, I graphed the g-forces on the trashcan in each of the X Y and Z directions as it was being emptied by the truck.




















Accelerometers are showing up in many devices this days; the Wii, iPhones, iPads, Droids, laptops etc. I hope this project encourages you to get your own accelerometer and perform other experiments.

Arduino Code


   
 /* --------------------------------------  
  MMA7260Q 3-axis accelerometer  
   
  Accelerometer and data collection.  
   
  code released as Open Source  
  feel free to use as you see fit.  
   
 */ --------------------------------------  
   
 // libraries from   
 // http://www.ladyada.net/make/logshield/download.html  
   
 #include <SdFat.h>  
 #include <Wire.h>  
 #include "RTClib.h"  
   
 #define ECHO_TO_SERIAL 0  // 1=echo is on, 0=echo is off  
   
 #define redLEDpin 9  
 #define greenLEDpin 8  
   
 #define x_axis 0  
 #define y_axis 1  
 #define z_axis 2  
 #define startStopSwitch 7  
   
   
 RTC_DS1307 RTC;   
 Sd2Card card;  
 SdVolume volume;  
 SdFile root;  
 SdFile file;  
   
 int sampleSize = 50; // used in moving average   
   
 //---------------------------------------------------------------  
 void error(char *str)  
 {  
  Serial.print("error: ");  
  Serial.println(str);  
  digitalWrite(greenLEDpin, LOW);   
  while(1)  
  {  
    digitalWrite(redLEDpin, HIGH);   
    delay(250);  
    digitalWrite(redLEDpin, LOW);   
    delay(250);     
  };  
 }  
   
 //---------------------------------------------------------------  
 void setup(void)  
 {  
  pinMode(redLEDpin, OUTPUT);  
  pinMode(greenLEDpin, OUTPUT);  
  pinMode(startStopSwitch, INPUT);  
    
  digitalWrite(redLEDpin, HIGH);  
  digitalWrite(greenLEDpin, HIGH);  
    
  Serial.begin(9600);  
   
  // initialize the SD card  
  if (!card.init()) error("card.init");  
    
  // initialize a FAT volume  
  if (!volume.init(card)) error("volume.init");  
    
  // open root directory  
  if (!root.openRoot(volume)) error("openRoot");  
    
  // create a new file  
  // starts with LOGGER00, and next one would be LOGGER01 if  
  // LOGGER00 already exists. THis preserves existing files and  
  // increments the new filename  
  char name[] = "XYZLOG00.CSV";  
  for (uint8_t i = 0; i < 100; i++)   
  {  
   name[6] = i/10 + '0';  
   name[7] = i%10 + '0';  
   //O_CREAT = create file, O_EXCL = only if file doesn't already exist  
   //O_WRITE = open for writing  
   if (file.open(root, name, O_CREAT | O_EXCL | O_WRITE)) break;  
  }  
    
  if (!file.isOpen()) error ("file.create");  
  //Serial.print("Logging to: ");  
  //Serial.println(name);  
   
  // write header  
  file.writeError = 0;  
   
  Wire.begin();   
  if (!RTC.begin())   
  {  
   file.println("RTC failed");  
   #if ECHO_TO_SERIAL  
    Serial.println("RTC failed");  
   #endif //ECHO_TO_SERIAL  
  }  
    
   
  file.println("sec,x-axis,y-axis,z-axis");    
  #if ECHO_TO_SERIAL  
   Serial.println("sec,x-axis,y-axis,z-axis");  
  #endif //ECHO_TO_SERIAL  
   
  // attempt to write out the header to the file  
  if (file.writeError || !file.sync()) {  
   error("write header");  
  }  
    
  digitalWrite(redLEDpin, LOW);  
  digitalWrite(greenLEDpin, LOW);  
  delay(1000);  
   
 }  
   
 //----------------------------------------------------------------------  
 void loop(void)  
 {  
    
  if (digitalRead(startStopSwitch) == LOW)  
  {  
   // user feedback for errors and status  
   digitalWrite(redLEDpin, HIGH);  
   digitalWrite(greenLEDpin, LOW);  
  }  
  else  
  {  
   digitalWrite(redLEDpin, LOW);  
   digitalWrite(greenLEDpin, HIGH);  
   DateTime now;  
    
   // clear print error  
   file.writeError = 0;  
    
   // delay for the amount of time we want between readings  
   delay(100);  
    
   digitalWrite(greenLEDpin, LOW);  
   now = RTC.now();   
   float x = 0;   
   float y = 0;   
   float z = 0;  
     
   // moving average for noise compensation  
   for( int i = 1; i<=sampleSize; i++)  
   {  
    x+= analogRead(0);  
    y+= analogRead(1);   
    z+= analogRead(2);  
   }  
   x = x / sampleSize;  
   y = y / sampleSize;   
   z = z / sampleSize;  
   
   // output format for CSV data on SD card    
   file.print(now.second(), DEC);  
   file.print(", ");  
   file.print(x);  
   file.print(", ");  
   file.print(y);  
   file.print(", ");  
   file.println(z);   
   #if ECHO_TO_SERIAL   
    Serial.print(now.second(), DEC);  
    Serial.print(", ");  
    Serial.print(x);  
    Serial.print(", ");  
    Serial.print(y);  
    Serial.print(", ");  
    Serial.println(z);    
   #endif //ECHO_TO_SERIAL   
    
   if (file.writeError) error("write data");   
   if (!file.sync()) error("sync");  
  }  
   
 }