Skip to content

Commit

Permalink
[DeviceMotion] convert rotationRate to degrees (#7876)
Browse files Browse the repository at this point in the history
* Use correct gravity

* convert rotationRate to degrees

* Fix rotation rate order on Android and in docs

* Make default update interval match iOS and web

* Correct ios rotation rate

* Correct device motion types

* fixed type conversion
  • Loading branch information
EvanBacon committed May 2, 2020
1 parent 55b6b56 commit f9b1b53
Show file tree
Hide file tree
Showing 13 changed files with 107 additions and 32 deletions.
8 changes: 7 additions & 1 deletion docs/pages/versions/unversioned/sdk/devicemotion.md
Expand Up @@ -47,13 +47,19 @@ Subscribe for updates to DeviceMotion.
DeviceMotion update is available. When invoked, the listener is
provided a single argument that is an object containing following fields:

- **interval (_number_)** -- Interval at which data is obtained from the native platform. Expressed in **milliseconds**.

- **acceleration (_object_)** -- Device acceleration on the three axis as an object with x, y, z keys. Expressed in m/s<sup>2</sup>.

- **accelerationIncludingGravity (_object_)** -- Device acceleration with the effect of gravity on the three axis as an object with x, y, z keys. Expressed in m/s<sup>2</sup>.

- **rotation (_object_)** -- Device's orientation in space as an object with alpha, beta, gamma keys where alpha is for rotation around Z axis, beta for X axis rotation and gamma for Y axis rotation.

- **rotationRate (_object_)** -- Rotation rates of the device around each of its axes as an object with alpha, beta, gamma keys where alpha is around Z axis, beta for X axis and gamma for Y axis.
- **rotationRate (_object_)** -- Device's rate of rotation in space expressed in degrees per second (deg/s).

- **alpha (_number_)**: X axis rotation.
- **beta (_number_)**: Y axis rotation.
- **gamma (_number_)**: Z axis rotation.

- **orientation (_number_)** -- Device orientation based on screen rotation. Value is on of `0` (portrait), `90` (right landscape), `180` (upside down), `-90` (left landscape).

Expand Down
7 changes: 7 additions & 0 deletions packages/expo-sensors/CHANGELOG.md
Expand Up @@ -4,6 +4,13 @@

### 🛠 Breaking changes

- `DeviceMotion.addListener` emits events with `rotationRate` in degrees instead of radians on all platforms. ([#7876](https://github.com/expo/expo/pull/7876) by [@evanbacon](https://github.com/evanbacon))
- `DeviceMotion.addListener` emits events with `rotationRate` in the form of alpha = x, beta = y, gamma = z on all platforms. ([#7876](https://github.com/expo/expo/pull/7876) by [@evanbacon](https://github.com/evanbacon))

### 🎉 New features

- `DeviceMotion.addListener` emits events with `interval` property. ([#7876](https://github.com/expo/expo/pull/7876) by [@evanbacon](https://github.com/evanbacon))

### 🐛 Bug fixes

- All sensors use more precise gravity `9.80665` instead of `9.8`. ([#7876](https://github.com/expo/expo/pull/7876) by [@evanbacon](https://github.com/evanbacon))
Expand Up @@ -16,6 +16,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.lang.Math;

import org.unimodules.core.ExportedModule;
import org.unimodules.core.ModuleRegistry;
Expand All @@ -33,7 +34,7 @@

public class DeviceMotionModule extends ExportedModule implements SensorEventListener2 {
private long mLastUpdate = 0;
private int mUpdateInterval = 100;
private float mUpdateInterval = 1.0f / 60.0f;
private float[] mRotationMatrix = new float[9];
private float[] mRotationResult = new float[3];

Expand Down Expand Up @@ -61,7 +62,8 @@ public String getName() {
public Map<String, Object> getConstants() {
return Collections.unmodifiableMap(new HashMap<String, Object>() {
{
put("Gravity", 9.81);
// Gravity on the planet this module supports (currently just Earth) represented as m/s^2.
put("Gravity", 9.80665);
}
});
}
Expand Down Expand Up @@ -231,27 +233,29 @@ private Bundle eventsToMap() {
Bundle accelerationIncludingGravity = new Bundle();
Bundle rotation = new Bundle();
Bundle rotationRate = new Bundle();

double interval = 0;
if (mAccelerationEvent != null) {
acceleration.putDouble("x", mAccelerationEvent.values[0]);
acceleration.putDouble("y", mAccelerationEvent.values[1]);
acceleration.putDouble("z", mAccelerationEvent.values[2]);
map.putBundle("acceleration", acceleration);

interval = mAccelerationEvent.timestamp;
}

if (mAccelerationIncludingGravityEvent != null && mGravityEvent != null) {
accelerationIncludingGravity.putDouble("x", mAccelerationIncludingGravityEvent.values[0] - 2 * mGravityEvent.values[0]);
accelerationIncludingGravity.putDouble("y", mAccelerationIncludingGravityEvent.values[1] - 2 * mGravityEvent.values[1]);
accelerationIncludingGravity.putDouble("z", mAccelerationIncludingGravityEvent.values[2] - 2 * mGravityEvent.values[2]);
map.putBundle("accelerationIncludingGravity", accelerationIncludingGravity);
interval = mAccelerationIncludingGravityEvent.timestamp;
}

if (mRotationRateEvent != null) {
rotationRate.putDouble("alpha", mRotationRateEvent.values[2]);
rotationRate.putDouble("beta", mRotationRateEvent.values[0]);
rotationRate.putDouble("gamma", mRotationRateEvent.values[1]);
rotationRate.putDouble("alpha", Math.toDegrees(mRotationRateEvent.values[0]));
rotationRate.putDouble("beta", Math.toDegrees(mRotationRateEvent.values[1]));
rotationRate.putDouble("gamma", Math.toDegrees(mRotationRateEvent.values[2]));
map.putBundle("rotationRate", rotationRate);
interval = mRotationRateEvent.timestamp;
}

if (mRotationEvent != null) {
Expand All @@ -261,8 +265,10 @@ private Bundle eventsToMap() {
rotation.putDouble("beta", -mRotationResult[1]);
rotation.putDouble("gamma", mRotationResult[2]);
map.putBundle("rotation", rotation);
interval = mRotationEvent.timestamp;
}

map.putDouble("interval", interval);
map.putInt("orientation", getOrientation());

return map;
Expand Down
20 changes: 18 additions & 2 deletions packages/expo-sensors/build/DeviceMotion.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/expo-sensors/build/DeviceMotion.js.map

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions packages/expo-sensors/build/ExponentDeviceMotion.web.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion packages/expo-sensors/build/ExponentDeviceMotion.web.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/expo-sensors/ios/EXSensors/EXSensorsManager.h
Expand Up @@ -8,7 +8,8 @@
#import <UMSensorsInterface/UMMagnetometerInterface.h>
#import <UMSensorsInterface/UMMagnetometerUncalibratedInterface.h>

static const float EXGravity = 9.81;
// Gravity on the planet this module supports (currently just Earth) represented as m/s^2.
static const float EXGravity = 9.80665;

@interface EXSensorsManager : NSObject <UMInternalModule, UMAccelerometerInterface, UMBarometerInterface, UMDeviceMotionInterface, UMGyroscopeInterface, UMMagnetometerInterface, UMMagnetometerUncalibratedInterface>

Expand Down
42 changes: 28 additions & 14 deletions packages/expo-sensors/ios/EXSensors/EXSensorsManager.m
Expand Up @@ -291,9 +291,16 @@ - (float)getGravity
return EXGravity;
}

- (float)radiansToDegrees:(double)radians
{
return radians * 180 / M_PI;
}

// Match https://www.w3.org/TR/orientation-event/
- (void)activateDeviceMotionUpdates
{
[[self manager] setDeviceMotionUpdateInterval:0.1f];
float interval = 1.0f / 60.0f;
[[self manager] setDeviceMotionUpdateInterval:interval];
__weak EXSensorsManager *weakSelf = self;
[[self manager] startDeviceMotionUpdatesUsingReferenceFrame:CMAttitudeReferenceFrameXArbitraryCorrectedZVertical toQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion *data, NSError *error) {
__strong EXSensorsManager *strongSelf = weakSelf;
Expand All @@ -320,12 +327,8 @@ - (void)activateDeviceMotionUpdates
break;
}

NSDictionary *result = @{
@"acceleration": @{
@"x": @(data.userAcceleration.x * EXGravity),
@"y": @(data.userAcceleration.y * EXGravity),
@"z": @(data.userAcceleration.z * EXGravity)
},
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithDictionary:@{
@"acceleration": [NSNull null],
@"accelerationIncludingGravity": @{
@"x": @((data.userAcceleration.x + data.gravity.x) * EXGravity),
@"y": @((data.userAcceleration.y + data.gravity.y) * EXGravity),
Expand All @@ -336,14 +339,25 @@ - (void)activateDeviceMotionUpdates
@"beta": @(data.attitude.pitch),
@"gamma": @(data.attitude.roll),
},
@"rotationRate" :@{
@"alpha": @(data.rotationRate.z),
@"beta": @(data.rotationRate.y),
@"gamma": @(data.rotationRate.x)
},
@"orientation": @(orientationDegrees)
};
@"rotationRate": [NSNull null],
@"orientation": @(orientationDegrees),
@"interval": @(interval),
}];

if ([[strongSelf manager] isGyroAvailable]) {
result[@"acceleration"] = @{
@"x": @(data.userAcceleration.x * EXGravity),
@"y": @(data.userAcceleration.y * EXGravity),
@"z": @(data.userAcceleration.z * EXGravity)
};
// Rate of rotation of the hosting device in space expressed in degrees per second.
result[@"rotationRate"] = @{
@"alpha": @([strongSelf radiansToDegrees:data.rotationRate.x]),
@"beta": @([strongSelf radiansToDegrees:data.rotationRate.y]),
@"gamma": @([strongSelf radiansToDegrees:data.rotationRate.z])
};
}

// DeviceMotionUpdates handle DeviceMotion data as well as magnetic field
for (void (^handler)(NSDictionary *) in strongSelf.deviceMotionHandlers.allValues) {
handler(result);
Expand Down
20 changes: 18 additions & 2 deletions packages/expo-sensors/src/DeviceMotion.ts
Expand Up @@ -2,7 +2,7 @@ import DeviceSensor from './DeviceSensor';
import ExponentDeviceMotion from './ExponentDeviceMotion';

export interface DeviceMotionMeasurement {
acceleration: {
acceleration: null | {
x: number;
y: number;
z: number;
Expand All @@ -17,11 +17,27 @@ export interface DeviceMotionMeasurement {
beta: number;
gamma: number;
};
rotationRate: {
/**
* Device's rate of rotation in space expressed in degrees per second (deg/s).
*/
rotationRate: null | {
/**
* x axis rotation.
*/
alpha: number;
/**
* y axis rotation.
*/
beta: number;
/**
* z axis rotation.
*/
gamma: number;
};
/**
* Interval at which data is obtained from the native platform. Expressed in **milliseconds**.
*/
interval: number;
orientation: number;
}

Expand Down
5 changes: 4 additions & 1 deletion packages/expo-sensors/src/ExponentDeviceMotion.web.ts
Expand Up @@ -8,8 +8,11 @@ export default {
get name(): string {
return 'ExponentDeviceMotion';
},
/**
* Gravity on the planet this module supports (currently just Earth) represented as m/s^2.
*/
get Gravity(): number {
return 9.81;
return 9.80665;
},
async isAvailableAsync(): Promise<boolean> {
if (typeof DeviceMotionEvent === 'undefined') {
Expand Down
2 changes: 1 addition & 1 deletion packages/jest-expo/src/preset/expoModules.js
Expand Up @@ -829,7 +829,7 @@ module.exports = {
systemFonts: { type: 'array' },
},
ExponentDeviceMotion: {
Gravity: { type: 'number', mock: 9.8100004196167 },
Gravity: { type: 'number', mock: 9.80665 },
addListener: { type: 'function' },
isAvailableAsync: { type: 'function' },
removeListeners: { type: 'function' },
Expand Down

0 comments on commit f9b1b53

Please sign in to comment.