Blog

Recently I’ve been playing with cheap GY-80 module, more precisely 10DOF module with accelerometer, gyroscope, magnetometer and barometer. Eventually I’ll write how to use all four of them. I’ll start with accelerometer (accel). This guide could potentially be used for interfacing most of the MEMS accels, and definitely as a guide how to interpret data coming from the accel, not only from MEMS but also how to use the data coming from Smartphone, wiimote etc. They are basically the same thing. However, I won’t be describing features as tap sensing and double tap sensing, this will be only an introduction about the raw accelerometer.

What is accelerometer anyway?

Short answer, a device that measures the acceleration in a specific direction from gravity and movement. In our case ADXL345 is a 3 axis accel, basically it can measure acceleration in 3 directions simultaneously. On Earth, accelerometer when placed on a flat surface will always measure 9.81m/s2.In most cases you’ll find that acceleration is measured in g-forces, which is basically acceleration felt as weight. Obviously at Earth surface and in restful condition we experience 1G.

In most cases the acceleration is used as a vector quantity, which can be used to sense the orientation of the device, more precisely pitch and roll. Because when you turn the device, the 1G component is distributed among those 3 axes. With simple vector math we can calculate the angle of the device.

Initializing ADXL345

In this tutorial, I’ll be using I2C protocol for communicating with the ADXL345. The basic principle of communication with device is as following. First, you send the address of register you either want to read or write. Then you send the new values to write in the corresponding register or request specific amount of bytes from the device.

The initialization of ADXL345, consists of three things, enabling measurement mode in register POWER_CTL, specifying the data format and setting the offset in registers – OFSX, OFSY, OFSZ.

To start the measurements we just need to set bit 3 in POWER_CTL register, basically we just write 0x08 to it, like so:

writeTo(ADXL345_POWER_CTL, 0x08);

After we have successfully started our ADXL345, we can now specify the data format in other words, the resolution of the measurements. See table below for the register DATA_FORMAT

In our case, we are just interested in 3 bits - D3, D1 and D0. When FULL_RES bit is enabled, the device will run in full resolution mode, in other words, it will always maintain 4mG/LSB. No matter what range is specified, one bit will represent 4mG of acceleration. If it is not enabled the ADXL345 will run in 10-bit mode, and the range bits will determine how many mg/LSB.

The Range bits basically sets the range of the measurements, see table below for possible configurations:

See table below for mG/LSB in different range configurations:

In my case I’ve decided I’ll be using ±16 g range in full resolution, according to my preferences and the table I’ve provided above, I’ve to send 0x0B to the register DATA_FORMAT

writeTo(ADXL345_DATA_FORMAT, 0x0B);

The final step is optional; you can easily have a working accel, without specifying the offset. To compensate for the offset, I’m using the built in registers in the ADXL345 and I’ve added ability to do the same in software as well.

As I mentioned previously, the offset is specified in registers – OFSX, OFSY and OFSZ. The offsets are stored in two compliments format and are automatically added to the output register. However, there is a downside using hardware offset, it is limited to how precise you can specify the offset, due to scale factor of 15.6 mG/LSB. Because of this limitation in the library I added software offset as well, so I can specify the offset in less than 15.6 mG as well. The offset is calculated for each accelerometer separately, don’t use my measurements, you’ll just make your accel to be even less precise.

Reading the raw acceleration and converting to Gs

At this point we are ready to read the data from the accelerometer. The accelerations in raw format are stored in registers – DATAX0, DATAX1, DATAY0, DATAY1, DATAZ0 and DATAZ1.

The results are divided in two 8 bit registers forming 16 bit registers where the format is LSB is first then followed by MSB. Again the data are stored in two’s compliment format. With I2C protocol, it is possible to request multiple bytes in one reading session. So to read the data, you can just provide the address of DATAX0 and request 6 bytes. It is also recommended by the datasheet to prevent a change in data between reads of sequential registers.

After we have read raw data from the acceleration, we need to convert them to Gs. Basically, we just how to multiply the raw data with a pre-calculated constant, which changes according to your “Range” and “full resolution” settings.

In my case, I’m using 16 bit mode and full resolution, which gives me around 3.9mG/LSB. So that means I’ve to multiply the data with 0.0039 to convert the raw data to Gs. See the table above for constants according to your settings.

See the code below on how I’m reading and converting the accelerometer raw data to Gs:

Not that in my readAccelG function I’ve also implemented a simple low pass filter:

res.x = fXg * ALPHA + (xg * (1.0-ALPHA));

Basically, I just take the component of the current accelerometer data and the previous one and sum them up to produce the new acceleration. The ALPHA can be anything between 0 and 1. The lower the ALPHA the lower frequencies will be filtered.

Calculating pitch and roll

One of the most common uses of accelerometer is to measure tilt on a particular axis. Remember, previously I mentioned that accelerometer on a flat surface would produce 1g on one of its axis (most likely Z). The output of accelerometer is not linear but rather a sine wave, so you can’t just convert g-forces proportionately to tilt in degrees.

Measuring tilt with one axis

The simplest way to measure the tilt, is to use only one axis. Basically the inverse of sine function will give you the angle.

So Ɵ = sin-1 (x). However due to nature of sine wave you can measure the tilt reliably from 45° to -45°. Past those points the sensitivity of measurements are significantly reduced.

Measuring tilt with two axis

A slightly more reliable method for calculating tilt, is to use two axis. Then you can measure from 90° to -90°, without any loss to sensitivity. Remember high school geometry:

Using two axes significantly improves the accuracy of measuring the angle. However, if your accelerometer is slightly turned in direction of Y axis, your measurements will again be imprecise, since some of the component of the vector from Z axis will be “lost” to Y axis.

Measuring tilt with three axis

To have the best accuracy when measuring tilt, you must use all three axes to determine the angle. Basically the same arctan equation is used, but instead of simply dividing by one axis, we calculate the magnitude between other two axes.

With the equation above we would calculate the angle between the gravity vector and X axis. Depending how you accelerometer is placed on the board; it can either be pitch or roll.
Basically, you have to determine on which axis for you is roll and on which is pitch.

In my case I calculate the pitch and roll like this:

To implement those two equations in code I used atan2 function, which provided by the math library in C and C++. The atan2 function returns the angle in radians, so again remember high school math that 1 radian = 180/π, which is around ~57°.

Calculating velocity and distance traveled (for educational purposes)

First of all, I advise not to use accelerometer to calculate neither the velocity nor distance, due to integral being only approximate in the code. Because the integral will be only approximation you’ll quickly get an error in your distance and speed. Especially in distance, since to calculate that, you have to use double integral.

First acceleration is change in speed in unit time:

From this we can derive that:

To calculate the velocity, you have to periodically take measurements from the accelerometer and multiply exactly by the time difference and add it to the current acceleration:

The more frequently you’ll take the samples, the less error you’ll have. However, because you can’t take infinite amount of measurements between two units of time, the velocity eventually will generate an error. Most likely it won’t even go back to initial state 0.

To calculate the distance, we just use the following equation:

And again, periodically you must calculate the distance traveled and add to the previously calculated distance:

The same problem applies as to calculating velocity when calculating the distance. Because you can’t have infinite measurements between, your integral will be an approximation and will generate an error. In practice because you would use double integral, the distance will generate the error VERY quickly, mainly because, the speed will never reach 0. It will always be something close to 0, and your distance will just drift in either direction. The more samples you’ll take and the more precise integral you’ll have the less drift you’ll have.

To avoid the drift in distance and velocity, you might want to consider using GPS together with the accelerometer. To fuse those sensors you can either use simple complementary filter or kalman filter. Or just don’t use the accelerometer for measuring distance or velocity

Implementing everything in code (Arduino)

Finally, all the necessary theory has been covered on how the ADXL345 accelerometer works and how to interpret and use the data provided by accelerometers. I won’t be going in detail through the code, because I believe it is self explanatory, especially due to me mentioning and giving examples of code while writing the theory.

It is great for all, I have some different tricks if you want to know it then for that I have some different tricks, for that, you want to learn to code. For that, if you want to know it then for that you just visit some tutorial. And from there it is great for all. If you faced any type...

I have read the post and it is very much helpful because I have got to know about the open cv on the raspberry pi. The images and the screenshots provided here will guide you for your questions. The code you will get here is very unique and can be only used to run OpenCV. If you face any...