LEARNING OBJECTIVES ⌵
- Understand the difference between
acceleration(pure dynamic force) andaccelerationIncludingGravity(total sensor force). - Read angular velocity rates ($\text{deg/sec}$) along 3 axes using
rotationRate. - Interpret the hardware sensor sampling
intervalin milliseconds. - Implement a robust, debounced Shake Detection algorithm using 3D Euclidean magnitude vectors.
- Apply high-pass and low-pass digital filters to separate continuous gravity from sudden user motions.
📖 The Mental Model & Story (Intuitive Foundation)
Imagine sitting in the passenger seat of a sports car with your eyes closed. When the driver stomps on the accelerator pedal, you feel pushed back into your seat. When the driver slams on the brakes, you lurch forward. Even when the car is parked completely motionless on the ground, your body still feels the continuous downward pull of Earth's gravity ($9.81 \text{ m/s}^2$).
[ ACCELEROMETER SENSOR CHIP (MEMS) ]
│
┌───────────────┴───────────────┐
▼ ▼
[ EARTH GRAVITY VECTOR (1G) ] [ USER KINETIC FORCE ]
(Static ~9.81 m/s² pointing (Dynamic acceleration:
straight down to Earth center) swiping, shaking, dropping)
│ │
└───────────────┬───────────────┘
▼
+───────────────────────────────+
│ accelerationIncludingGravity │
│ (Total Sensor Force) │
+───────────────────────────────+
│
(OS Kalman Filter)
▼
+───────────────────────────────+
│ acceleration │
│ (Pure User Dynamic Motion) │
+───────────────────────────────+
Modern mobile devices contain a micro-machined MEMS accelerometer consisting of tiny silicon cantilever springs with seismic masses. When you move the phone, the mass deflects, changing electrical capacitance.
The Device Motion API (devicemotion) streams these inertial forces directly into JavaScript at high frequency (often 50Hz to 60Hz), allowing you to build pedometers, shake-to-undo gestures, and motion-controlled gaming physics.
Technical Deep Dive & Specifications
The DeviceMotionEvent Interface
interface DeviceMotionEvent extends Event {
readonly attribute DeviceMotionEventAcceleration? acceleration;
readonly attribute DeviceMotionEventAcceleration? accelerationIncludingGravity;
readonly attribute DeviceMotionEventRotationRate? rotationRate;
readonly attribute double interval; // Sampling interval in milliseconds (e.g. 16.0 ms)
}
interface DeviceMotionEventAcceleration {
readonly attribute double? x; // Left-to-Right axis (m/s²)
readonly attribute double? y; // Bottom-to-Top axis (m/s²)
readonly attribute double? z; // Back-to-Front axis (m/s²)
}
interface DeviceMotionEventRotationRate {
readonly attribute double? alpha; // Z-axis rotation rate (deg/s)
readonly attribute double? beta; // X-axis rotation rate (deg/s)
readonly attribute double? gamma; // Y-axis rotation rate (deg/s)
}
acceleration vs. accelerationIncludingGravity
The distinction between these two properties is fundamental to physical computing:
| Physical Scenario | acceleration ($x, y, z$) |
accelerationIncludingGravity ($x, y, z$) |
Explanation |
|---|---|---|---|
| Resting flat on a desk | (0, 0, 0) m/s² |
(0, 0, +9.81) m/s² |
Gravity pulls the seismic mass down against the Z-axis sensor floor. |
| Held vertically upright | (0, 0, 0) m/s² |
(0, +9.81, 0) m/s² |
Gravity points along the Y-axis (downward through the phone base). |
| In Free Fall (Dropped) | (0, 0, 0) m/s² |
(0, 0, 0) m/s² (0G) |
In orbital or free-fall weightlessness, no normal force acts on the sensor. |
| Pushed sharply forward | (0, 0, +15.0) m/s² |
(0, 0, +24.81) m/s² |
Kinetic force ($+15$) is added on top of static gravity ($+9.81$). |
+---------------------------------------------------------------------------------------------------+
| ACCELERATION AXIS DEFINITION (m/s²) |
+---------------------------------------------------------------------------------------------------+
| |
| +Y (Toward Top Edge) |
| ▲ |
| │ |
| ┌─────┴─────┐ |
| │ [Camera] │ |
| -X (Toward Left Edge) ◄────────┤ ├────────► +X (Toward Right Edge) |
| │ Screen │ |
| │ │ |
| └─────┬─────┘ |
| │ |
| ▼ |
| -Y (Toward Bottom Edge) |
| |
| +Z: Straight OUT of the screen toward user's face |
| -Z: Straight THROUGH the back cover toward the floor |
| |
+---------------------------------------------------------------------------------------------------+
Digital Filtering & Shake Detection Algorithm
To detect an intentional Shake gesture (e.g., shake-to-undo or dice rolling):
- Compute the 3D Euclidean vector magnitude of the acceleration: $$|A| = \sqrt{a_x^2 + a_y^2 + a_z^2}$$
- Calculate the delta change $\Delta A = ||A_{\text{current}}| - |A_{\text{previous}}||$.
- Check if $\Delta A$ exceeds a calibrated threshold (typically $15 \text{ to } 25 \text{ m/s}^2$).
- Implement a cooldown debounce timer (e.g. 800ms) to avoid triggering dozens of events during a single shake gesture.
Acceleration Vector Stream
│
▼
[ Compute ||A|| = √(x²+y²+z²) ]
│
▼
[ Is ||A|| > Threshold? ]
│
┌────────┴────────┐
▼ YES ▼ NO
[ Cooldown Active? ] [ Ignore & Stream ]
│
┌────┴────┐
▼ NO ▼ YES
[ FIRE SHAKE ] [ Suppress (Debounce) ]
💻 Interactive Code Playground
Starter Code
Line-by-Line Code Breakdown
- Lines 135–144: Defines the debounce threshold ($18.0 \text{ m/s}^2$) and cooldown ($800\text{ms}$) to prevent multiple triggers per single gesture.
- Lines 159–165: Handles the
triggerShake()UI animation state and auto-resets after $500\text{ms}$. - Lines 169–175: Reads pure dynamic acceleration ($a_x, a_y, a_z$) without gravitational bias.
- Line 177: Calculates the vector magnitude using Pythagoras in 3D: $\sqrt{a_x^2 + a_y^2 + a_z^2}$.
- Lines 182–186: Executes the debounced shake detection logic comparing
dynamicMag > SHAKE_THRESHOLDand timestamp cooldown. - Lines 188–198: Reads total force including Earth's gravity vector ($\approx 9.81 \text{ m/s}^2$).
- Lines 200–205: Reads angular rotational velocities ($\text{deg/s}$) from the gyroscope.
- Lines 207–210: Calculates the real hardware sensor sampling rate in Hertz from
event.interval.
Expected Browser Render Output
⚡ Kinetic Device Motion & Shake Lab
Streams 3-axis accelerometer and gyro rotation velocity at hardware refresh rates.
+-------------------------------------------------------------+
| SHAKE DETECTIONS |
| 0 |
| Shake device vigorously to test |
+-------------------------------------------------------------+
LINEAR ACCEL (m/s²) ACCEL + GRAVITY (m/s²)
X (Left/Right): 0.00 X: 0.00
Y (Up/Down): 0.00 Y: 0.00
Z (In/Out): 0.00 Z: 9.81
ANGULAR ROTATION RATE (deg/s)
α (Yaw): 0.0 β (Pitch): 0.0 γ (Roll): 0.0
Sensor Sampling Interval: 16.0 ms (60 Hz) Force Magnitude: 0.00 m/s²🏋️ Hands-On Exercise
🎯 The Challenge: Build a Free-Fall Drop Detector (Zero-G Alert)
Instructions:
- Create a security drop-detector dashboard.
- In normal stationary conditions,
accelerationIncludingGravitymagnitude is $\approx 9.81 \text{ m/s}^2$ (1G). - If a phone is dropped or in free fall, the total acceleration magnitude plummets toward $0.0 \text{ m/s}^2$ (weightlessness).
- Detect if total acceleration magnitude falls below $3.0 \text{ m/s}^2$ for more than 150 milliseconds.
- If free-fall is detected, trigger an emergency visual alarm: "FREE-FALL IMPACT IMMINENT 🚨".
🏁 Starter Code Sandbox
⚠️ Common Pitfalls
- Confusing
accelerationwithaccelerationIncludingGravity: UsingaccelerationIncludingGravityfor velocity integration without subtracting the $9.81 \text{ m/s}^2$ gravity vector will make your physics math falsely accelerate continuously toward the sky. - Double Shake Triggers: Failing to implement a cooldown timestamp window will cause a single flick of the wrist to fire 10–20 shake events in under 200ms.
- Assuming
event.accelerationis Always Available: Some low-cost embedded hardware platforms only reportaccelerationIncludingGravityand leaveaccelerationasnull. Always provide fallback math using a high-pass filter.
💡 Pro Tips
- High-Pass Gravity Isolation Filter:
// Isolate dynamic acceleration when event.acceleration is null let lastX = 0, lastY = 0, lastZ = 0; const kFilteringFactor = 0.8; // Gravity isolation gravityX = (gx * kFilteringFactor) + (gravityX * (1.0 - kFilteringFactor)); // Dynamic motion = Total - Gravity dynamicAccelX = gx - gravityX; - Conserve Battery with Event Detachment: Always remove
devicemotionlisteners (window.removeEventListener('devicemotion', ...)) when the tab is hidden (document.visibilityState === 'hidden') to avoid burning CPU cycles and battery power at 60Hz.
📌 Key Takeaways
window.addEventListener('devicemotion', ...)streams hardware accelerometer and gyroscopic velocity metrics.event.accelerationmeasures pure dynamic kinetic force ($\text{m/s}^2$).event.accelerationIncludingGravityincorporates Earth's continuous gravitational pull ($\approx 9.81 \text{ m/s}^2$).event.rotationRatemeasures angular rotational speed around 3 axes in degrees per second.- Shake detection requires computing 3D Euclidean magnitude combined with a cooldown debounce lock.
- --