kriswiner / MPU9250

Arduino sketches for MPU9250 9DoF with AHRS sensor fusion
1.03k stars 472 forks source link

Inaccurate yaw when reading IMU infrequently (> 300ms between reads). #386

Open jimdinunzio opened 5 years ago

jimdinunzio commented 5 years ago

Hi, I've actually got the 9255 (returns 0x73 for whoami) connected to a nano. I am using the SparkFun 9250 Arduino library which includes your MPU9250 Basic Example code from April 1, 2014 modified by Brent Wilkins July 19,2016 as MPU9250BasicAHRS_I2C. I am trying to use the magnetometer to get a heading and try to keep a bipedal robot walking a straight line by going left, right, or straight to stay on the heading. The step routine is currently synchronous and therefore the calls to read the IMU are infrequent (1hz). I've simplified this example to just adding a delay(1000) call at the end of the loop() of example code mentioned above. With the stock code enabling AHRS i see reasonably stable pitch, yaw, and roll. When I add the delay(1000) at the end the values wildly vary from one line to the next. I thought that it may be required to read the sensor more frequently and discovered that about 10hz is the minimum to get stable values. Question is how to do this properly?

A possible solution I thought was I could use a ISR on the arduino to read the sensor. I use pin 2. I tried to do this but it seems that the 9250 interrupt line is not resetting to low after the status read. It calls the handler once and does not call it again. I could not find specific example code for this. I tried both of these: attachInterrupt(digitalPinToInterrupt(intPin), updateMyIMU, RISING); - seems to result in one call attachInterrupt(digitalPinToInterrupt(intPin), updateMyIMU, HIGH); - results in constantly calling service routine I made the ISR routine immediately read the IMU data, and at its end it reads the INT_STATUS.

Anyway without progress here I'm looking at switching to the SparkFun DMP library which has a pedometer feature which could be especially useful anyway for my application or the Bolder Flight Systems 9250 library which has an interrupt example. But I'll still be using the sensor fusion algorithms you have provided.

Thanks for any help you can offer.

kriswiner commented 5 years ago

You have a choice with the MPU9250 to set the interrupt as latching, so that the status register must be read to unlatch or pulsing so that no read is required to clear. There might even be a configuration setting so that any data read can clear the interrupt. But I would investigate the interrupt configuration and see if it is set the way you want it to be.

Also, Sparkfun has some new MPU9250 sketches they developed from scratch. Maybe these would be better for your application?

On Thu, Sep 12, 2019 at 2:09 AM jimdinunzio notifications@github.com wrote:

Hi, I've actually got the 9255 (returns 0x73 for whoami) connected to a nano. I am using the SparkFun 9250 Arduino library which includes your MPU9250 Basic Example code from April 1, 2014 modified by Brent Wilkins July 19,2016 as MPU9250BasicAHRS_I2C. I am trying to use the magnetometer to get a heading and try to keep a bipedal robot walking a straight line by going left, right, or straight to stay on the heading. The step routine is currently synchronous and therefore the calls to read the IMU are infrequent (1hz). I've simplified this example to just adding a delay(1000) call at the end of the loop() of example code mentioned above. With the stock code enabling AHRS i see reasonably stable pitch, yaw, and roll. When I add the delay(1000) at the end the values wildly vary from one line to the next. I thought that it may be required to read the sensor more frequently and discovered that about 10hz is the minimum to get stable values. Question is how to do this properly?

A possible solution I thought was I could use a ISR on the arduino to read the sensor. I use pin 2. I tried to do this but it seems that the 9250 interrupt line is not resetting to low after the status read. It calls the handler once and does not call it again. I could not find specific example code for this. I tried both of these: attachInterrupt(digitalPinToInterrupt(intPin), updateMyIMU, RISING); - seems to result in one call attachInterrupt(digitalPinToInterrupt(intPin), updateMyIMU, HIGH); - results in constantly calling service routine I made the ISR routine immediately read the IMU data, and at its end it reads the INT_STATUS.

Anyway without progress here I'm looking at switching to the SparkFun DMP library which has a pedometer feature which could be especially useful anyway for my application or the Bolder Flight Systems 9250 library which has an interrupt example. But I'll still be using the sensor fusion algorithms you have provided.

Thanks for any help you can offer.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/386?email_source=notifications&email_token=ABTDLKUBXKA3ZO3XOJTHLLTQJIBLHA5CNFSM4IWBG62KYY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4HK5WUIQ, or mute the thread https://github.com/notifications/unsubscribe-auth/ABTDLKVDGOM62FXP4S7X7N3QJIBLHANCNFSM4IWBG62A .

jimdinunzio commented 5 years ago

Hi Kris, Thanks for the reply. I am sticking with your code because of the really nice sensor fusion feature. I assume that the long synchronous delay is causing the problem with the fusion calculations. Is that right? If I even got this working would the calculations execute in the time required for an ISR? Unfortunately I'm trying to get this working for a contest tomorrow and the interrupt seems to only happen once after reset and then not again! I'm using pin 2 on the nano. Leaving the latching as you have it which is fine. I just do the int status read to clear it. Maybe I'll try your latest version of the code in that _t3 file.

Thanks, Jim

jimdinunzio commented 5 years ago

I ended up giving up with the interrupt and it was a good thing because I simply now pass a yield callback function into the walking code that is called frequently so sensor fusion is stable. Now I'm facing other issues like the robot wobbles back and forth a lot and wanting to move the MPU further away from the servo motor to avoid magnetic field interference.

kriswiner commented 5 years ago

Might try calibrating the sensors.

On Sat, Sep 14, 2019 at 9:16 PM jimdinunzio notifications@github.com wrote:

I ended up giving up with the interrupt and it was a good thing because I simply now pass a yield callback function into the walking code that is called frequently so sensor fusion is stable. Now I'm facing other issues like the robot wobbles back and forth a lot and wanting to move the MPU further away from the servo motor to avoid magnetic field interference.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/386?email_source=notifications&email_token=ABTDLKXF2EWXIVONU64ANCLQJWZJFA5CNFSM4IWBG62KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD6XI2JQ#issuecomment-531533094, or mute the thread https://github.com/notifications/unsubscribe-auth/ABTDLKWMFKONXAAQIAD7TTDQJWZJFANCNFSM4IWBG62A .

jimdinunzio commented 4 years ago

Hi Kris, I finally got a good result for my walking robot walking reasonably straight and turning 180 and going back (https://www.youtube.com/watch?v=WnslkxbpbaU). I just use the magnetometer with the simple calculation: heading = 180.0*atan2(myIMU.my, myIMU.mx)/PI and run the figure 8 mag calibration every time I turn it on, which helped a lot. I previously tried to use the AHRS code after adding a callback function to keep frequent reading of the imu and calling the Mahony update, but the yaw was just not stable. It would keep drifting after the robot stopped. However my solution is subject to magnetic fields. I see other people including Lego Mindstorms users using just the gyroscope data and a PID to drive straight. I have read that the 9250 gyro has rapid drift. A friend told me he very carefully calibrated his gyro (maybe 9150?) and combines its info with wheel odometry for good results. All I see here is a function calibrateMPU9250() which is called on boot up. I am not yet knowledgeable or comfortable with the filtering and sensor fusion algorithms which seem to be a common aspect of using IMUs but make a steep learning curve. But I just need a yaw for an object on level ground so it should be simpler right?

Thanks, Jim

kriswiner commented 4 years ago

Hi Jim,

Pretty impressive for just using the mag. The pre-run calibration seems to be limited to 2 dimensions; for absolute orientation all 3 dimensions need to be sampled for good results. I wonder if this is why you couldn/t make AHRS work? Accel and gyro offset bias correction is usually sufficient for ~4 degree rms heading accuracy with either Madgwick or Mhoney filters as long as you are using good sensors (like the MPU9250 or LSM6DSM+LIS2MDL) and properly calibrate them. In fact, with our latest methods we are getting heading accuracy < 1 degree rms routinely, which is plenty goo fo almost any kind of robot, rolling, flying, or shuffling like yours;>!

On Tue, Nov 12, 2019 at 11:35 PM Jim DiNunzio notifications@github.com wrote:

Hi Kris, I finally got a good result for my walking robot walking reasonably straight and turning 180 and going back ( https://www.youtube.com/watch?v=WnslkxbpbaU). I just use the magnetometer with the simple calculation: heading = 180.0*atan2(myIMU.my, myIMU.mx)/PI and run the figure 8 mag calibration every time I turn it on, which helped a lot. I previously tried to use the AHRS code after adding a callback function to keep frequent reading of the imu and calling the Mahony update, but the yaw was just not stable. It would keep drifting after the robot stopped. However my solution is subject to magnetic fields. I see other people including Lego Mindstorms users using just the gyroscope data and a PID to drive straight. I have read that the 9250 gyro has rapid drift. A friend told me he very carefully calibrated his gyro (maybe 9150?) and combines its info with wheel odometry for good results. All I see here is a function calibrateMPU9250() which is called on boot up. I am not yet knowledgeable or comfortable with the filtering and sensor fusion algorithms which seem to be a common aspect of using IMUs but make a steep learning curve. But I just need a yaw for an object on level ground so it should be simpler right?

Thanks, Jim

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/386?email_source=notifications&email_token=ABTDLKUU3PEXW26DGBH37ADQTOU57A5CNFSM4IWBG62KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOED5FQWY#issuecomment-553277531, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABTDLKRBEWTFDYHSMOOUN4LQTOU57ANCNFSM4IWBG62A .

catchrow1 commented 4 years ago

Hi, Im also using the modified code by Brent wilkins. Pretty new to this but managed to modify to run on Teensy 3.2. I'm now trying to drive a servo but its very lumpy and random. I cannot map the x,z,z ( just looking to get one servo running at the moment!) I declared an int axi at the start then added this command to write to the servo: ...... myIMU.yaw -= 8.5; myIMU.roll *= RAD_TO_DEG;

    axi = map (myIMU.yaw, -16000, 16000, 0, 180) ;
    servo1.write (myIMU.yaw) ;
    //servo1.write (axi) ;

which doesnt work. Any ideas? If i servo1.write ( myIMU.yaw) it runs badly.. Any help or pointers to the right forum greatly appreciated!

Thanks,

Row

kriswiner commented 4 years ago

Mayb Sparkfun or Teensy forums?

On Sun, Nov 24, 2019 at 11:14 AM catchrow1 notifications@github.com wrote:

Hi, Im also using the modified code by Brent wilkins. Pretty new to this but managed to modify to run on Teensy 3.2. I'm now trying to drive a servo but its very lumpy and random. I cannot map the x,z,z ( just looking to get one servo running at the moment!) I declared an int axi at the start then added this command to write to the servo: ...... myIMU.yaw -= 8.5; myIMU.roll *= RAD_TO_DEG;

axi = map (myIMU.yaw, -16000, 16000, 0, 180) ;
servo1.write (myIMU.yaw) ;
//servo1.write (axi) ;

which doesnt work. Any ideas? If i servo1.write ( myIMU.yaw) it runs badly.. Any help or pointers to the right forum greatly appreciated!

Thanks,

Row

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/386?email_source=notifications&email_token=ABTDLKXG4SSF3EINGV5OZ53QVLG7ZA5CNFSM4IWBG62KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFASSLQ#issuecomment-557918510, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABTDLKTXQC7J47Y75CHY5ATQVLG7ZANCNFSM4IWBG62A .

jimdinunzio commented 4 years ago

@kriswiner Thanks for the compliment above. I worked hard to get it even to that point. When I was trying AHRS I was doing a complete figure 8 in 3D, which is hard with a serial line attached for debugging. But I was still having too much drift after the bot stopped moving. So I assume I should keep trying with the AHRS and sensor fusion because it is a superior solution and should be the most stable and mitigate magnetic sources somewhat, correct?. Perhaps I should try to upgrade to the code from MPU9250_MS5637_AHRS_t3.ino. I'd like to read at least some intro to filters like Madgwick/Mhoney, though the original paper is a bit too intense for me right now. I read about a low cost alternate way using "sensor fusion with complementary filter." Is that a decent way to go as well?

Thanks, Jim

kriswiner commented 4 years ago

The ingredients for accurate AHRS in order of importance:

1) quality sensors 2) adequate calibration ...

37) sensor fusion methods

If you are using the MPU9250, you should be getting stable 4 degree rms heading accuracy or better if you are doing 2) no matter the fusion method.

On Tue, Nov 26, 2019 at 10:59 PM Jim DiNunzio notifications@github.com wrote:

@kriswiner https://github.com/kriswiner Thanks for the compliment above. I worked hard to get it even to that point. When I was trying AHRS I was doing a complete figure 8 in 3D, which is hard with a serial line attached for debugging. But I was still having too much drift after the bot stopped moving. So I assume I should keep trying with the AHRS and sensor fusion because it is a superior solution and should be the most stable and mitigate magnetic sources somewhat, correct?. Perhaps I should try to upgrade to the code from MPU9250_MS5637_AHRS_t3.ino. I'd like to read at least some intro to filters like Madgwick/Mhoney, though the original paper is a bit too intense for me right now. I read about a low cost alternate way using "sensor fusion with complementary filter." Is that a decent way to go as well?

Thanks, Jim

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/kriswiner/MPU9250/issues/386?email_source=notifications&email_token=ABTDLKSASNMMPNTGTAXWPNLQVYLERA5CNFSM4IWBG62KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEFIQJ7Q#issuecomment-558957822, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABTDLKUQ36M2CEBKJ5HD573QVYLERANCNFSM4IWBG62A .