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

pybricks.hubs.MoveHub: Increase resolution for imu.acceleration() #88

Merged
merged 1 commit into from
Apr 1, 2022

Conversation

cschlack
Copy link
Contributor

Given the following python snippet:

from pybricks.hubs import MoveHub
from pybricks.tools import wait

# Initialize hub
hub = MoveHub()

while True:
  x, y, z = hub.imu.acceleration()
  print(x)
  wait(100)

When using the Pybricks firmware, the result of hub.imu.acceleration will return values between -10 and 10. This is a very low resolution. The following table shows the raw values, LEGO and Pybricks values and the values after applying this PR.

I tried to distribute the range of raw values to the range between -90 and 90.

angle raw value LEGO firmware Pybricks firmware after applying PR
-90° -67 -90 -10 -91
-60° -58 -64 -9 -78
-45° -47 -46 -7 -63
-30° -34 -26 -5 -45
-20° -24 -17 -4 -32
-10° -13 -8 -2 -17
-1 0 0 0
10° 11 8 2 17
20° 22 17 3 32
30° 32 28 5 45
45° 45 45 7 63
60° 55 66 9 77
90° 65 90 10 91

@dlech
Copy link
Member

dlech commented Jan 12, 2022

Thanks for the pull request!

In Pybricks, all of our measurements use specific units of measurement. For accelerometers, this is currently m/s/s.

What is your application that requires higher resolution?

@cschlack
Copy link
Contributor Author

I'm building a self-balancing bot. If I hold it upright at an angle between -10° and +10°, I only get values between -2 and +2 to work with.

@dlech
Copy link
Member

dlech commented Jan 12, 2022

The consumer accelerometers I've seen maybe go up to 8 or 16 Gs so if we use mm/s/s then the max value would be something like 8G * 9.8 m/s/s/G * 1000 mm/m = 78400 mm/s/s. This still fits in a MP_SMALL_INT. So I would be happy with just using mm/s/s everywhere. The only drawback changing it will break existing programs. But IMU stuff is still considered experimental at this point anyway.

@laurensvalk, thoughts?

@cschlack
Copy link
Contributor Author

I'm not sure if the values returned by motion_get_acceleration () are acceleration anyway. The values are not zero when the MoveHub is still. Rather, they correspond to the angle at which the hub is held.

@dlech
Copy link
Member

dlech commented Jan 12, 2022

Gravity causes acceleration on everything on the surface of the earth at a rate of 9.8 m/s/s. So it makes sense that when the hub is standing still, the only force on the hub is due to gravity. And 9.8 rounded to an integer is 10. So this is how you know which what the hub is oriented - by which way gravity is pulling on it!

@cschlack
Copy link
Contributor Author

But gravity is supposed to be the same when I hold the hub vertically or horizontally. The returned value is not (see the table above).

@cschlack
Copy link
Contributor Author

I get it now.

@dlech
Copy link
Member

dlech commented Jan 12, 2022

The accelerometer is a 3-axis accelerometer. So it measures the effect in 3 different directions. When one value goes down, another value will go up. In your code, you are only looking at the x direction.

@@ -185,7 +185,7 @@ STATIC mp_obj_t hubs_MoveHub_IMU_acceleration(mp_obj_t self_in) {
// Convert to appropriate units and return as tuple
mp_obj_t values[3];
for (uint8_t i = 0; i < 3; i++) {
values[i] = MP_OBJ_NEW_SMALL_INT((data[i] * 10) >> 6);
values[i] = MP_OBJ_NEW_SMALL_INT(((data[i] + 1) * 11) >> 3);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this change the unit to mm/s/s, then?

Suggested change
values[i] = MP_OBJ_NEW_SMALL_INT(((data[i] + 1) * 11) >> 3);
values[i] = MP_OBJ_NEW_SMALL_INT((data[i] * 10000) >> 6);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks right, assuming the existing code was correct.

You could test and see if it reads something close to 9800 if you compile and run the change.

Copy link
Member

@dlech dlech Jan 12, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at the datasheet, it looks like the sensor returns a value in mg so if the value is closer to 10000, then we may need to use * 9860 instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It reads 10313

@laurensvalk
Copy link
Member

Thanks for making this pull request! When very specific new features are requested (like a resolution change), I usually try to dig a little deeper to better understand why we'd need it.

It's currently rounded to whole numbers because the Move Hub does not support floating point operations. We've kept it in m/s^2 to be consistent with other hubs, which do support floating point numbers, thus providing higher resolution.

The justification for rounding it (instead of choosing a movehub-specific resolution) is that the acceleration values are often not that useful without further processing. When they are used as-is (such as for impact or free-fall detection), the low resolution really isn't all that bad, since it's usually just a threshold comparison.

But based on what you're describing, I think what we're trying to get here is a gradual tilt value, not acceleration per-se. This was proposed in pybricks/support#539 and I think we can still do this.

So, @cschlack would you say the acceleration resolution is okay if we implemented the following method as well?

image

I'm building a self-balancing bot. If I hold it upright at an angle between -10° and +10°, I only get values between -2 and +2 to work with.

This can't be done with an accelerometer alone; you'd need a gyroscopic sensor. You could also make one with the color sensor, where the reflection intensity gives you a sense of the robot's angle.

@cschlack
Copy link
Contributor Author

Thanks @laurensvalk for the background information. imu.tilt() sounds exactly like what I'm actually looking for.

@dlech
Copy link
Member

dlech commented Jan 13, 2022

We've kept it in m/s^2 to be consistent with other hubs, which do support floating point numbers, thus providing higher resolution.

I thought we were trying not to use floating point in any of our APIs.

@laurensvalk
Copy link
Member

Geometry like rotation matrices would be hard to do (or at least very cumbersome) without floating point math.

Maybe we can restrict floating point usage to particular relevant areas only but not rule it out entirely?

That said, using mm/s/s for all accelerations (so int) might be fine.

@laurensvalk
Copy link
Member

This has been split into two tasks in pybricks/pybricks-api#94 and pybricks/support#539.

When we complete those, we can update this pull request accordingly and merge it. Thanks for your patience :)

@laurensvalk laurensvalk marked this pull request as draft January 14, 2022 09:03
@laurensvalk laurensvalk force-pushed the movehub_acceleration branch from 116eb6c to c3e8192 Compare April 1, 2022 14:04
@laurensvalk laurensvalk marked this pull request as ready for review April 1, 2022 14:05
@laurensvalk laurensvalk requested review from laurensvalk and dlech and removed request for dlech April 1, 2022 14:05
@laurensvalk laurensvalk force-pushed the movehub_acceleration branch from c3e8192 to 6b260a4 Compare April 1, 2022 14:13
@laurensvalk laurensvalk merged commit fe2b730 into pybricks:master Apr 1, 2022
@laurensvalk
Copy link
Member

Updated and merged. Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants