The BMA180 is a 3 axis accelerometer with I2C interface.
Looking to buy or find the datasheetLook here.

  • Wide variety of measurment ranges (±1g, 1.5g, 2g, 3g, 4g, 8g and 16g)
  • 14- or 12-bit ADC conversion
  • 2 selectable I2C addresses 0x40 & 0x41
  • Programmable integrated digital filters (no external components necessary)
  • 8 low-pass filters
  • 1 high-pass filter
  • 1 band-pass filter
shop button
  • Programmable interrupt features:
    • Wake-up
    • Low-g detection
    • High-g detection
    • Tap sensing
    • Slope detection
  • 2 main standard modes: low-noise and low-power
  • Sleep mode
  • Wake-up mode
  • Self-test capability

Dimensions: 0.80 x 0.40″

BMA180frontBMA180back

BMA180 Pitch and Roll

Accelerometers can be used for measuring both dynamic and static acceleration. Pitch and Roll are static measurements where gravity is the acceleration being measured.  The earth’s gravity is a constant acceleration where the force is always pointing down to the centre of the Earth. When the accelerometer is parallel with the gravity, the measured acceleration will be 1G, when the accelerometer is perpendicular with the gravity, it will measure 0G. So when rotating the accelerometer around the Z axis gravity will not have any change in the results. This means that a horizontally placed accelerometer can not be used for measuring the yaw component and we must use another device called a magnetometer. All accelerometers will experience acceleration in the range of +1g to -1g as the device is tilted from -90 degrees to +90 degrees due to gravity. In addition will be other forces such as an increace of speed which will impact the accelerometer readings.

In order to define the angles of the accelerometer in three dimensions the pitch, roll and theta are sensed using all three outputs of the accelerometer. Pitch (rho  ρ ) is defined as the angle of the X-axis relative to ground.
Roll (phi φ) is defined as the angle of the Y-axis relative to the ground. Theta θ  is the angle of the Z axis relative to gravity.
In order to determine the angle of tilt, θ, the acceleration is compared to a known position with known  g offset. This can be for instance a horizontal position where the z axis experiences 1g and the other two axis zero g. It is then possible to determine if the g forces acting on the accelerometer are  positive or negative, e.g.  if value is greater than the offset then the acceleration is seeing a positive acceleration, so the offset is subtracted from the value and the resulting value is passed to a tilt algorithm. If the acceleration is negative, then the value is subtracted from the offset.

Unfortunately, this theory can only be applied when the accelerometer is completely static. If the accelerometer is accelerating, there will be other components of acceleration acting on it causing the calculated tilt angle to be inaccurate.  One solution for this problem is low-pass filter the data from the accelerometer. Typically, the acceleration components caused by dynamic movement  only happen in a short period of time, while the gravity acceleration is  permanent. There is another effect which is present in accelerometer which is often reffered to as jitter. This describes the non static nature of the results. They tend to be eratic even when the accelerometer is completely stationary.  By low-pass filtering the data from the accelerometer, we can filter out some of the the unwanted high frequency acceleration components and we are left with only the gravity acceleration which can be used to calculate the tilt angle.  This can even be done using the built in filters in the chip itself. In the example below a 10Hz filter is used. However, the low-pass filter will increase the latency and slow down the response time.

There are other more sophisticated possibilities too such as Paul Badger’s digital smooth. A digital smoothing filter for smoothing sensor jitter. This filter accepts one new piece of data each time through a loop, which the filter inputs into a rolling array, replacing the oldest data with the latest reading. The array is then transferred to another array, and that array is sorted from low to high. Then the highest and lowest 15% of samples are thrown out. The remaining data is averaged and the result is returned. Every sensor used with the digitalSmooth function needs to have its own array to hold the raw sensor values. This array is then passed to the function, for it’s use. This is done with the name of the array associated with the particular sensor.

Many people use gyro’s to complement the accelerometer data. Gyro’s have drift which mean that they over time lose accuracy but in the short term they are very accurate.
What typically happens is that the short term of the gyro and long term of the accelerometer is taken as the dominant factors in a fused set up.
Many different types of filters exist such as Kalman, DCM or complementary.
For now i will show the results of only using the accelerometer data.

You can calculate the two angles for pitch and roll using the formula below.

x2 = bma180.getXValFloat() * bma180.getXValFloat();
y2 = bma180.getYValFloat() * bma180.getYValFloat();
z2 = bma180.getZValFloat() * bma180.getZValFloat();

//X Axis  angle_x = atan(bma180.getXValFloat()/sqrt(y2+z2)) * 360 / PI / 2;
//Y Axis  angle_y = atan(bma180.getYValFloat()/sqrt(x2+z2)) * 360 / PI / 2;

I use the library from fabio Varesano which you can find here
But there are plenty of others around. Just look at the list of links at the bottom of the page and you will find many more.

Below is a short program which demonstrates some of the functionality of this library. Here it is used to calculate pitch and roll angles in degrees.
The listing below gives a short screendump of the output of the program. The last two colums are pitch and roll and the other three are the accelerometer values  expressed in g.
You can download it from here.
[spoiler]

#include <Wire.h>
#include <bma180.h>
BMA180 bma180;
char startcommand = 69 ; // ASCII – E, dec: 69,
char command ; //Command received from PC
float timeStep = 0.2; //200ms. Need a time step value for integration of gyro angle from angle/sec
unsigned long timer;
void setup()
{
Wire.begin();
Serial.begin(38400);
bma180.SoftReset();
bma180.enableWrite();
bma180.SetFilter(bma180.F10HZ);
bma180.setGSensitivty(bma180.G15);
bma180.SetSMPSkip();
bma180.SetISRMode();
bma180.disableWrite();
delay(100);
Serial.print(“nBMA180.inonPress E to start…..n”);
while ( command != startcommand){
if (Serial.available() > 0) { // wait for 1 byte with start command
command = Serial.read();
}
else {
delay(50);
}
}
}
void loop()
{
timer = millis(); //get a start value to determine the time the loop takes
// Using x y and z from accelerometer, calculate x and y angles
float pitch,roll,result,x2, y2, z2;;
bma180.readAccel();
Serial.print(“X = “);Serial.print(bma180.getXValFloat());Serial.print(“,”);
Serial.print(“Y = “);Serial.print(bma180.getYValFloat());Serial.print(“,”);
Serial.print(“Z = “);Serial.print(bma180.getZValFloat());Serial.print(“,”);
delay(20);
// Work out the squares
x2 = bma180.getXValFloat() * bma180.getXValFloat(); // getXValFloat() gets the measured g-force in m/ss
y2 = bma180.getYValFloat() * bma180.getYValFloat();
z2 = bma180.getZValFloat() * bma180.getZValFloat();
//X Axis
pitch = atan(bma180.getXValFloat()/sqrt(y2+z2)) * 360 / PI / 2;
//Y Axis
roll = atan(bma180.getYValFloat()/sqrt(x2+z2)) * 360 / PI / 2;
Serial.print(“Pitch = “);Serial.print(pitch);Serial.print(“,”);Serial.print(“Roll = “);Serial.println(roll);
timer = millis() – timer; //how long did the loop take?
timer = (timeStep * 1000) – timer; //how much time to add to the loop to make it last time step msec
delay(timer); //make one loop last time step msec
}

[/spoiler]

BMA180output

 

This same program is used to link to the processing sketch which visualises this data as an artificial horizon.
This processing sketch can be downloaded from here.

[spoiler]

/**
* Artificial Horizon - PROCESSING sketch
*
* View Pitch and Roll angles from an accelerometer of gyro
*
* By krulkip
* Originally developed by TUTO2002 - tuto2002@gmail.com
* Free software distribution
*/
import processing.serial.*;
Serial myPort; //
PFont myTypeL;
// Conversion factor - Degrees to Radians (2 * PI/360) = 0.01745
float DegToRadians = 0.0174;
int angX = 0;
int angY = 0;
int XA;
int YA;
int XB;
int YB;
int counter=0;
String myString = null;
float num;
int lf = 10; // Linefeed in ASCII
boolean firsttime = true; // Allow time for Arduino to "wake up" in First Cycle
byte start= 0x45; // ASCII - E, dec: 69, hex 45 - Arduino command to "Start" to send data
void setup() {
size(1200, 700);
// The font must be in the "Data" folder
myTypeL = loadFont("Impact-48.vlw");
// List all the serial ports available
println(Serial.list());
// On my PC the port used is COM28.
// In your case it may be different
myPort = new Serial(this, Serial.list()[11], 38400);
myPort.clear();
}
void draw() {
if (firsttime){
delay(1000); // If we do not wait for Arduino to "wake up" we will have lost data sent
firsttime = false;
myPort.write(start); // Send an E to start arduino transmitting data
delay(100);
}
read();
background (204);
textFont(myTypeL, 30);
textAlign (CENTER);
fill(0);
text ( " Artificial Horizon" , width/2 , 40);
textFont(myTypeL, 20);
fill(90);//gray
text ( "Pitch º Roll º " ,600 , 660); // Clear the previous data
fill(0,0,159); // Blue
text ( angX ,550 , 660);
text ( angY ,730 , 660);
horizonte (angX,angY);
// For Me Out NO
if (angX < -44){
angX = 40;
}
if (angY > 85){
angY = -85;
}
delay (20);
}
void horizonte (int angleX, int angleY){
rectMode(CORNERS);
stroke(0);
strokeWeight(1);
fill(51,204,204);// Light Blue
rect(400, 150, 800,550);
int cotaY = int(200*tan(angleY *DegToRadians));
int cotaX = int(200*tan(angleX *DegToRadians));
YA= 350-cotaX+cotaY;
YB= 350-cotaX-cotaY;
println ("Antes " + "YA "+ YA + " YB "+ YB );
// NORMAL tilt (NO sideband)
if (YA >= 150 & YA <550) {
XA = 400;
}
if (YB >= 150 & YB <550) {
XB = 800;
}
// We go above or below
if (YA > 550) {
XA = 600 - 200*(200-abs(cotaX))/cotaY;
YA = 550;
println( "Excep 1 ");
}
if (YA < 150) {
XA = 600 - 200*(200-cotaX)/abs(cotaY);
YA = 150;
println( "Excep 2 ");
}
if (YB > 550) {
XB = 600 + 200*(200 +cotaX)/abs(cotaY);
YB = 550;
println( "Excep 3 ");
}
if (YB < 150) {
XB = 600 + 200*(200-cotaX)/abs(cotaY);
YB = 150;
println( "Excep 4 ");
}
// For debugging
println ("XA "+ XA + " YA "+ YA);
println ("XB "+ XB + " YB "+ YB);
println ();
strokeWeight(2);
fill( 153,51,0);
beginShape();
vertex(XA, YA);
if (YA==150){
vertex(400-1,150-1);
}
vertex(400-1,550+1);
vertex(800+1,550+1);
if (YB==150){
vertex(800+1,150-1);
}
vertex(XB,YB);
endShape(CLOSE);
stroke(152,0,0);
strokeWeight(1);
// AXIS
line (400,350,800,350); // Horizontal axis
line (600,150,600,550); // Vertical axix
// Tilt marks
int angleMark = 40;
textFont(myTypeL, 12);
textAlign(LEFT);
fill(204,255,0);
for (int n =0 ; n <4; n++){
int markX = int(200*tan((angleMark-n*10) *DegToRadians));
line (601,350 - markX, 610, 350- markX); // Upper
line (601,350 + markX , 610, 350+ markX); // Lower = X Negative Angles
text ( (angleMark-n*10), 620, 350+6- markX);
text ( -(angleMark-n*10), 620, 350+6+ markX);
}
strokeWeight(4);
noFill ();
ellipse ( 600,350, 392,392); // Outline
// TRIM Surplus
stroke(204);
strokeWeight(10);
ellipseMode(CENTER);
for (int i=1; i < 170; i=i+10){
ellipse ( 600,350, 403+i,403+i);
}
}

void read() {
while (myPort.available() > 0) {
myString = myPort.readStringUntil(lf);
if (myString != null) {
String[] words=split(myString,",");
String test1="";
String test2="";
for(int i=0;i<words.length;i++)
{
if (i==3) test1=words[i];
if (i==4) test2=words[i];
}

println(test1);
println(test2);
String[] qwerty1=split(test1,"= ");
for(int i=0;i<qwerty1.length;i++)
{
if (i==1) test1=qwerty1[i];
}
println(test1);
println (parseInt(test1));
String[] qwerty2=split(test2,"= ");
for(int i=0;i<qwerty2.length;i++)
{
if (i==1) test2=qwerty2[i];
}
print(test2);
println (parseInt(test2));
angX=(parseInt(test1));angY=-(parseInt(test2));
}
}
}

[/spoiler]

BMA180horizon

BMA180 links.

http://www.schwietering.com/jayduino/
http://www.geeetech.com/wiki/index.php/BMA180_Triple_Axis_Accelerometer_Breakout
http://chaos-its-not-just-a-theory.com/2011/07/30/seismograph/
https://github.com/johnmccombs/arduino-libraries/tree/master/bma180
https://github.com/makerbot/BMA180-Datalogger
http://sodnpoo.com/posts.xml/arduino_with_bma180_and_itg3200.xml
http://www.dsscircuits.com/accelerometer-bma180.html
http://wiki.openmoko.org/wiki/Freerunner_Navigation_Board_v3
http://tom.pycke.be/mav/69/accelerometer-to-attitude
https://sites.google.com/site/giandgisoftwaresolution/troduino-180
http://mbed.org/users/GerritPathuis/code/BMA180_SPI_simple/file/8ce1608bb6f8/main.cpp
https://gitorious.org/blazetablet/kernel/commit/c51fcb2/diffs

This is an IMU board in eagle 1.22L
http://ffimu.org/blog/

 

Leave a Comment