I helped attach an accelerometer to a robot at ISU, which has been featured on Discovery Channels show, Brink.

arduino taped onto robots arm

Accelerometer taped onto robot finger
We used an adxl345 digital accelerometer with the breakout board from sparkfun.com, in addition to an arduino.
We used the I^2c wire arduino library. This was a temporary solution so that the research assistants can gather surface texture data to see if it is possible to categorize surfaces based on touch, essentially giving the robot a sense of touch similiar to our fingers.
The final project will most likely include several accelerometers and some sort of pic, hopefully sampling at 1200 Hz, the maximum sampling rate of the accelerometer.
We were only able to sample at 500 Hz max. The limiting factor was the serial port speed. 230400 baud was the highest speed we could use without getting gibberish input on the serial port. This proves that it is possible to go past what the Arduino documentation for the serial library says here.
We also noticed that the variance increased with the frequency, and so the usefulness of the higher sampling rate obtaining more data is still being analyzed.
The two signal wires are connected to analog in 4, and 5
The two interrupt wires are open
The rest are either held high, or low at 3.3V and Gnd off of the arduino.
Here is the arduino code we created:
/* The MIT License Copyright (c) <2009> < Vlad Sukhoy, Joe Coleman , Ritika Sahai , Nate Nuzum > Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * Arduino Duemilanove programming to read the data from ADXL345 accelerometer. * This code is a part of tactile sense implementation in rc. * * It is not advised to use this code at data rates above 400 Hz (bandwidth = 200 Hz) * as Arduino serial I/O cannot keep up with the accelerometer at those bandwidths. * The actual data rate we can achieve is about 500 Hz, however the accelerometer * only supports data rates <= 400 Hz or >= 800 Hz, so we cannot get 500 Hz without * discarding some of the data. * * Using binary coding we might be able to actually transfer at 800 Hz. * Using compression we might be able to transfer however much we like, but this * will depend on the properties of the data stream. * * In scratching study we might not really need all 3 vectors, but the magnitude of the * deviation from g. Unfortunately, as the device might turn we don't really * know where g points to, so we smooth the acceleration vector and use that value * for g. If we settle down on that logic, it can be pushed down to Arduino and then we * only need to transfer one value per measurement which, together with binary coding * and/or compression should put us at 2000+ Hz. * * Authors: * Vlad Sukhoy * Joe Coleman * Ritika Sahai * Nate Nuzum */ #include < Wire.h > // The address of the accelerometer device in terms of Arduino board #define ADXL_ADDR ((byte)0x1d) // The bandwidth to use for the serial port // It appears that Duemilanove only supports up to 230400 bits per second #define SERIAL_BANDWIDTH 230400 #define BUFSIZE 1024 enum registers { power_ctl = 0x2d, bw_rate = 0x2c, data_format = 0x31, datax0 = 0x32, datax1, datay0, datay1, dataz0, dataz1, fifo_ctl = 0x38, fifo_status = 0x39 }; // bits for the POWER_CTL register enum power_ctl { pc_link = (1 << 5), pc_auto_sleep = (1 << 4), pc_measure = (1 << 3), pc_sleep = (1 << 2), pc_wakeup_mask = 3, // Frequency of readings in sleep mode pc_wakeup_8hz = 0, pc_wakeup_4hz = 1, pc_wakeup_2hz = 2, pc_wakeup_1hz = 3 }; // bits and masks for the BW_RATE register enum bw_rate { bw_low_power = (1 << 4), bw_rate_mask = 0xf, // low power modes, the number of Hz is the bandwidth. the data rate is 2x that bw_lp_200hz = bw_low_power | 0xc, bw_lp_100hz = bw_low_power | 0xb, bw_lp_50hz = bw_low_power | 0xa, bw_lp_25hz = bw_low_power | 0x9, pw_lp_12dot5hz = bw_low_power | 0x8, pw_lp_6dot25hz = bw_low_power | 0x7, // regular modes bw_1600hz = 0xf, bw_800hz = 0xe, bw_400hz = 0xd, bw_200hz = 0xc, bw_100hz = 0xb, bw_50hz = 0xa, bw_25hz = 0x9, bw_12dot5hz = 0x8, bw_6dot25hz = 0x7, bw_3dot125hz = 0x6 }; // bits and masks for the DATA_FORMAT register enum data_format { df_self_test = (1 << 7), df_spi = (1 << 6), df_int_invert = (1 << 5), df_full_res = (1 << 3), df_justify = (1 << 2), df_range_mask = 0x3, df_range_2g = 0x0, df_range_4g = 0x1, df_range_8g = 0x2, df_range_16g = 0x3 }; enum fifo_ctl { fc_mode_bypass = 0, fc_mode_fifo = (1 << 6), fc_mode_stream = (1 << 7), fc_mode_trigger = (3 << 6), fc_trigger = (1 << 5), fc_samples_mask = 0x1f, fc_samples_32 = 0x1f }; enum fifo_status { fs_fifo_trig = (1 << 7), fs_entries_mask = 0x3f }; // transmit a register value to the accelerometer static inline void reg_set(byte regid, byte value) { Wire.beginTransmission(ADXL_ADDR); byte data[] = {regid, value}; Wire.send(data, sizeof(data)/sizeof(data[0])); Wire.endTransmission(); } // receive a register value from the accelerometer static inline byte reg_get(byte regid) { Wire.beginTransmission(ADXL_ADDR); Wire.send(regid); Wire.endTransmission(); Wire.requestFrom(ADXL_ADDR, (byte)1); return Wire.receive(); } static inline byte fifo_entries() { return reg_get(fifo_status) & fs_entries_mask; } // one accelerometer measurement struct measurement { int16_t data[3]; }; static inline struct measurement reading() { // read 6 bytes from the accelerometer data registers and put the bytes in order struct measurement rv; Wire.beginTransmission(ADXL_ADDR); Wire.send(datax0); Wire.endTransmission(); Wire.requestFrom(ADXL_ADDR, (byte)6); int i; byte lsb, msb; for (i=0; i< sizeof(rv.data)/sizeof(rv.data[0]); ++i) { lsb = Wire.receive(); msb = Wire.receive(); rv.data[i] = (((int16_t)msb) < < 8) | lsb; } return rv; } void setup() { Serial.begin(SERIAL_BANDWIDTH); Wire.begin(); // Join I2C bus as a master reg_set(power_ctl, 0); // stand by reg_set(bw_rate, bw_200hz); // bandwidth reg_set(data_format, df_range_2g); // request 2g resolution reg_set(fifo_ctl, fc_mode_fifo | fc_samples_32); // request 32 entry FIFO (max) reg_set(power_ctl, pc_measure); // start measuring } void loop() { byte n, b[BUFSIZE]; int bsz = 0; struct measurement m; while ((n = fifo_entries())) { while (n--) { m = reading(); bsz += sprintf((char*)&b[bsz], "%d\t%d\t%d\r\n", (int)m.data[0], (int)m.data[1], (int)m.data[2]); if (bsz > BUFSIZE - 30) goto quit; } } quit: Serial.write(b, bsz); }
#1 by guest on November 6, 2009 - 12:02 am
Quote
byte lsb, msb;
for (i=0; i<< 8) | lsb;
}
in the read routine. Is there something missing here? I presume you are creating and int out of the lsb and msb for the x value…but the syntax/construct looks strange
[Translate]
[Reply]
#2 by Nate on November 6, 2009 - 10:22 am
Quote
Ah, yes there was a problem with the html escaping. It’s fixed now.
[Translate]
[Reply]
#3 by guest2 on November 21, 2009 - 11:20 am
Quote
May I ask what pull-up resistor values you used for the SDA and SCL lines? Thank you.
[Translate]
[Reply]
Nate Reply:
November 26th, 2009 at 1:20 pm
@guest2-
We actually didn’t use resistors, and connected it straight to the arduino pins specified for those. We were a little confused about the pull up resistors, but it seemed to work without them. We were thinking it might effect the bandwidth of the measurements, but not really sure. You should reply if you investigate more into this topic.
Thanks
[Translate]
[Reply]
#4 by EyeTic on November 25, 2009 - 5:18 am
Quote
Hi!
I’ve managed to work out the data reading from the adxl345, how do I translate the values to g’s though? The pos/neg doesn’t seem to be consistent, and I can’t figure out how to arrange the bits so that I get it in the right format
Thanx!
[Translate]
[Reply]
Nate Reply:
November 26th, 2009 at 1:14 pm
@EyeTic-
Well, for our application, we didn’t need to do this, but I may be able to tell you which direction to go.
Each individual axis has three positions that can allow you to translate output from accelerometers into g’s.
Pointing an axis down should be the value corresponding to 1g, pointing it up should be -1g, and having it horizontal should be the zero value. Using these three points for each axis you should be able to do a linear regression and get a transform function for each axis.
[Translate]
[Reply]
#5 by EyeTic on December 3, 2009 - 3:11 pm
Quote
Nate thanx! I’ve managed to translate it well enough for my app! The problem was mixed types, I used chars instead of bytes, and it pretty much messed up the readings…
You can see the final thingie here: http://www.youtube.com/watch?v=BJeohcZssBU
[Translate]
[Reply]