Skip to main content
Up and Coming
May 11, 2013

Tracker DK magnetometer 2-axis, or 3?

UPDATE: I have received a replacement Rift DK, and all three magnetometer axes change as expected.

I am reading Tracker DK raw HID packets with my Raspberry Pi.

Speculation from the i-fixit teardown suggests that the Tracker DK contains a 3-axis magnetometer, and the HID packets sent from the Rift DK contain storage space for three magnetometer axes.
- Invensense MPU-6000 six-axis (gyro + accelerometer) motion tracking controller
- A983 2206—we suspect this is a three-axis magnetometer, used in conjunction with the accelerometer to correct for gyroscope drift

I like how the MPU-6000 (Tracker DK accel/gyro) has built-in sensor fusion. :D
The MPU-6000/6050 devices combine a 3-axis gyroscope and a 3-axis accelerometer on the same silicon die together with an onboard Digital Motion Processor™ (DMP™) capable of processing complex 9-axis MotionFusion algorithms. The parts’ integrated 9-axis MotionFusion algorithms access external magnetometers or other sensors through an auxiliary master I²C bus, allowing the devices to gather a full set of sensor data without intervention from the system processor

My magnetometer values in the Tracker DK HID packets have a fixed value for one axis (roll). The values only change for pitch (elevation) and yaw (heading). I am curious why one magnetometer axis contains a fixed (non-changing) value. Is that normal?

    41 replies

    Up and Coming
    May 18, 2013
    "Sebbi" wrote:
    And yes, I get different values for all 3 magnetometer axis. As described by jherico, you have to think of this as a 3D vector of earths magnetic field. You can derive north/yaw from it and in a limited way even tilt angles (if you know how the local magnetic field is oriented).

    I am using the Tracker DK HID data returned after powering on the Rift DK, without configuring it first. All I do in my main loop is open HID device (0x2833,0x01) if not already open, then send feature report 2, then read a HID packet and extract the data.

    If I only send feature report 2 when I open the device, the Tracker DK *SOMETIMES* stops sending HID packets after about 10 seconds. This behavior seems intermittent (perhaps depending on what Rift apps have been run since the Rift DK was powered on), and I can probably send feature report 2 a lot less often.

    I just tested this again, and I can get my Mag Y and Mag Z values to dither around 0 by pointing my Rift DK North, and tilted downward at about 45-degrees (my geographical lattitude), but my Max X value stays fixed at 27958 no matter how I move my Rift DK.

    What does that third magnetometer axis represent anyway? As I understand this, the magnetic field lines should have the same strength at any rotation around the tangential field line at the point of measurement, so if it really is somehow TRYING to measure sensor rotation, then it makes that this value should not change.

    Can somebody explain to me why my understanding and experience about magnetic fields agrees with my measured Tracker DK data, but seems to disagree with other people are reporting here?

    And what real world coordinate does that Tracker DK HID packet Mag X value represent?
    This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
    Up and Coming
    May 18, 2013
    It shouldn't stay fixed when you rotate the device ... three axis magnetometers are necessary to have tilt compensated compasses (google for algorithms) ;-)

    Regarding the data capture through HID, you need to periodically send a keep alive message (feature report 0x03 with report id 0x08 on the control channel so the Rift doesn't stop sending data.

    I do it like this on Android:
    private static boolean sendKeepAlive(int keepAliveInterval, UsbDeviceConnection connection) {
    synchronized (lock) {
    int command = 0;

    buf[0] = (byte) (command & 0xFF);
    buf[0] = (byte) (command >> 8);
    buf[0] = (byte) (keepAliveInterval & 0xFF);
    buf[0] = (byte) (keepAliveInterval >> 8);


    // http://www.usb.org/developers/devclass_docs/HID1_11.pdf from page 51
    // 0x21 => Send direction
    // 0x09 => Set_Report request
    // 0x0308 => Report Type Feature 0x03 << 8 | Report ID 0x08 (keep alive)
    int len = connection.controlTransfer(0x21, 0x09, 0x0308, 0, buf, 4, 0);
    return len >= 0;
    }
    }


    Are you sure you are parsing values correctly? Magnetometer data starts at byte 56 of the 62 bytes in the package and the values are signed 16 bit integers.
    Up and Coming
    May 18, 2013
    "Sebbi" wrote:
    Are you sure you are parsing values correctly? Magnetometer data starts at byte 56 of the 62 bytes in the package and the values are signed 16 bit integers.

    I am "pretty sure" that it is correct. All the values returned make sense. And I still have no idea what real-world coordinate that fixed MagX value is supposed to represent anyway, even IF it returned a changing value...

    Here are my relevant code snippets:

    typedef __int16 Int16;
    int ORmX,ORmY,ORmZ; // mag
    ...
    unsigned char buf[256];
    Int16 *pi; // int16 ptr
    ...
    pi=(Int16*)buf;
    ORmX=pi[28]; ORmY=pi[29]; ORmZ=pi[30];
    ...
    printf(" MagX: %6d\n",ORmX);
    printf(" MagY: %6d\n",ORmY);
    printf(" MagZ: %6d\n",ORmZ);
    printf("=====================");
    Note that unlike the SDK unpacking code, my simpler and faster code only works on little-endian machines, such as typical x86 and ARM desktop/tablet/embedded computers. And I have conditional typdefs for different compilers.

    Here is some sample output:

    MagX: 27958
    MagY: -872
    MagZ: -3073
    =====================
    MagX: 27958
    MagY: -853
    MagZ: -3083
    =====================
    MagX: 27958
    MagY: -826
    MagZ: -3092
    =====================
    MagX never changes, not even between runs or Rift DK power cycles.

    EDIT: Okay, Google time:
    "Crazy eight's man!
    This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
    Up and Coming
    May 19, 2013
    Hmm ... that's not how magnetometers work. You can get away with 2 axis if the sensor is never tilted, but you need 3 axis to be always able to measure earths magnetic field.

    All values should change when you turn the sensor around and point it in different directions. For an algorithm that computes your heading see https://www.loveelectronics.co.uk/Tutorials/13/tilt-compensated-compass-arduino-tutorial
    Up and Coming
    May 19, 2013
    "Sebbi" wrote:
    Hmm ... that's not how magnetometers work. You can get away with 2 axis if the sensor is never tilted, but you need 3 axis to be always able to measure earths magnetic field.

    All values should change when you turn the sensor around and point it in different directions. For an algorithm that computes your heading see https://www.loveelectronics.co.uk/Tutorials/13/tilt-compensated-compass-arduino-tutorial

    I am using my Tracker DK in its default power-on state, and my magX value never changes despite a wide range of motion.

    Are you saying that the document I quoted was wrong about magX being tied to your longitude? Here is the title and credits for that linked document:
    GEOPHYSICAL COORDINATE TRANSFORMATIONS

    CHRISTOPHER T. RUSSELL

    Institute of Geophysics and Planetary Physics, Univ. of Calif., Los Angeles, Calif. 90024, U.S.A.
    Originally published in Cosmic Electrodynamics, 2, 184-196, 1971. All rights reserved. Copyright 1971 by D. Reidel, Publishing Company Dordrecht-Holland. (Received 12 January, 1971; in revised form 26 March, 1971)

    If that document is not correct, has our understanding of magnetism and geographical coordinates changed since 1971?

    Is a tutorial on the internet more accurate than a published scientific paper? Who can we believe?

    But still, not even the LSB changes on my magX. It seems it should at least change a little (noise bit) if it were a true measurement. However, maxY and magZ seem to be correct for my location.

    Perhaps the magX sensor does NOT correspond to the third magX (longitude-based) geographical coordinate, but is just used for tilt-compensation. I have to remember that they are in different frames of reference. It looks like I need to study tilt-compensation for magnetic sensors now. Your link does use all three axes. But my third axis is still frozen (and therefore useless for tilt compensation).
    This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
    Up and Coming
    May 19, 2013
    No axis of a magnetometer is measuring any geographical coordinate, they all measure the magnetic fields around them (mainly the one that our planet is producing). Since it is a 3D vector you can only measure it with 3 axis ... a 2 axis sensor will only work in a certain configuration (level to the ground).

    Point one axis of your tracker to north, turn the device around so that another axis is pointing north ... it should display the same value. If it doesn't either your tracker has a defect or the sensor reading doesn't work (does it work in the Oculus SDK demos?)

    Your citation was from a geomagnetic coordinate system ... that is not what magnetometers are displaying. It is the same system as the normal coordinate system (lon/lat) that we use, transformed so the z axis points to magnetic north (it is not what a GPS would display 0°/0°) ... the whole paper is about these coordinate transformations (the title gives it away) which has nothing to do with how magnetometers work. The Arduino tutorial is a working code example with good explanations of what everything does and how magnetometers work (thus being more accurate than a paper which doesn't explain a thing about the topic) ;-)
    New Participant
    May 20, 2013
    If I may weigh in here, Sebbi is bang on the money. There's either something wrong with the rift firmware/SDK or you've made a mistake in your code. I run an HMC5883L magnetometer and all 3 values change (as they should) when my sensor is rotated.

    Remember, magnetometers are measuring magnetic field strength on the sensor aligned x-y-z axis only. And that's NOT just the earths magnetic field.

    The sample link Sebbi has provided is a good way to learn how to derive a tilt corrected heading by fusing magnetometer and accelerometer data. Watch out though, it's only good for pitch of around 40 degrees.

    It is imperative though, to calibrate your magnetometer to your surroundings before expecting your magnetometer data to be accurate. I cannot stress this enough... CALIBRATE FIRST, you'll save yourself a lot of future headache. Your mobile phone, computer screen, keyboard & mouse, magnets! etc are all creating distortions in the values your magnetometer is returning.

    The rift SDK provides some rudimentary magnetometer calibration which is a good place to start.

    If you're feeling a little more adventurous I recommend creating an ellipsoid fit calibration matrix from sample data using the form Ax^2 + By^2 + Cz^2 + 2Dxy + 2Exz + 2Fyz + 2Gx + 2Hy + 2Iz = 1 (Yury Petrov). You'll should start with a good spread of samples (10,000+) and the matrix math is a little tricky but it's definitely worth the effort.
    Up and Coming
    May 20, 2013
    "homersimpson" wrote:
    If I may weigh in here, Sebbi is bang on the money. There's either something wrong with the rift firmware/SDK or you've made a mistake in your code. I run an HMC5883L magnetometer and all 3 values change (as they should) when my sensor is rotated.
    ...
    It is imperative though, to calibrate your magnetometer to your surroundings before expecting your magnetometer data to be accurate. I cannot stress this enough... CALIBRATE FIRST, you'll save yourself a lot of future headache. ...

    Thanks. This is a new area of study for me. So far I have only been interested in "good enough for a cool demo" while using minimal code. I have just been using the default uncalibrated values (which actually seem to be rather close except for the fixed magX). Regarding "code mistakes", I published the relevant code snippets I am using above in a previous post. I have used a couple of different methods of unpacking the code, and in both cases the magX is constant for my Rift. I do not know if it starts changing after calibration...

    It sounds like trying to use uncalibrated data could result in a demo that works great on my Rift DK, but perhaps not on others that need different calibration.

    EDIT: Here is a nice description of how to compensate for tilt and other magnetic anomalies:
    http://circuitcellar.com/featured/implement-a-tilt-and-interference-compensated-electronic-compass/
    This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.
    New Participant
    May 20, 2013
    I do not have a rift so I cannot check your code... but it's worth noting, your magX value should change before and after calibration.

    This is my calibration utility:
    magcal-3.jpg
    Raw data is red, calibrated (raw passed through a 4x4 calibration matrix) is blue.
    Notice how distorted and off-center the raw data is? This is caused by a number of magnetic items in the vicinity of my sensor (phone, screen, keyboard, laptop, HMD, headphones etc).

    Seeing as there's no way to predict what and where users magnetic items may be, one can only hope they've followed whatever calibration processes you or Oculus have put in place. If not, their experience may differ (sometimes wildly) from what you've intended.

    That being said, from a development perspective, you should always make sure you've calibrated before experimenting.

    Try plotting the raw data from your rift. A properly calibrated magnetometer should appear close to a centered sphere.
    Up and Coming
    May 20, 2013
    "homersimpson" wrote:
    I do not have a rift so I cannot check your code... but it's worth noting, your magX value should change before and after calibration.

    This is my calibration utility:
    magcal-3.jpg
    Raw data is red, calibrated (raw passed through a 4x4 calibration matrix) is blue.
    Notice how distorted and off-center the raw data is? This is caused by a number of magnetic items in the vicinity of my sensor (phone, screen, keyboard, laptop, HMD, headphones etc).

    Seeing as there's no way to predict what and where users magnetic items may be, one can only hope they've followed whatever calibration processes you or Oculus have put in place. If not, their experience may differ (sometimes wildly) from what you've intended.

    That being said, from a development perspective, you should always make sure you've calibrated before experimenting.

    Try plotting the raw data from your rift. A properly calibrated magnetometer should appear close to a centered sphere.

    I see the need for accurate calibration for "real world" applications, and accurate modelling. But for interesting little demos and games, the default (uncalibrated) data sent from my Rift DK pretty closely matches where North really is, and my 45-degree lattitude. I think that is plenty accurate for gaming use, because the brain can adapt to minor anomalies sufficient for in-game nagivation. A little smooth distortion should be fine as long as there are no discontinuities (nexpected jumps or sign reversals). The returned values in my HID packets actually DO seem to match my real-world geographical coordinates well enough for my purposes (at this time).

    Now, when I get around to using real-world props, they will need to be in the real world right where I see then in VR. For that application, mag sensor calibration certainly makes a lot of sense. Thanks for your information, and the screenshot above. I plan to do something similar when I need more accurate mag sensor values.

    But for now, I think I will continue to use what seems to be working for me (to keep my code small and simple). The reason for this thread is just that I was curious why the magX value in my HID packets was frozen at that unrealistic value...
    This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License.