N900 accelerometer

(wikify slightly)
(Link to python class that gives smoothed values)
Line 129: Line 129:
</source>
</source>
x,y,z are the raw accelerometer measurements values, and the first three variables give text information about the device orientation. In particular, the first one informs about the landscape/portrait state.
x,y,z are the raw accelerometer measurements values, and the first three variables give text information about the device orientation. In particular, the first one informs about the landscape/portrait state.
 +
 +
A python class that gives smoothed accelerometer values is available [http://lesloueizeh.com/jdieter/accelreader.py here].
=== Smoothed C interface ===
=== Smoothed C interface ===

Revision as of 15:42, 13 February 2011

The accelerometer detects orientation and movement of the phone.

Contents

Hardware

The accelerometer in the phone is a LIS302DL.

It is connected through the I2C bus.

It features:

  • Low power consumption
  • Dynamically selectable 2/8 G full-scale.
  • Programmable multiple interrupt generator
    • Click and double click recognition
    • Zero G detection

The click and double click functionality are not implemented in the current software.

The accelerometer is uncalibrated - the sensitivity may vary by around 10% plus or minus per-axis. Ideally this would be able to be calibrated by the user. It is possible to recover the bias and sensitivity by rotating the phone several times, and then finding the best mapping of the resulting ellipsoid to a sphere centered around zero.

The absolute resolution is poor - 18 mG (at 2 G sensitivity) typical. This is fine for detecting the orientation of the phone, but makes most uses that would attempt to integrate the acceleration for detection of position useless.

At the fastest sampling speed, the noise is enough to dither the output, so the resolution is somewhat higher.

Fundamental limitations

For example - with a 9 mG error - there is an acceleration error of 9 centimeters per meter per second.

This means that after 10 seconds, the velocity may be anywhere within a 1.8 m/s (around 4 MPH) band, and the position inaccurate by 4.5 m. After 100 s, the position inaccuracy is up to 450 m (this assumes the orientation of the phone is known exactly).

Bugs

Sometimes the LIS302 in N900 gets massive offset on one or more axes, due to unknown reason (possibly I2C errors). Symptoms: Dialer autorotation fails or gets weird. Even rebooting seems not to help to fix this, but removing battery for some seconds resets the chip.

Software

The accelerometer is supported by the dbus/sysfs infrastructure accelerometers, and the application rotation framework. It is used by much software, including N900Fly and a pedometer widget as well as all applications that support the screen rotating automatically to be up.

Fremantle provides an accelerometer API. There are currently two interfaces available:

  • D-Bus
  • sysfs

See also the related thread at talk.maemo.org.

D-Bus

Thomas Thurman (marnanel) has put together a simple demo of an application using accelerometers using the D-Bus interface. You can find sources and .deb up at http://people.collabora.co.uk/~tthurman/sandcastle/

sysfs

Another way is to use the sysfs file information:

/sys/class/i2c-adapter/i2c-3/3-001d/coord

When reading that file you get 3 values X, Y and Z (provided on one line, separated by white space). Values are in mG (milli G). 1000 = 1 G

Theoretical values from the accelerometers
Position X Y Z
Lying on table (back down) 0 0 -1000
Lying on table (face down) 0 0 1000
Sitting on table (bottom edge down) 0 -1000 0
Sitting on table (right edge down) -1000 0 0
Sitting on table (left edge down) 1000 0 0
Bottom right corner down (approx.) -707 -707 0

These are theoretical values. In real life your mileage will vary.

An example can be found at: [1]

Using the data

The X and Y values can be used to calculate[1] the pitch (that is, clockwise rotation) using the atan2 function (note the inverted sign of y):

 angle_in_radians = atan2(x, -y)

Similar, Y and Z can be used to calculate the roll:

 angle_in_radians = atan2(y, -z)

Python

Using the sysfs interface:

  def get_rotation():
    f = open("/sys/class/i2c-adapter/i2c-3/3-001d/coord", 'r' )
    coords = [int(w) for w in f.readline().split()]
    f.close()
    return coords

And using the D-Bus interface:

import dbus
bus = dbus.SystemBus()             
accel = bus.get_object('com.nokia.mce',
        '/com/nokia/mce/request',
        'com.nokia.mce.request') 
orientation , stand , face , x , y , z = accel.get_device_orientation()

x,y,z are the raw accelerometer measurements values, and the first three variables give text information about the device orientation. In particular, the first one informs about the landscape/portrait state.

A python class that gives smoothed accelerometer values is available here.

Smoothed C interface

This is a C function which returns smooth values from the accelerometer. Designed for applications running at >=25fps (otherwise it lags)

(GPL code extracted from libliqbase: liqaccel.c)

static int ocnt=0;
static int oax=0;
static int oay=0;
static int oaz=0;
 
static const char *accel_filename = "/sys/class/i2c-adapter/i2c-3/3-001d/coord";
 
int liqaccel_read(int *ax,int *ay,int *az)
{
	FILE *fd;
	int rs;
	fd = fopen(accel_filename, "r");
	if(fd==NULL){ liqapp_log("liqaccel, cannot open for reading"); return -1;}	
	rs=fscanf((FILE*) fd,"%i %i %i",ax,ay,az);	
	fclose(fd);	
	if(rs != 3){ liqapp_log("liqaccel, cannot read information"); return -2;}
	int bx=*ax;
	int by=*ay;
	int bz=*az;
	if(ocnt>0)
	{
		*ax=oax+(bx-oax)*0.1;
		*ay=oay+(by-oay)*0.1;
		*az=oaz+(bz-oaz)*0.1;
	}
	oax=*ax;
	oay=*ay;
	oaz=*az;
	ocnt++;
	return 0;
}

C++ Class

This is a simple C++ class based on the sysfs interface. Placed in the public domain by thp. Feel free to improve:

 
#include <stdio.h>
 
#define ACCELEROMETER_FILE_N900 "/sys/class/i2c-adapter/i2c-3/3-001d/coord"
 
class Accelerometer {
    int x;
    int y;
    int z;
 
public:
    Accelerometer() : x(0), y(0), z(0)
    {
        update();
    }
 
    bool update()
    {
        int tmp[3] = {0, 0, 0};
        FILE *fd;
 
        if (!(fd = fopen(ACCELEROMETER_FILE_N900, "r"))) {
            return false;
        }
 
        if (fscanf(fd, "%i %i %i", tmp, tmp+1, tmp+2) != 3) {
            return false;
        }
 
        if (fclose(fd) == EOF) {
            return false;
        }
 
        x = tmp[0];
        y = tmp[1];
        z = tmp[2];
 
        return true;
    }
 
    int getX() { return x; }
    int getY() { return y; }
    int getZ() { return z; }
 
};

Cite error: <ref> tags exist, but no <references/> tag was found