Android Magnetic Sensors

I suppose I ought to start with the caveat that all my work has been done on a Samsung Galaxy Y and whilst it is reasonable to suppose that there are similarities between Android phones, it is likely that other manufacturers, and even other phone models, will use different magnetometer chips. Information on the exact chips used is not readily available.

Smart phones provide a lot of equipment in a small package and the lower cost Android phones make a great value platform for embedded development even if you don't use it as a phone. Compare the price/performance against other embedded development platforms that have a processor, colour display, SD Card, USB, WiFi, Bluethooth, Camera, 3-axis accelerometers, 3-axis magnetometers, audio and not to forget a mobile phone. It should be noted that some older models of Android phones do not include magnetometers whilst the very latest models may include gyros. The Galaxy Y runs happily without a SIM card so it can be used just as a development platform. From the point of view of magnetic sensing having so much in a small package could be a disadvantage, lots of electronics means lots of electromagnetic interference.

There are a couple of features that reduce this problem. Firstly the phone has a Flight Mode (or Airplane Mode on American models); enabling this mode switches off all the transmitters. The second is that the magnetometers are always in calibrate mode. What this means is that when the magnetometers are enabled they are constantly reading the magnetic field and setting the direction of the largest value as 0 degrees. The implications of this are that any distortion of the magnetic field changes the calibration but it also means that the phone is very easy to calibrate. In practice calibration is a simple as moving the phone around so that it points in all directions, this can be achieved by waving the phone around in a 3 dimensional figure-of-8 pattern or by performing rotations around all three axes.

Experiments showed that with the phone in Flight Mode the biggest single influence on the calibration was the screen brightness. Varying the brightness, for example by popping up a dialog box on a black background, can put the calibration out by up to 10 degrees. His would seem to be due to the electromagnetic field created by the screen backlight. However as long as the phone is calibrated with the screen at the same brightness as when the magnetometers are to be read then the effect of the backlight is compensated for.

The Android SDK (at least from version 10 upwards) provides a reasonable API for handling the sensors. It is possible to access the sensor data directly but the API has methods for performing the matrix manipulation required to obtain roll, pitch and yaw from the sensor data without a lot of extra work.

To work with the sensors in Android it is necessary to register listeners for specific sensor types with the SensorManager. To determine orientation the orientation listeners are needed for the magnetometers and accelerometers:

m_sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

m_sensorManager.registerListener(sensorEventListener,
				m_sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
				SensorManager.SENSOR_DELAY_NORMAL);
		m_sensorManager.registerListener(sensorEventListener,
				m_sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
				SensorManager.SENSOR_DELAY_NORMAL);

On registering the sensorEventListener the update frequency is specified (e.g. SensorManager.SENSOR_DELAY_NORMAL ), this sets the rate at which the sensors are checked for changed values. The SensorEventListener interface requires an onSensorChanged method which is called every time a sensor value changes. The type of sensor that triggered the call can be determined from the SensorEvent argument. As can be expected from any sensor there is noise on the sensor values which can be smooted by maintaining a moving average of the last n results.

At some point, typically on a sensor value change, it is desirable to compute the phone orientation and display the result. The phone's axes are named as shown below.

The method SensorManager.getRotationMatrix (float[] R, float[] I, float[] gravity, float[] geomagnetic) is provided to do this. Here R is the computed rotation matrix, I the computed inclination matrix and gravity and geomagnetic are the input sensor values. The following computes the rotation matrix and then the yaw, pitch and roll, where yaw is about the Z axis and pitch about the X axis.

if (SensorManager.getRotationMatrix(rotationMatrix, null, aveAccels, aveMags)) {
float[] orientation = new float[3];
SensorManager.getOrientation(rotationMatrix, orientation);
}

Whilst this works with the phone in normal orientation, i.e. screen parallel with the ground in portrait mode, it is convenient to be able to use the phone at other orientations. The method SensorManager.remapCoordinateSystem is used to do this. It allows the position of the phones axes to be specified with respect to their real world equivalents, e.g. if the phone is vertical on it's right hand side then the phone's X axis is pointing in the real-world Z direction then X is remapped to Z:

SensorManager.remapCoordinateSystem(rotationMatrix,
                        SensorManager.AXIS_Z, SensorManager.AXIS_Y,
                        remapMatrix);

See computeOrientation in Orientation.java (available at the bottom of this linked page) for the full example.