Calibrating the magnetometer with linear algebra

Posted on
  • Hello,

    I am working on code which calibrates the magnetometer on the puck.js. This hasn't been done, has it? A short review of online resources shows that this can be done using elementary linear algebra (and, apparently, involves distortion coming from 'soft' and 'hard' iron nearby). As seen in the attach picture (projection to the first two coordinates) the data fits on an ellipse. This can be corrected so that the data fits on a sphere centered at zero. The readings on the picture come directly from the magnetometer on a puck.js.

    I am considering writing the whole thing up, but I wanted to know if there is an easy way to acces some "standard" libraries implementing things such as matrix multiplication, diagonalization, or svd decomposition, or such things. I am now in the process of learning how to use modules in node.js, since these things have been implemented, but I'm not sure how that would translate to the puck.js interpreter. Writing the whole thing up in a couple hundred lines seems like an easier way out at this point. But if these tools are available easily, that would be great.

  • Attached picture :)


    1 Attachment

    • bla.png
  • Btw, there is a post somewhere on the forum which gives code which calibrates the magnetometer by taking maximal and minimal values of coordinats, which allows for at least centering the ellipse at the origin. I imagine this is a very good approximation of a solution, and is quite good for many applications. Fitting the data on a sphere would be even better though :D

  • That sounds like a really neat project - it'd be great if you could turn it into a library.

    All we have built-in for maths at the moment is https://www.espruino.com/Vec3, but that won't help you with matrix maths I'm afraid. If it's easier you could use C and the Inline C compiler (but that won't have matrix math built in either)...

    IMO, at least from my experience with Bangle.js the holy grail isn't so much trying to make that ellipse into a sphere, but to add some kind of continuous calibration - because while you can calibrate when you're at your desk, if you stand up and move away from the desk, the effect of the metal in the desk changes and the calibration moves off again.

    I did try some algorithms with bangle.js but without much success, but the best I got was just keeping a min/max and then estimating what the magnetic field strength was, and if eg max got further from min than 2*strength, I move min

  • Right, I will continue coding, and update here. This project might split into a couple of branches, depending on usage. One is that I managed to fit the ellipse to a sphere on my laptop using python and numpy, which does everything one might need with accuracy.

    In order to be able to calibrate on the run, I wanted to have this implemented on the puck itself, so that it can calibrate itself. I ran into an issue, though, which is that I made it save some readings, and then some computations, and it ran out of memory. I figured I'd try running basically the same code on the banglejs2, sourcing the data directly from the puck via bluetooth, and this worked better. However, the code for either puck or banglejs2 is not finished, for lack of libraries, but I have started implementing a simple diagonalization procedure in javascript which won't depend on any libraries. I'd love to pack this up into an app available for the banglejs, as well as a library for the puck. I will maybe have some format related questions when it comes to that.

    In any case, this is part of a project I have been thinking about, which is to use the puck as a running footpod, and get (hopefully) an accurate speed. I hope to post some code on that soon. I might take the puck with me on a run and collect data, to see what calibration is needed out there, and work from there. I certainly shouldn't calibrate the magnetometer at home, since I have two big magnets sitting on my desk.

    Doing continuous calibration "on the run" like that would be great. This might be difficult while running, though, since the puck would for the most part have the same part facing up (given that I won't be doing somersaults on the way, or taking falls at regular intervals, let's hope).

  • I have updated an app [1] to github for Bangle.js, which connects to a Puck.js, obtains some magnetometer data, and then finds the best fitting ellipse to this data. The object cal_data consists of a matrix A, a translation vector v, and a radius r. If the calibration goes as it should, then, if you first translate any reading from the magnetometer by -v, and then multiply the vector by A, then you should land on the sphere with radius r.

    The app is still in a somewhat rudimentary form, but it works.

    When the app is done with data collection and analysis, it displays some numbers on the screen. First, if the three eigenvalues displayed all coincide (more or less), then the data fits on a sphere, more or less, whereas if they are very different, then the ellipse is skewed, indicating 'soft iron distortion', whereas the transation vector indicates 'hard iron distortion (whatever that means).

    I should note that the app tells the Puck.js to stop giving out data after 500 readings, which might be a bit much. However, data collection can be stopped by pressing the button on the Puck.js, it should be enough to let this run for just a couple of seconds, but make sure to rotate the Puck.js around while data is being gathered. Data gathering is indicated by blinking lights on the Puck.js.

    The app also saves the data on the watch. For now, I will be using it for data collection, but the code is ready to be used with any application.

    Right now I am going out for a run, I'll be back soon with new data from outside.

    [1] https://github.com/baldursigurds/calibrtr

  • That sounds great! It might be an interesting thing to add to https://www.espruino.com/apps ?

  • Yes, I hope to have time this week to polish this app a little bit. Is there a procedure to upload an app to the espruino repository?

  • Is there a procedure to upload an app to the espruino repository?

    Not particularly, no - just fork https://github.com/espruino/EspruinoApps and make your changes, and make sure there's a green tick next to your commit (which shows that the checks succeeded - if it's a cross just click on it to find out what failed). After that it should be easy to submit a PR

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Calibrating the magnetometer with linear algebra

Posted by Avatar for jeansnorth @jeansnorth

Actions