micropython-IMU / micropython-mpu9x50

Drivers for InvenSense inertial measurement units MPU9250, MPU9150, MPU6050
MIT License
260 stars 82 forks source link

Magnetometer wrong values and freezes esp32 #10

Closed DaneGrinder closed 7 years ago

DaneGrinder commented 7 years ago

HI. I'm back :-)

I've started testing with the mpu9250. Both the standard 9DOF and the newer 10DOF.

The x and z values for the mag vector is frozen. They might very rarely make a blip, but then right back to the frozen value.

i2c = I2C(-1, scl, sda, freq=400000)

imu = MPU9250(i2c)

sens = imu.sensors
while True:
     print(sens[2].xyz)
     print("mag_stale_count: {}".format(imu.mag_stale_count))
     utime.sleep_ms(200)

yields this result when I'm constantly moving the sensors around

(-0.1869141, -14.58692, 0.2244141)
mag_stale_count: 0
(-0.1869141, -14.58692, 0.2244141)
mag_stale_count: 1
(-0.1869141, -7.405664, 0.2244141)
mag_stale_count: 0
(-0.1869141, -3.815039, 0.2244141)
mag_stale_count: 0
(-0.1869141, -3.815039, 0.2244141)
mag_stale_count: 1
(-0.1869141, -14.58692, 0.2244141)
mag_stale_count: 0
(-0.1869141, -46.90254, 0.2244141)
mag_stale_count: 0
(-0.1869141, -7.405664, 0.2244141)
mag_stale_count: 0
(-0.1869141, -7.405664, 0.2244141)
mag_stale_count: 0
(-0.1869141, -29.39824, 0.2244141)
mag_stale_count: 0
(-0.1869141, -7.405664, 0.2244141)
mag_stale_count: 0
(-0.1869141, -3.815039, 0.2244141)
mag_stale_count: 0
(-0.1869141, -3.815039, 0.2244141)
mag_stale_count: 0

The newer mpu9250 10DOF freezes randomly for a few seconds every 30 - 60 seconds or something like that.

Manually calling the

imu.mag.xyz

over and over again, yields the same result.

Have it running in C on an Arduino uno, and have no problems, so both sensors seems okay.

What am I doing wrong here?

DaneGrinder commented 7 years ago
>>> imu.sensors[2].xyz
(-0.1869141, -45.10723, 0.2244141)
>>> imu.sensors[2].ixyz
[-1, -201, 1]

the two frozen values are apparently a -1 and a 1

peterhinch commented 7 years ago

What platform are you using? Have you got pullup resistors on the I2C lines? (On the Pyboard these are on the board but on the ESP8266, for example, you need to supply them). I'm puzzled otherwise: I've run sensor fusion on an ESP8266 with an MPU9250 using software I2C. This has run for long periods without issue, and it bis running again as I write.

The IMU is instantiated as follows:

from machine import Pin, I2C
import uasyncio as asyncio
import gc
from mpu9250 import MPU9250
from fusion_async import Fusion # Using async version
scl = Pin(14, Pin.OUT)
sda = Pin(12, Pin.OUT)
i2c = I2C(-1, scl, sda) 

I have 1.2K pullups to 3.3V on pins 12 and 14. Because of RAM constraints all code is frozen bytecode.

DaneGrinder commented 7 years ago

Sorry for the late reply. Have been away for 2 weeks.

Using the ESP32

Just tried now with 1K pullups, but same result.

Not using the sensor fusion lib, because I don't want that computation on the board, unless I can move it to the DSP on the IMU. But that shouldn't make any difference should it? I should still get a stream of changing values from the mag sensor

peterhinch commented 7 years ago

Firstly I've been doing quite a bit of testing with the MPU9250 lately and the code seems to be working here. I haven't got an ESP32 but it runs with the ESP8266 and the Pyboard: I'd be surprised if there's an ESP32-specific issue. Sensor fusion is optional: the Vector3d class has methods you can use if you don't need fusion. You should get valid results from the magnetometer. I assume you're getting sensible results from the accelerometer and the gyro.

Apologies if what follows is elementary - I don't know your level of experience. Magnetometers are sensitive beasts and the Earth's magnetic field is small. So it's essential to ensure that there are no local sources of magnetic flux such as motors, wires carrying significant current or lumps of steel. Secondly calibration is essential. Run the calibration as described in the doc with the sensor in the location where you're doing the testing. End the calibration phase, then read xyz values as you rotate the device around each axis.

I've confused myself many times with magnetometer readings so good luck.

DaneGrinder commented 7 years ago

I never did the calibration. Didn't think it necessary to just see an output. Let us hope that's what's wrong. Will try and get back to you

DaneGrinder commented 7 years ago

Now that you have been testing on the ESP8266, do you by any chance have a small piece of test code, that I could get and try out? I have esp8266's laying around, so I could start there, and what I learn

DaneGrinder commented 7 years ago

Hmmmm... The chip id of the MPU9250's I'm using seems to be 115? I forgot I made a few changes when trying to get the mpu6050 working. One of them was apparently to remove the check for chip id. Now just started with a fresh download, and ran into this problem.

Could this be a newer chip, and therefore something has changed with the mag?

edit: It really shouldn't be a problem. I remember having that same problem on the Arduino, put everything still worked.

peterhinch commented 7 years ago

I have a brand new Adafruit MPU9250 board and it woks with the existing code - i.e. the chip ID is 113. I'd be very suspicious of a different chip ID. Is it a genuine MPU9250? It could indeed be some newer chip. Or maybe even a Chinese near-copy? I don't really see how we can support a chip with a different ID as it's a completely unknown quantity.

Calibration isn't needed to get readings, just for them to make sense in the context of a compass. You should be able to run it on the ESP8266 as follows (with pin numbers changed as required):

from machine import Pin, I2C
import uasyncio as asyncio
import gc
from mpu9250 import MPU9250
scl = Pin(14, Pin.OUT)  # Remember the pullups
sda = Pin(12, Pin.OUT)
i2c = I2C(-1, scl, sda) 
mpu = MPU9250(i2c)
print(mpu.accel.xyz)  # Check accel
print(mpu.mag.xyz)  # Check mag
DaneGrinder commented 7 years ago

I might be on to something here. It would seem, that they have given me MPU9255's instead of MPU9250. At least the WHO_AM_I (chip id) of the MPU9255 is 115.

I'll have to dig into this possibility. Still baffled, that it seems to work flawlessly with the C++ library on Arduino, as long as I just skip the test for the WHO_AM_I being equal to 113. You have any idea's on why this could be?

peterhinch commented 7 years ago

No, sorry. I haven't studied the MPU9255. You'd need to study the Arduino code and the MPU9255 data for the answer: perhaps the library was written with knowledge of that chip and an eye to future compatibility?

DaneGrinder commented 7 years ago

So, I think I've located the more specific problem.

MPU9250 has the magnetometer as an external AK8963 chip, that it can pass-through on the i2c bus, with the address 0X0C or 12 decimal.

MPU9255 has the magnetometer built in, and therefore does not pass it through on the i2c bus.

Can you confirm or refute this? i2c.scan() on the mpu9255 only returns the mpu itself on address 104. I'm guessing the mpu9250 returns [104, 12]?

All the registers for handling the magnetometer are identical on the mpu9250 and mpu9255, so my guess here is, that the only reason this lib does not work on the mpu9255 is, that you have to interact with the magnetometer, via the mpu's main i2c address 0X68 / 104.

peterhinch commented 7 years ago

Alas I'm too busy to investigate the MPU9255 at the moment. If you wish to do this, by all means try your ideas and report your findings: this would be very helpful.

I'm sure you'll appreciate that for us to support the device we'd need either to buy some hardware or to rely on someone like yourself to do the testing. I'll discuss this with @turbinenreiter in due course but it could be a few weeks before I find time to give this any attention. Sorry.

DaneGrinder commented 7 years ago

EDIT: Just ignore this post :-D

No problem mate. I completely understand the time restrictions we're all under.

I'm pretty sure I've got it now. Will get back to you with my findings. Just really wanted a confirmation on the MPU9250 showing up as 2 separate i2c addresses? 104 for the main unit, and 12 for the magnetometer.

peterhinch commented 7 years ago

That is correct. There is some setting-up to do before the magnetometer becomes visible - i.e. enabling passthrough.

DaneGrinder commented 7 years ago

Yes, I got the "having to do a pass through" from reading about it, also why I edited my last comment to just be ignored :)

After having read sooo much about this sensor, I finally gave up, and just wrote from scratch. Now I have it working on 1 of the boards. Both type of boards works with Arduino, but there seems to be some problems with the pull-up resistors on the esp32. Maybe not strong enough. Will look into that later.

The shortest version of the working code for the magnetometer is:

from machine import I2C, Pin

scl = Pin(18)
sda = Pin(19)
i2c = I2C(-1, scl, sda)

i2c.writeto_mem(104, 0x6B, b'\x00') # Initialize Power Manager Register to 0
i2c.writeto_mem(104, 0x6A, b'\x00') # Disable master I2C
i2c.writeto_mem(104, 0x37, b'\x02') # Enable pass through mode
i2c.writeto_mem(12, 0x0A, b'\x16') # Setup magnetic sensor to Continuous Measurement Mode 2 (100hz).

xl = i2c.readfrom_mem(12, 0x03, 1)
xh = i2c.readfrom_mem(12, 0x04, 1)
yl = i2c.readfrom_mem(12, 0x05, 1)
yh = i2c.readfrom_mem(12, 0x06, 1)
zl = i2c.readfrom_mem(12, 0x07, 1)
zh = i2c.readfrom_mem(12, 0x08, 1)

i2c.readfrom_mem(12, 0x09, 1) # read from st2 to signal transmission end.

ONLY to show the shortest working code.

I don't really see, where this differs from your code?

The mpu9250 and mpu9255 seems to be completely identical, but a change has been made to the mpu9250 (and carried over to mpu9255), that has broken a few peoples implementation. Read so many pages about this, so unfortunately I don't remember the solution.

DaneGrinder commented 7 years ago

Got it working. I might do a complete implementation of the MPU9255 at a later time.

Thanks for all the help @peterhinch

Closing this

tmbinc commented 6 years ago

To add to this - I found the MPU9255 (on a cheap GY-91 board) to not work with the default I2C clock frequency of the esp32 port. Reducing the I2C clock speed made it work:

i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(23), freq=100000)
from mpu9250 import MPU9250
imu = MPU9250(i2c)
print(imu.mag.xyz)  # prints (0,0,0) when using default speed

I also had to change the chip_id for 9255. I haven't done extensive testing but at least it's responding to movements.

(MicroPython v1.9.3-548-gd12483d9 on 2018-04-18; ESP32 module with ESP32)