Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iot.Device.Imu.Mpu6050 - System.IO.IOException on .CalibrateGyroscopeAccelerometer() #2356

Open
mfitconsultants opened this issue Oct 2, 2024 · 9 comments
Labels
bug Something isn't working Priority:2 Work that is important, but not critical for the release

Comments

@mfitconsultants
Copy link

I am struggling to calibrate an Mpu 6050 specifcially it is a;

Adafruit MPU-6050 6-DoF Accel and Gyro Sensor - STEMMA QT Qwiic

which is connected to a Raspberry Pi 2.

When I try to call the .CalibrateGyroscopeAccelerometer(); method I get the error;

System.IO.IOException: Can set GyroscopeBandwidth, desired value Bandwidth0184Hz, stored value Bandwidth0250Hz

 public HardwareAccelerometerController(
     ILogger<HardwareAccelerometerController> logger,
     int i2cAddress,
     int recalibrationIntervalMinutes,
     int i2cBusId = 1)
 {
     _logger = logger;

     try
     {
         var i2cSettings = new I2cConnectionSettings(i2cBusId, i2cAddress);
         var i2cDevice = I2cDevice.Create(i2cSettings);

         _mpu6050 = new Mpu6050(i2cDevice);  // Initialize the MPU6050
         _logger.LogInformation($"MPU6050 initialized with I2C address {i2cAddress} on bus {i2cBusId}.");
     }
     catch (Exception ex)
     {
         _logger.LogError(ex, $"Failed to initialize MPU6050 with I2C address {i2cAddress} on bus {i2cBusId}. Check connections and configuration.");
         throw new InvalidOperationException("MPU6050 initialization failed. Ensure the device is connected and configured correctly.", ex);
     }

     _recalibrationIntervalMinutes = recalibrationIntervalMinutes;
     _lastCalibrationTime = DateTime.Now;
 }

 /// <summary>
 /// Calibrate the accelerometer and gyroscope.
 /// </summary>
 public async Task CalibrateAsync()
 {
 if (_mpu6050 == null)
 {
     _logger.LogError("Cannot calibrate MPU6050 because it is not initialized.");
     throw new InvalidOperationException("MPU6050 is not initialized.");
 }

 await Task.Run(() =>
 {
     _logger.LogInformation("Calibrating MPU6050...");
     try
     {
         _mpu6050.CalibrateGyroscopeAccelerometer();
         _logger.LogInformation("Calibration complete.");
     }
     catch (IOException ex)
     {
         _logger.LogError(ex, "Failed to set the GyroscopeBandwidth. Proceeding with default bandwidth.");
     }
 });
}

From the logger the device is initilised;

MPU6050 initialized with I2C address 104 on bus 1.

From running sudo i2cdetect -y 1 on the pi I get

     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

So the unit is present - i have also tried the a python sript which is returning data from the unit.

I have also tested

                    _logger.LogInformation($"MPU6050: Accelerometer X:{_mpu6050.GetAccelerometer().X}, Y:{_mpu6050.GetAccelerometer().Y}, Z:{_mpu6050.GetAccelerometer().Z}");
                    _logger.LogInformation($"MPU6050: Gyroscope X:{_mpu6050.GetGyroscopeReading().X}, Y:{_mpu6050.GetAccelerometer().Y}, Z:{_mpu6050.GetAccelerometer().Z}");

Prior to calling the CalibrateGyroscopeAccelerometer() method which return values. attmepting after the exception leads to 0,0,0 being returned.

I cannot find any detail on this specific error? Can anyone tell me how to debug this and what I may be doing wrong please?

@mfitconsultants mfitconsultants added the bug Something isn't working label Oct 2, 2024
@Ellerbach
Copy link
Member

It's been a long time I haven't look at it. But seems you have to set a specific bandwidth before calibrating. Have you tried this? The error message seems to indicate that.

@mfitconsultants
Copy link
Author

@Ellerbach

Thanks for the reply. Yes I have tried this, see the example code below;

try
{
    _logger.LogInformation($"Gyroscope bandwidth is set to {_mpu6050.GyroscopeBandwidth}");
    _logger.LogInformation($"Attempting to set the gyroscope bandwidth to Bandwidth0184Hz.");
    _mpu6050.GyroscopeBandwidth = GyroscopeBandwidth.Bandwidth0184Hz;
    _logger.LogInformation($"Gyroscope bandwidth successfully set.");

    _logger.LogInformation($"Attempting to set the accelerometer bandwidth to Bandwidth0184Hz.");
    _mpu6050.AccelerometerBandwidth = AccelerometerBandwidth.Bandwidth0184Hz;
    _logger.LogInformation($"Accelerometer bandwidth successfully set.");
}
catch (IOException ex)
{
    _logger.LogError(ex, $"Failed to set the bandwidth. Exception: {ex.Message}");
}

The output logs shows it appears to be set to the Bandwidth0184Hz value, but then when .CalibrateGyroscopeAccelerometer() is called I get the same error message?

(To note it is only this class using the device so it can't be set elsewhere). I've tried setting this both in the constructor and directly prior to calling .CalibrateGyroscopeAccelerometer().

On top of this I have tried setting the MPU bandwidth directly on the pi

sudo i2cset -y 1 0x68 0x1A 0x01  # Set gyroscope bandwidth to 184Hz
sudo i2cset -y 1 0x68 0x1D 0x01  # Set accelerometer bandwidth to 184Hz

and then confimed the change with

sudo i2cget -y 1 0x68 0x1D
sudo i2cget -y 1 0x68 0x1A

which confirms the output is set to 0x01.

However, then when I run my service and run sudo i2cset it reverts back to 0x00?

Just to note as well if I call;

                    _logger.LogInformation($"Reading MPU values - start");
                    _logger.LogInformation($"MPU6050: Accelerometer X:{_mpu6050.GetAccelerometer().X}, Y:{_mpu6050.GetAccelerometer().Y}, Z:{_mpu6050.GetAccelerometer().Z}");
                    _logger.LogInformation($"MPU6050: Gyroscope X:{_mpu6050.GetGyroscopeReading().X}, Y:{_mpu6050.GetAccelerometer().Y}, Z:{_mpu6050.GetAccelerometer().Z}");
                    _logger.LogInformation($"Reading MPU values - end");


                    _logger.LogInformation($"Gyroscope bandwidth is set to {_mpu6050.GyroscopeBandwidth}");
                    _logger.LogInformation($"Attempting to set the gyroscope bandwidth to Bandwidth0184Hz.");
                    _mpu6050.GyroscopeBandwidth = GyroscopeBandwidth.Bandwidth0184Hz;
                    _logger.LogInformation($"Gyroscope bandwidth now set to {_mpu6050.GyroscopeBandwidth}");

                    _mpu6050.CalibrateGyroscopeAccelerometer();
                    _logger.LogInformation("Calibration complete.");

I do get values returned from the unit the example output first time is

Reading MPU values - start
MPU6050: Accelerometer X:0.4944203, Y:-0.23344299, Z:8.300994
MPU6050: Gyroscope X:-1.1138916, Y:-0.19992298, Z:8.300994
Reading MPU values - end

which then after the calibration failing just then outputs 0?

Equally if do not calibrate the MPU I can read data from the unit (though I am I not sure how accurate this is).

@krwq krwq added Priority:2 Work that is important, but not critical for the release and removed untriaged labels Oct 3, 2024
@krwq
Copy link
Member

krwq commented Oct 3, 2024

[Triage] @mfitconsultants can you share the stack trace within our code? (current shows only inside your code). Are you perhaps interested in creating a PR with a fix?

@mfitconsultants
Copy link
Author

No problem. I will put together a basic test program and PR for it.

Stack trace ex.StackTrace from catching the error on CalibrateGyroscopeAccelerometer() is

System.IO.IOException: Can set GyroscopeBandwidth, desired value Bandwidth0184Hz, stored value Bandwidth0250Hz
...        at Iot.Device.Imu.Mpu6050.set_GyroscopeBandwidth(GyroscopeBandwidth value)

Is there any other information I can try to get? I've ordered another mpu6050 to see if it is the unit as well.

@mfitconsultants
Copy link
Author

Added a public repo here

https://github.com/mfitconsultants/MPU6050Test

@mfitconsultants
Copy link
Author

The local company ran out of the 6050 so sent me a Adafruit TDK InvenSense ICM-20948 9-DoF IMU (MPU-9250 Upgrade) (STEMMA QT / Qwiic) × 1 as a replacement.

This looks like it isn't supported? I know not really the right forum, but in the short term to get this project off the ground, could you recommend a unit that works well with this library please?

@Ellerbach
Copy link
Member

@mfitconsultants
Copy link
Author

@Ellerbach It doesn't appear the ICM-20948 is supported - whilst it mentions 9250 (it does mention upgrade) it appears not to be supported. I have tested to make sure and receive the error;

Failed to initialize MPU9250 with I2C address 105 on bus 1. Check connections and configuration.
System.IO.IOException: This device does not contain the correct signature 0x71 for a MPU9250
at Iot.Device.Imu.Mpu9250..ctor(I2cDevice i2cDevice, Boolean shouldDispose, I2cDevice i2CDeviceAk8963)

@Ellerbach
Copy link
Member

Clone the repository and use the project itself to debug. This clone may have a different signature. We saw this in the past and for some devices, we added the possibility to bypass the check. Also make sure it is at the proper address.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working Priority:2 Work that is important, but not critical for the release
Projects
None yet
Development

No branches or pull requests

3 participants