Code Monkey home page Code Monkey logo

Comments (17)

psiphi75 avatar psiphi75 commented on September 27, 2024

Can you show me all the code related to AHRS? How frequently are you calling the magwick update function? It should be around every 5 to 10 ms.

One way to confirm the angle is in radians/ sec is to continuously print out the gyro value of one axis, when you rotate the device by 90 degrees around that axis and take 1 second to make the rotation, the rotation rate should be 90 rad/s.

from ahrs.

Lelelo1 avatar Lelelo1 commented on September 27, 2024
const madgwick = new AHRS({ sampleInterval: 20, algorithm: 'Madgwick', beta: 0.4 });

I read from the sensors:

    gyroscope.subscribe(({ x, y, z }) => {
            this.gX = x;
            this.gY = y;
            this.gZ = z;
        });
    accelerometer.subscribe(({ x, y, z }) => {
            this.aX = x;
            this.aY = y;
            this.aZ = z;
        });
    magnetometer.subscribe(({ x, y, z  }) => {
            this.mX = x;
            this.mY = y;
            this.mZ = z;
        });

Start the updates

setInterval(this.getHeading(), 7);

And get the heading

getHeading() {
        madgwick.update(this.gX, this.gY, this.gZ, this.aX, this.aY, this.aZ, this.mX, this.mY, this.mZ);
        let heading = madgwick.getEulerAnglesDegrees().heading;
        heading %= 360;
        if (heading < 0) {
            heading += 360;
        }
    this.heading = heading;
}

Now in a different location when I point the phone north I get: 106°, 132°, 163°, 205° rotating it each time.

I am not 100% certain yet the raw gyroscope is in radians/second yet. It is a bit harder too see it than the way you explained. I must take the average rotating speed when turning it 90° in a second. But I asked in the apple developer forums just to be sure.

from ahrs.

psiphi75 avatar psiphi75 commented on September 27, 2024

Since you subscribe to the IMU data, you can remove the setInterval function and just do this:

    gyroscope.subscribe(({ x, y, z }) => {
            this.gX = x;
            this.gY = y;
            this.gZ = z;
        });
    accelerometer.subscribe(({ x, y, z }) => {
            this.aX = x;
            this.aY = y;
            this.aZ = z;
        });
    magnetometer.subscribe(({ x, y, z  }) => {
            this.mX = x;
            this.mY = y;
            this.mZ = z;
            this.getHeading()
        });

This would mean that every time you get the magnetometer data you update the heading. It also means you will correctly update the data. Magnetometers generally update less frequently than the accel and gyro. However you would need to detect the sampleInterval, or time elapsed to match the update rate of the magnetometer. You can run the following:

madgwick.update(this.gX, this.gY, this.gZ, this.aX, this.aY, this.aZ, this.mX, this.mY, this.mZ, elapsedTimeMs);

where elapsedTimeMs is the time, in milliseconds, since the last update.

I see that you have set the sampleInterval to 20 ms, but are calling the .getHeading() function every 7 ms. These numbers should be the same.

One other thought is that the heading value may have a different orientation than your phone. From memory the heading should be along the x-axis.

It's likely the raw output is rad/s, but you could try converting it to degrees/sec and see if that helps.

from ahrs.

Lelelo1 avatar Lelelo1 commented on September 27, 2024

I moved getHeading() to magnetometerSubscribe(). And measured the delta time to be 39ms. so I set sampleInterval and madgwickUpdate to 0.039s. Both appears to be given in seconds. Now I can rotate the device successfully. Rotating it back to the same position gives the same heading as before.

However irregardless of orientation I have on the phone when I start the app I get the same heading. Starting the device pointing north gives me 107 degrees - when it should be 0 or 360. Starting app with the phone pointing south gives be 107 degrees.

This is the rotation of x y z on iPhone.

Unfortunately when converting to radians/sec to degrees/sec (180/Pi) the heading will keep changing while the phone is still - never stopping in a fast manner. So it is probably indeed in radians/sec.

Also the Madgwick heading gives me changes when rotating along z axis. The roll and pitch does not change when rotating the phone when placed on a table. So that appears to be in order.

I will investigate further.

from ahrs.

psiphi75 avatar psiphi75 commented on September 27, 2024

That's good that it's working better now. Yes, if the readings go wild when you convert to degrees, then it's almost certain the angles are in radians.

That's strange that the output is always 107 degrees. Try using pitch or roll instead of heading and see if you get an angle. Is 107 degrees when it's on a flat surface? Because I don't see where 107 degrees would come from, normally it would be +/-90 degrees if one of the axes are incorrect.

from ahrs.

Lelelo1 avatar Lelelo1 commented on September 27, 2024

On a flat surface both roll and pitch gives 0 degrees when starting the app which is expected. Rotating in x-axis changes roll. Rotating in y-axis changes pitch. (These are mixed up). Rotating in z-axis changes heading which is correct.

So I changed to:

    gyroscope.subscribe(({ x, y, z }) => {
            this.gX = y;
            this.gY = x;
            this.gZ = z;
        });
    accelerometer.subscribe(({ x, y, z }) => {
            this.aX = y;
            this.aY = x;
            this.aZ = z;
        });
    magnetometer.subscribe(({ x, y, z  }) => {
            this.mX = y;
            this.mY = x;
            this.mZ = z;
        });

Making it correspond to this image. This change didn't help fixing the problem that heading always is 107 degrees on app start though. - regardless of which way the phone is placed on a table.

From heading I get degrees raging from +/-180. On roll I get +/-180. But on pitch degrees raging +/-90. This is strange.

from ahrs.

psiphi75 avatar psiphi75 commented on September 27, 2024

Making it correspond to this image. This change didn't help fixing the problem that heading always is 107 degrees on app start though. - regardless of which way the phone is placed on a table.

That's strange. That sounds like magnetometer related issue. If the magnetometer is not working, then the heading will always remain the same. It's strange that it's 107 degrees though, if the magnetometer was not working, it would start at 0 degrees. The magnetometer is also very sensitive to nearby magnetic materials, e.g. iron, if your table has iron in it. You could try using it in an area without iron, such as outside.

One other issue is that the ARHS algorithm needs to be "warmed up". This is because all it's reference points are set as zero to begin with. To work around this issue you can do something like the following:

if (is_first_reading) {
   for (let count = 50; count > 0; count -= 1) {
           // Initialisation, g*, a*, m* values remain the same.
           madgwick.update(this.gX, this.gY, this.gZ, this.aX, this.aY, this.aZ, this.mX, this.mY, this.mZ);
   }
}

Test with different count values. The update function is computationally intensive, so you want to keep count as small as possible.

From heading I get degrees raging from +/-180. On roll I get +/-180. But on pitch degrees raging +/-90. This is strange.

That's fine. That's the range of Euler angles. It's how the Earth has latitude -90..90 and longitude -180..180.

from ahrs.

Lelelo1 avatar Lelelo1 commented on September 27, 2024

I switched to taking calibrated data on iOS via cmdevicemotion instead of taking raw data directly from cmmotionmanager. I think it in particular helped the magnetometer values - since I have experienced the raw magnetometer data on ios to give away strange values. The device motion api I got the values from updated every 10ms so I set the madgwickUpdate and sampleInterval to 0.01s. It now took 11 seconds every time I started to get an accurate heading. (regardless of what orientation the device had on start)

What I was not completely happy about though was that it most of the time took 50s to 1:40 min to get the correct heading again after the phone has been rotated (rotated 90degrees). So it was very unresponsive.

To reduce the time to get correct heading after rotation the following helped.

    this.gX = -y;
    this.gY = -x;
    this.gZ = -z;

The ios api and this lib does not seem to match in rotation -clockwise/counter-clockwise. So that rotating creates a faultiness that eventually gets corrected by magnetometer - taking time.

Now I have around 7s of responsiveness when the device is rotated and start up time to get correct heading of 11s. I also want to point out that I had to swap x-axis and y-axis with each other on all three sensors to get the correct heading.

from ahrs.

psiphi75 avatar psiphi75 commented on September 27, 2024

Ah, there is no standardised set of coordinate systems. If you use the following transformation (rotate counter-clockwise about the z-axis):

    this.gX = y;
    this.gY = -x;
    this.gZ = z;

it should fix the issues you have.

This will explain why it takes 7 seconds to "catch up". The magnetometer is fighting against all the others because it seems the orientation is incorrect.

Have a look at this video, which shows this AHRS library is use, as you can see the response is near instantaneous. Although this video shows an early version of the library, newer versions are more responsive and more accurate.

Why don't you just use the iOS heading feature?

from ahrs.

Lelelo1 avatar Lelelo1 commented on September 27, 2024

The delay where due to react native which I am using being unable to handle 10 ms update (an apparent limitation in how react native communicates with native code). Using 100ms update I get the flawless responsiveness like in the video.

It was correct to use:

    this.gX = -y;
    this.gY = -x;
    this.gZ = -z;

The following gave the wrong heading on rotation

    this.gX = y;
    this.gY = -x;
    this.gZ = z;

I am looking for a stable bearing I can use regardless of orientation and that can withstand magnetic disturbance. So only using the magnetometer/compass was not sufficient. And heading is not enough as I need to know where north is. I also found that the magnitude seem to change when north reading becomes inaccurate.

This ahrs sensors fusion algorithm indicates this is possible - by introducing a magnitude filter on the magnetometer in uT. However I am not completely sure about the connection between abnormal magnitude reading and inaccuracy of compass

from ahrs.

psiphi75 avatar psiphi75 commented on September 27, 2024

It's good to here you got it going.

What kind of magnetic disturbances are you experiencing? Is it due to nearby ferrous objects, or electromagnetic interference? In general this AHRS works best on unfiltered raw values. Filtering can introduce unwanted bias.

You could try the Mahony algorithm, that may give you better results. You can try to play with the parameters, the Mahony algorithm gives you two parameters to play with. I have found both algorithms to be about the same in responsiveness.

One other thing to consider is to adjust for magnetic north, because true North is usually in a different direction that magnetic north.

from ahrs.

Lelelo1 avatar Lelelo1 commented on September 27, 2024

Yes and thank you for you help.

The magnetic interference arise at certain locations in a city where I live - especially on a certain square - Where the magnitude varies from 25 μT to 120μT (I believe it to be be power lines under ground). Standing outside certain stores also creates interference. Otherwise its relatively stable with 42-45 μT (And geomagnetic data say it should be 50μT in my location) - which produces an accurate compass heading. Actively disturbing the sensor with metal also changes the magnitude.

I asked a question regarding compass accuracy and magnetic field magnitude here.

Using raw magnetometer data the given heading is drastically different and depends on how the device is orientated on app start. Also the magnitude given from raw data is 573 when it should be 47μT. The devicemotion CMCalibratedMagneticField is supposed to be without "device bias" - while the raw magnetometer data has it. I believe device bias means that the components inside the phone interferes with the magnetometer. Devicemotion magnetometer give a magnitude of 45.

Yes I will also have to adjust from magnetic north to true north.

from ahrs.

psiphi75 avatar psiphi75 commented on September 27, 2024

Great to hear it's mostly working. I need to write up better debugging instructions.

from ahrs.

browniefed avatar browniefed commented on September 27, 2024

@Lelelo1 Are you able to expose any of the code you wrote for RN.

I'm running into similar issues attempting to calculate magnetic north from Magnetometer, Accelerometer, and Gyroscope from Expo.

from ahrs.

dmenneck avatar dmenneck commented on September 27, 2024

@Lelelo1 i'm also curios to know if you got the heading up and running!

from ahrs.

Lelelo1 avatar Lelelo1 commented on September 27, 2024

@dmenneck
I don't have that code anymore. And I continued working in Xamarin. For the project in RN: react-native-simple-compass was sufficient for me.
Problem is as I mentioned for calibrated iOS magnetometer readings, the Device Motion api is needed.
There is also device orientation quaternion available on Android and iOS - which I found out was more accurate that Madgwick

from ahrs.

browniefed avatar browniefed commented on September 27, 2024

@dmenneck I ended up finding Java internals and translated it to JS. Here is some code from a while ago.

https://gist.github.com/browniefed/bbfe7067875937e5a95393de2079928a

from ahrs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.