Module for MPU9150

Showroom for MicroPython related hardware projects.
Target audience: Users wanting to show off their project!
User avatar
pythoncoder
Posts: 1564
Joined: Fri Jul 18, 2014 8:01 am

Re: Module for MPU9150

Postby pythoncoder » Sun Oct 05, 2014 10:35 am

I've tried increasing the delay in line 192. The results are somewhat erratic but I seem to get reliable operation with a value of 20mS. The values returned by the magnetometer are an order of magnitude higher than those I got with the original code and I no longer get the spurious zero values. The actual values now seem plausible: for example with the magnetometer Y axis pointing North I get
[-21.00853, 1.200487, -71.429]
I'm no expert but I think these values are credible for my location (UK, 53.2580°N, 2.1270°W).

I've not spotted anything in the datasheet regarding a value for this delay - is there any information out there on how to access the magnetometer?

Regards, Pete
Peter Hinch

Turbinenreiter
Posts: 260
Joined: Sun May 04, 2014 8:54 am

Re: Module for MPU9150

Postby Turbinenreiter » Sun Oct 05, 2014 12:54 pm

hey, nice to see my second user!

I just pushed an update to github.

  • added passthrough mode - you no longer have to connect ESD and ESC
  • changed mode() to wake() and sleep()
  • the default setting after init know is awake, passthrough mode active, accel and gyro range set to 3
  • added get_*_raw(), so you can store bytes if you are trying to log data as fast you can
  • fixed get_mag(), so it now waits for data ready

The last point addresses your problems. The magnetometer has a register that indicates whether data is ready or not. If you read the magnetometer before data is ready it will give zeros or bogus values. I now have the method check if data is ready, wait until data is ready, and then return the values. Note that the way it's done right now it's blocking the main loop, waiting for values.

TODO:
  • adjust magnetometer values to sensitvity as described on page 59 in the register map
  • make get_mag() none blocking by using yield

If you find bugs or more typos, please tell me. Either here or on github. Also, if you have any ideas or criticism about the structure and the interface, I'm listening. Finding good names for functions and methods is hard.

User avatar
pythoncoder
Posts: 1564
Joined: Fri Jul 18, 2014 8:01 am

Re: Module for MPU9150

Postby pythoncoder » Tue Oct 07, 2014 4:26 pm

The new build does provide consistent magnetometer values. A non-blocking method would be great. I'm building a balancing robot so my main interest is the gyro and accelerometer until I get the control system sorted, but I'll return to the mag later. Looking at your code it seems clear how to do non-blocking access. I'll see what you come up with, otherwise I'll hack it using my threading library.

I'm still in the dark about the sample rate parameter. My application will read values at intervals of probably tens of milliseconds. Is there any merit in reducing the chip's sample rate? A web or datasheet reference would be fine but so far I've not spotted anything which explains it, nor have I spotted any empirical difference if I change it.

Regards, Pete
Peter Hinch

Turbinenreiter
Posts: 260
Joined: Sun May 04, 2014 8:54 am

Re: Module for MPU9150

Postby Turbinenreiter » Tue Oct 07, 2014 4:48 pm

datasheet
http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/IMU/PS-MPU-9150A.pdf
register map
http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/IMU/RM-MPU-9150A-00.pdf

I think the sample rate is pretty irrelevant for us. Lowering it may lower power consumption.

User avatar
pythoncoder
Posts: 1564
Joined: Fri Jul 18, 2014 8:01 am

Re: Module for MPU9150

Postby pythoncoder » Sun Oct 12, 2014 6:59 pm

I've come across an issue which needs consideration. My application was freezing for a period at random intervals. Currently the only repeated call to the library is via get_gyro(): it turns out that the call, which normally takes about 5mS, occasionally takes 5 seconds! It also very occasionally crashes with
# File "mpu9150.py", line 247, in get_gyro
# TypeError: tuple indices must be integers, not NoneType

Both these behaviours are down to self._mpu_i2c.mem_read() timing out and returning None - the default timeout is 5 seconds. In the case of the crash I think it's prompted by scale[gr] where gr is None as a result of a timeout in self.gyro_range(). I'm not sure what's causing the timeout - it happens very roughly once a minute while I'm calling get_gyro() at 20Hz or so. I think the code needs to specify a much shorter timeout and to handle the return of None. I've changed the timeout to 20mS and modified get_gyro() so that, in the event of a timeout, it returns the last good value. This has fixed my immediate problem.

Unfortunately I suspect that this will apply to all accesses to the MPU9150 including the accel and mag. Clearly a five second lockup would have interesting consequences for anyone using this code to stabilise an aircraft...

It's possible that I have an unreliable device or electrical issues. However the kit is powered from a lab bench supply and the leads between the device and the Micropython board are only an inch long so I doubt that my problems are electrical. I wonder if you can replicate this problem?

Regards, Pete
Peter Hinch

Turbinenreiter
Posts: 260
Joined: Sun May 04, 2014 8:54 am

Re: Module for MPU9150

Postby Turbinenreiter » Sun Oct 12, 2014 8:36 pm

I have the exact same problem and until now I thought it was the SD card!

You finally found the real location if that bug for me! I'll look into it tomorrow.

User avatar
pythoncoder
Posts: 1564
Joined: Fri Jul 18, 2014 8:01 am

Re: Module for MPU9150

Postby pythoncoder » Mon Oct 13, 2014 6:21 am

Another observation. When looking for the bug, I removed gr = self.gyro_range() from get_gyro() - after all the range is known to the class instance because it set the value in the first place. This greatly reduced the frequency of the error. This perhaps suggests some kind of hardware issue with the MPU but given that these things are likely to be used in realtime applications it needs to be handled.

I'd suggest having the timeout as a class property defaulting to something more akin to 20mS than 5S, but changeable by the user.

Regards, Pete
Peter Hinch

Turbinenreiter
Posts: 260
Joined: Sun May 04, 2014 8:54 am

Re: Module for MPU9150

Postby Turbinenreiter » Mon Oct 13, 2014 12:07 pm

okay, this should now be fixed. i added timeouts to the i2c functions that will get looped and made the range functions store the selected range to a pseudo-private attribute, which is then used by the get functions.

thanks again for finding that bug!

User avatar
pythoncoder
Posts: 1564
Joined: Fri Jul 18, 2014 8:01 am

Re: Module for MPU9150

Postby pythoncoder » Tue Oct 14, 2014 7:56 am

The code looks good, I'll give it a thorough workout today. But I still have a concern. Your original version didn't have a bug as such: the code was fine, yet the hardware very occasionally took exception to the sequence of events and timed out. I wish we understood the reason for this: I think the hardware has some limitation which we need to discover. We've effectively implemented a workround by reducing the timeout and avoiding doing two I2C reads in quick succession.

Yesterday I hacked the gyro part of your code to effectively do the same as you're doing now, reducing the timeout to 10mS and avoiding reading the scaling from the hardware. Usually timeouts were handled fine but I still got occasional I2C crashes which could only be cleared by power cycling the hardware. I'll investigate further with your new code and report back.

Regards, Pete
Peter Hinch

User avatar
pythoncoder
Posts: 1564
Joined: Fri Jul 18, 2014 8:01 am

Re: Module for MPU9150

Postby pythoncoder » Tue Oct 14, 2014 6:12 pm

I've run the new code for a long period today. Timeouts usually have no adverse consequences, but sometimes I'm seeing
Exception: HAL_I2C_Mem_Read failed with code 2

When this occurs the I2C bus seems to be locked solid. I tried to query the bus as follows when it was in this state

Code: Select all

>>> import pyb
>>> a = pyb.I2C(2, pyb.I2C.MASTER)
>>> a.is_ready(104)
False
>>> a.scan()
[]
>>>

This contrasts with the normal situation

Code: Select all

>>> a = pyb.I2C(2, pyb.I2C.MASTER)
>>> a.is_ready(104)
True
>>> a.scan()
[12, 104]
>>>

I'm baffled as to why timeouts occur, why it gets into this state, and how to retrieve the situation in code.

Regards, Pete
Peter Hinch


Return to “Hardware Projects”

Who is online

Users browsing this forum: No registered users and 1 guest