4
\$\begingroup\$

I am using the DeviceMotionEvent web API, which gives me a device's acceleration split up into x-, y- and z-dimensions and a time interval.

Here's my attempt at moving an object on screen based on these accelerations in data (just the x-dimension, for clarity):

velocity.x = data.acceleration.x * data.interval;

var newLeft = $('.object').position().left + (velocity.x);

$('.object').css({ 'left': newLeft });

This sort of works, but after moving, it goes back to where it started from instead of slowing to a stop.

What am I doing wrong? How do I do this right?


Here's an example of some data the API returns:

{ acceleration: 
   { x: -0.048474962000711816,
     y: 0.025074772074713834,
     z: -0.0035549827887938587 },
  accelerationIncludingGravity: 
   { x: -0.07826046448306878,
     y: 0.34760814211749236,
     z: -9.804854269410603 },
  rotationRate: 
   { alpha: -0.15093386712448556,
     beta: 0.051146754356783085,
     gamma: -0.019824252207518427 },
  interval: 0.05000000074505806 }
\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

Remember that acceleration is a change in velocity. You will want to use the acceleration samples to accumulate in the velocity variable. IE, instead of

velocity = acceleration * time

try

velocity = velocity + acceleration * time
\$\endgroup\$
7
  • \$\begingroup\$ This makes it work more accurately, however it seems to build up an error from the acceleration not matching the deceleration, so I end up with it drifting in one direction after a while. \$\endgroup\$
    – Tom
    Sep 4, 2014 at 19:00
  • 1
    \$\begingroup\$ Yes, and that's a common problem with inertial navigation. One way to solve this would be to add a friction factor: move the velocity towards zero by a small set amount each frame. \$\endgroup\$
    – Shadow503
    Sep 4, 2014 at 19:10
  • 1
    \$\begingroup\$ @user759 You may wish to only apply this friction factor when velocity is within some range of zero (otherwise the object will appear to slow down noticeably when it is moving at a constant velocity). \$\endgroup\$
    – Shadow503
    Sep 4, 2014 at 19:26
  • \$\begingroup\$ Very helpful. However even with this, the results don't seem accurate enough to map the user's motion onto the screen as well as the gyroscope does. Do you know anything about the accuracy? \$\endgroup\$
    – Tom
    Sep 5, 2014 at 23:01
  • \$\begingroup\$ @user759 I'm not sure why the gyroscope code is working better, but maybe I can explain the issue you're having with the accelerometer. Imagine raising your device up a few centimeters: Your device starts at rest, and then you begin to lift it. When it starts to move upwards, we read a positive acceleration, telling us its speed is increasing. As you approach the top, we read a negative acceleration, tellling us the device is slowing down. Ideally, the acceleration upwards and the acceleration downwards would cancel out, telling us the device has stopped, but errors often make these unequal. \$\endgroup\$
    – Shadow503
    Sep 8, 2014 at 17:05
0
\$\begingroup\$

The acceleration measures how fast you move the device, not the current position (rotation/tilt).

For moving something based in the tilt of the device you need to use the rotation with the device orientation event.

For the x axis you would use the gamma data if the device is standing up, and beta if it's in panoramic mode.

Then treat it like it was a analog joystick. For example using gamma:

var movementX = data.gamma / 90;
velocity.x = speed * movementX;

speed is the speed that the object can have (the maximum speed), you choose it.

movementX is a range between -1 and 1. 1 means that it wants to move at full speed to the right, and -1 it want to move at full speed to the left. It can be 0.2, so you move at 20% speed to the right.

So you use the tilt like a controller with smooth steps (instead of moving or not, you move a percentage of the speed).

You would probably want to limit it before 90 degrees, so the player doesn't need to put the device vertical. For example with 45 degrees as max speed:

var movementX = data.gamma / 45;
if(movementX > 1) movementX = 1;
if(movementX < -1) movementX = -1;

If you want the player to have a better control you can have a minimum angle that need to be tilt to start reacting:

var movementX = 0;
if(data.gamma <-10 || data.gamma > 10) {
    movementX = data.gamma / 45;
    if(movementX > 1) movementX = 1;
    if(movementX < -1) movementX = -1;
}

In this case I'm using 10.

\$\endgroup\$
1
  • \$\begingroup\$ This is all true, but I am already mapping the gyroscope to the object on the screen, so it doesn't make sense to use it for motion as well. \$\endgroup\$
    – Tom
    Sep 5, 2014 at 19:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .