-
Notifications
You must be signed in to change notification settings - Fork 59
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
Provide the DeviceOrientation sensor #170
Comments
@kenchris @tobie @anssiko @alexshalamov wdyt? |
I definitely think we should have a few higher level sensors like Orientation, but for efficiency sake it is probably best to just create a sensors exposing the data directly instead of having people pass in other sensors. If we will have sensors integrated with Gamepad (like for WebVR) then that also makes more sense, for instance DaydreamController already exposed orientation as a fusion value as well as the raw gyro and accel values. |
Absolutely. This has been the plan from day 1 and is why I'm pushing for a single motion sensor spec rather than separate specs for each combination of accelerometer, gyroscope and magnetometer. |
WRT to the API proposal, you want to design a more generic BYOB solution, bake it in either the |
It seems batching API is beyond the scope of this issue. I'm just thinking yet of the device orientation representation that will be most convenient to the user. There are few options like quaternion, rotation matrix or Euler angles, and we even could have several BYOB methods for different representations. |
Yes. You'll definitely want the different representations. Whether you obtain them through different constructors, different construction arguments, different method names or different method arguments, is still TBD. What's certain however is you want this defined consistently at the
On the contrary, I think the hard API to solve is the batching one. That's the one we need to look at first. It's easy to handle the BYOB for a single sample use case once we know where we're going with the more complex cases and create a consistant API that works across sensor types. |
Agree, I just meant that batching API deserves a dedicated issue, or is #98 supposed track it? |
Here is an updated IDL with a better description
|
So this API fills-in the buffer synchronously? While the batching API will do so async? Seems confusing. Do we really want to offer two different APIs for this? Won't we often be in a case where there might be more than one sample per AF? e.g. especially if a frame is delayed. Providing quaternions doesn't seem to be specific to DeviceOrientation, though. It seems like a data representation strategy for a vector plus acceleration combo. Would be useful elsewhere too, e.g. for gyroscopes. I need better clarity on which data representation is useful for which high and low level sensors, so we figure out how we organize this across all motion sensors in a consistant and coherent whole. |
Those |
You could also look at the quartenion a + bi + cj + dk as a scalar + 3 dimensional vector, which seems to be what you do implicitly in the comment, though you don't explain that well. z-axis points up and is perpendicular to the ground - and with ground you mean plane made up of x and y axis. - especially because ground will not be 100% stable and actually represent the actual ground. |
IMO we need to split between "getCurrentValue" API returning the freshest data from the HW and batching API collecting the previous values with weaker latency requirements: these two kinds of APIs have to be both used and implemented in different ways.
On platform level (In Windows and Android) Sensor APIs use quaternions only to represent device orientation. |
VR heavily relies on gyroscope data presented as quaternions. Worth digging into, imho. |
@tobie so, are you considering moving |
Quaternions are a very nice and compact way of representing rotations. Ie. you can multiply quaternions to apply rotation (though non-commutative - due to being rotations). They are basically the evolution of complex numbers (which are good for rotations in 2D space), and you can easily build a rotation matrix from them. Good intro: https://www.youtube.com/playlist?list=PLpzmRsG7u_gr0FO12cBWj-15_e0yqQQ1U Build rotation matrix from quaternions multiplication: http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/ (the video above explains it quite well) |
What do you mean by |
Yes I am a fan of you using Float32Array :) |
That's seems trendy, these days. It would be nice to have some rationale behind the trend, if only to be able to justify that decision. |
And they are also not susceptible to gimbal lock which is a big benefit |
As mentioned above, I'm not considering much right now beyond what's needed to provide a consistant and coherent API across sensors that's easy to use, yet allows for high performance, low latency, and limits GC cycles. At this point, we don't even have a list of motion sensors we want to expose, we don't have a list of how we want to expose that data, we don't have clear requirements derived from the use cases, and we don't even have use cases written down, so I really don't have the info to answer that question. |
Well, with arrays you can use methods of say glMatrix as the matrices were created using it. ie
|
that was exactly the intention :) |
Cool. Can we turn that into a use case and derive those as requirements? That would be pretty awesome. |
Let the following to be the first draft: Use cases
Functional requirements
Non-functional requirements
|
Oops, sorry. :-/ I didn't mean use cases in general. I meant specific use cases and rationale for presenting the data in array format (as that's a departure from platform conventions and I want us to document why we're doing it). |
|
The idea is to match WebGL, where Float32Array is one of the most commonly used data types. |
Well, are they really? There's a different cost to each API: sensor.quaternion; // returns TypedArray benefit: simpler than BYOB, plays well with WebGL sensor.acceleration, sensor.x, sensor.y, sensor.z ; // returns floats corresponding to the quaternion values benefit: simpler than BYOB, GC sensor.buffer = buffer;
requestAnimationFrame(_ => buffer); // returns TypedArray benefit: GC, plays well with WebGL Not to mention the array-like behavior you were describing (no idea whether we could pull this off or even if it's desirable). |
I meant they are easy to represent as an array :-) [scalar, vector(x, y, z)] Maybe we can combine these above solutions somehow. Though that the second solution seems easy to grasp and use, is it really that must easier when put to actual use? I mean you most often have to do either
That is why I was thinking about exposing, x, y, z etc as properties, plus implement [Symbol.iterator] or something similar to easily get the data in array form. (that is in addition to have the populate methods) |
We need to consider the perf impact of this. |
Could you add an example of client code for this? |
Sure, this was just an idea and there might be other similar hooks. This example is a bit stupid how shows how you could do in JS:
Maybe this could be made quite fast in native code. Also an async version of this is scheduled for ES2018: https://github.com/tc39/proposal-async-iteration |
I'm just not sure how all above helps comparing to AFAIK splitting scalar and vector parts will not be beneficial for representing the rotation quaternion (q) itself. This splitting is needed to represent as quaternion a 3-D vector that will be rotated: Also I'd like to add that the BYOB semantics will allow overloading, i.e. it could accept also 3*3 matrices and different data types (Float64Array, DOMMatrix, ..) |
Yes, it would not help populate, but tobie seemed to think that populate was a bit too advanced for some users and I though we might have multiple ways to access the data then, a bit like the Response object from fetch as a json() method. |
I believe a person who understands quaternions and rotation matrices should not experience any problems with understanding BYOB :-) |
I think it was especially not for those who knew that :-) but simple use-cases. I am just not sure what these simple use-cases are. |
For basic use-cases we can add predefined set of orientations @pozdnyakov wdyt?
|
People use device orientation as a controller etc, screen orientation is already handled by |
@kenchris https://www.w3.org/TR/screen-orientation/ is for screen orientation, that can be locked, etc. How someone would implement, for example, silencing WebRTC call by laying down device on the table facing screen down (Z towards facing towards ground)? With screen orientation API this would be impossible. Using rotation matrices is overkill for such simple use-case, thus, I think, some helper methods / constants might be useful. |
Well wouldn't accelerometer not be better for that? Or a GravitySensor (isolated gravity from accelerometer) which Android supports |
Whether or not that use case is actually a valid one—I'd probably argue higher-level events (e.g. There's also little sense for an API with such a coarse output to be able to specify input parameters like polling frequency with such precision. So maybe my initial plan to have |
Here is the early (and uncompleted) version of spec draft https://pozdnyakov.github.io/orientation-sensor/ |
Oh, wow! I've been massively misled by your choice of name which made me think you wanted to emulate the API of the DeviceOrientation Event Specification when it turns out that what you were really after was simply a rotation vector. :-/ |
Is that rotation vector anchored in the geomagnetic north or not? Is it based on gyro data or the accelerometer? Should/can we provide all combinations of all of the above? Should these be different constructors? or options in the same constructor? Are 4x4 matrices just a different representation of the same data? |
I do not see how one contradicts to another: both DeviceOrintationEvent and rotation vector provide same device orientation data but just using different representations (Euler angles in one case and quaternion in the second case). IMO |
Yes. Pls see #170 (comment)
Different options are possible (tagging @kenchris here and his https://github.com/01org/websensor-compass :) ), but fortunately data fusion is already done on platform level (at least on Android and Windows)
No. Let's just rely on platform API (where it is present).
Yes. |
My limited understanding is that Android provides both gyro only (not north-anchored) and accelerometer + magnetometer (north-anchored) and that VR needs the former for latency reasons. |
If we call it DeviceOrientationSensor then it should be a fusion of accel and gyro, which most sensor hubs now can do in hardware and usually accomplish using a complimentary filter, as it creates satisfactory results for common use-cases without must computation. A fusion of magnetomer and gravity (gravity isolated from accelerometer - also sometimes done in the sensor hub using a low pass filter - Android exposes a specific Gravity sensor for that) should be called CompassSensor or similar. We could also make it an argument to a generic orientation sensor, like say { type: "compass" | "device" | "gamepad" | "vr-headset" ... } Sometimes for gamepads, you actually might not want the orientation to always be 100% fixed in one direction, but instead slowly move towards you current position, - a fusion of gyro and accel will usually do that unless the fusion is done 100% precise to avoid that (ie choosing the right constants). I think I saw that Android exposes both, but I will have to check. |
DeviceOrientationSensor is a terrible name given there's already a DeviceOrientation Event on the platform which everyone hates. Just imaging googling for info on this or searching stackoverflow. @kenchris my plan is to make a matrix of all of the different motion-based sensors, showing the data they provide, on which of the three primitive sensors they are based, their purpose, their advantages and disadvantages, and the platforms that support them. Basically, an improved version of this: https://github.com/w3c/sensors/blob/master/sensor-types.md Ideally, we'll stick all of this data (minus the platform support bit, obviously) at the beginning of the motion sensor spec. |
The Android docs already have some sort of that |
Yup, used some of it for the above matrix. |
What's interesting is that the above four have massively different latency, accuracy and energy consumption characteristics and don't rely on the same underlying HW sensors. The question is how should we expose that to the API consumer? Basically, how do we strike the right balance between providing the right underlying primitives and making it easy for developers to use the APIs. In the spirit of the extensible web manifesto, we'd lay bare the underlying structures on which these sensors are based, leaving it to JS libraries to offer more user-friendly domain-specific APIs. And, then only, pave the cowpath. |
From a user point of view (user being front end dev or the like) - they will mostly care about the actual orientation values and know that the latency will be different between something connected and something external, but it is not like that they will drop using a headset because of latency issues, if what they care about is the headset orientation :-) It is all about balance. If we say that these are super low level APIs and that libs need to be built around them to make the APIs consumable, well then we can very well get away with only having populate methods and nothing for the simple case, which you were arguing for :-) But then again, I don't think having a low levelish API means it is mutual exclusive that the API can be nice and that something has to be build around it. |
My understanding is key players in the industry are are worried about VR-induced motion sickness and thus would probably want to restrict usage for devices which don't meet certain latency requirements (motion-sickness correlates closely with latency). The game industry is accustomed to running a bunch of tests to figure out if HW requirements for particular settings are met. I imagine the same will be done for VR.
I wasn't expecting the BYOB API to be synchronous, as unless the implementation is willing to always store all samples between two frames, then this API doesn't work for more than 1 samples (which is clearly a requirement). Arguably we can have two BYOB APIs, but it might not be super API-consumer friendly to have one such API be sync (for 1 sample) and the other one async (for > 1 sample). But maybe it would be OK. I don't know. If we go for a sync BYOB, we could also imagine the Typed Array as argument would be optional, so you could do: [Constructor(...)]
interface VectorRotation : Sensor {
Float32Array? read(optional Float32Array buffer);
}; Where read would either fill the the buffer you passed it or create one on the fly, e.g.: let s = new VectorRotation({
format: "quaternions",
pollingFrequency: 120
});
s.start();
let reading = s.read(); // null
// once sensor it activated
reading = s.read(); // Float32Array of length 5? we need a timestamp somewhere :-/
let buffer = new Float32Array(VectorRotation.QUATERNION_SIZE);
s.read(buffer); // buffer is now filled up with one reading.
// etc. For > than 1 sample, we could imagine setting the buffer size in the constructor, let s = new VectorRotation({
format: "quaternions",
pollingFrequency: 120,
bufferSize: 2 * VectorRotation.QUATERNION_SIZE
}); or through a dedicated method: let s = new VectorRotation({
format: "quaternions",
pollingFrequency: 120
});
s.bufferSize = 2 * VectorRotation.QUATERNION_SIZE; or even by passing a buffer upfront that's always overwritten (similar to the async version I had in mind): let buffer = Float32Array(4 * VectorRotation.QUATERNION_SIZE);
let s = new VectorRotation({
format: "quaternions",
pollingFrequency: 120,
buffer: buffer
});
buffer === s.read(); // true There's a lot explore here, though. And some pretty important issues to consider, e.g. what happens when pollingFrequency < animation frame rate? Or when when frames slow down so you buffer gets more samples than it can handle? Where do you put timestamps? etc. Half of the above are probably terrible ideas, but this area is certainly worth digging into seriously. There's the potential to make something both powerful and user-friendly but also to screw it up badly and ship something that's over-engineered and crappy. (Which btw, I'm not suggesting any of the proposals are. It's just a general concern, not a specific one.) |
Editor's Draft now hosted at: https://w3c.github.io/orientation-sensor/ I'd suggest we split this issue (now at 71 comments) into smaller self-container issues in https://github.com/w3c/orientation-sensor/issues @pozdnyakov @kenchris @tobie can you help migrate the issues you care about to the |
At the moment developers experience problems when merging data from different motion sensors (which is required in most cases): sensor data updates come at the same time from HW but it is not quite obvious -- the user is dealing now with multiple sensor instances (gyro, accel, magnetometer), each with their onchange event.
So, it would be beneficial to have a new
DeviceOrientation
class providing the merged device orientation data in a convenient way with a single 'onchange' event. This was also discussed on a DAP call: https://lists.w3.org/Archives/Public/public-device-apis/2017Feb/0003.htmlI would like to provide a solution for this and draft an API for such sensor. Please consider the following piece of IDL as a starting point for discussion:
The text was updated successfully, but these errors were encountered: