Close

Accelerometers are normally noisy.

A project log for GimbalBot

Gimbaled thrusters, aerospace-grade adhesives, carbon-fiber-reinforced polymers, and inertial measurement units. This is a space project!

zakqwyzakqwy 07/02/2014 at 02:042 Comments

Switching platforms was a great call. I got back from a relaxing North Woods weekend and an Adafruit package was waiting; the Due hooked right up after getting my hands on Arduino 1.5.6-r2 (you need this version for Due support). I wired my 9DOF stick up to the I2C bus (in my case, SDA is comm line 20 while SCL is comm line 21), grabbed a demo program mentioned in the product comment section, and tried displaying some data on the serial debug window. It took a bit of putzing (getting addresses right, re-restarting serial communications, that sort of thing) but I got it working; a live data stream showing raw integer values for the accelerometer, gyroscope, and magnetometer. Code is in the dropbox repo under /firmware/ArduinoDue/_9DOF_test1 (click the c code link if you don't want to download the Arduino file).

Getting a data stream set up was great, but the actual values didn't make much sense. The accelerometer's datasheet suggests the device features a 10-bit output; since it's signed, that means I should see integer values between -512 and 511, scaled to +/- 2g (this is selectable during initialization). However, I was getting wild results; sometimes I'd see reasonable numbers in the teens or low hundreds, but turning the board upside-down would make the value hover a bit below 65536. Hmm.. that's 2^16. Seems like we've got an issue with the data type conversion.

The ADXL345 dumps raw data through a pair of bytes for each axis, marked n0 and n1 (where n is the axis, x/y/z). By default, the output is in two's complement format; this article provides a great overview of that concept and talks about how one can do various conversions . In any case, the Arduino compiler is supposed to convert signed two's complement bytes into signed integers automatically using the int() function, but I'm guessing this didn't work right because these are 10-bit values. The ADXL345 is also set up with sign extension, meaning everything to the left of the most significant bit (the 10th, which represents sign) is the same as the most significant bit. Time to modify the function a bit.

I took the _9DOF_test1 program and pretty well gutted it; at this point, I've only messed around with the accelerometer so the magnetometer and gyroscope portions have been removed. I kept [petmar0]'s Wire() calls intact to buffer data from the sensor, but changed how the two bytes are combined to properly convert the two's complement pair to a signed integer. I also took out a few program delay functions and cranked the baud rate up to 115,200 bps; I want a lot of fast data to get a better handle on noise. Take a look at this completed program at /firmware/ArduinoDue/_9DOF_test2 (again, click the c code link if you don't want to download the Arduino file).

I used gtkterm to dump a bit of data from the accelerometer; in the _9DOF_test2 folder, you'll see a few text files with various names related to 'data dump'. The only one I've taken a close look at so far is the file marked 'NoShaking', where I just left the chip on my desk and let it record noise. Note that the files blew up to ~100kb+ in a matter of seconds; I calculated my acquisition rate at 340 samples/second. Speedy!

The spreadsheet [*.ods file] in the _9DOF_test2 folder shows a bit of quick data analysis. For clarity, I changed microseconds to seconds and divided the acceleration values by 256 to get floating point 'g' values. Then I plotted the x record against time:

The blue dotted lines are standard deviation, while the green is the mean. Note the y-axis range; the standard deviation is roughly +/- 0.03g, which isn't bad! 

Kalman filtering assumes the data follows a Gaussian distribution. I didn't run any normality tests, but I did put the data into a histogram to get a feel for its shape:

Looks pretty normal to me, I'll take it. For the stats folks:

xmin: -0.592 g

xmax: -0.326 g

n: 5362

bins: 64

sigma: 0.037

xmean: -0.485

rate: 340 samples/sec

Still to do: take a look at the accelerometer movement records, figure out the magnetometer and gyroscope interface (they also appeared to exhibit the two's complement conversion issue), and start thinking about Kalman filter implementation. 

Comments more than welcome--I'm not great with bitwise stuff and I'd like to make my code as efficient as possible. Let me know your thoughts!

Discussions

Michael O'Brien wrote 07/08/2014 at 03:53 point
Due to having to brush up on some basic Calculus of my own, do you know how distance, velocity, and acceleration are mathematically related?

I have a sensor that gives the movement of a needle responsible for controlling pressure for fuel injection. The output is surprisingly clean. That being said, even though I don't know how much it's moving, I know the voltage output is proportional to the velocity. Numerically integrating the signal gives me the relative position of the needle. Taking the numeric derivative would give me the acceleration.

That being said, after you do some rudimentary calibration, you can take the numeric integration of the accelerometers output and determine the bot's velocity. By the way, velocity is speed with direction, in case you're unfamiliar with the topic.

  Are you sure? yes | no

zakqwy wrote 07/08/2014 at 15:26 point
Yup, I'm familiar with the relationship between distance, velocity, and acceleration; I think that's what actually got basic calculus to stick. Every calc class should start with Newtonian mechanics! (For those following along, velocity is the derivative of position with respect to time, while acceleration is the derivative of velocity. You can reverse the process by integrating.)

I'm less concerned with determining the bot's Cartesian coordinates and velocity vector than I am with determining its angular orientation with respect to gravity; I'll eventually need to know both for navigation and movement, but angular position, velocity, and acceleration are crucial for the stability control loops. As such, the gyroscope is my main tool right now; trouble is, the gyro has a tendency to drift over time, so I need to use accelerometer data (which is noisy but stable) to constantly correct the gyro's angular data. I'll put together a more detailed post that starts discussing sensor fusion in the near future.

What are your thoughts on using accelerometers to determine absolute velocity and position with respect to an arbitrary starting point? I suppose I could use an integration function to calculate relative velocity and position and correct the values periodically using other sensor outputs (such as an air pressure based altimeter).

Thanks for the comment! Out of curiosity, how fast are you reading needle movement for injector pressure? I've done quite a bit with pressure measurement but usually in applications that have a time base measured in seconds.

  Are you sure? yes | no