モバイルデバイスのアクセルロメーターは、デバイスの向きと運動を決定するために三軸の直線加速度を測定する MEMS センサーです。Google Android Sensors Guide (2025)によると、アクセルロメーターはモバイルアプリで最も広く使われているセンサーです。MEMS技術により、センサーを1 mmのチップに収め、1 mW未満の消費電力で動作します。
ポイント
アクセルロメーターは、互いに直交する三つの軸に加速度の投影を測定する微細電子機械系 (MEMS) センサーです: X (水平…右向き)、Y (垂直…上向き)、Z (画面に垂直)。静止状態では、Z軸に9.8 m/s²を示します — これは地球中心に向かう重力加速度です。この値を基にシステムがデバイスの向きを決定します: Z値が0に近く、Y値が-9.8 m/s²に近ければ水平に回転しています。加速度計の測定範囲は、チップモデルにより通常±2g、±4g、±8gまたは±16gです。
現代のアクセルロメーターにはいくつかの重要パラメーターがあります: センシティビティ (0.001 m/s²から)、サンプリングレート (1000 Hzまで)、測定範囲、ノイズレベル。フラッグシップ機では、STMicroelectronics LSM6DSO または Bosch BMI270 センサーを使用し、1600 Hzまでの周波数、アクティブモードでの消費電力0.5 mW未満を実現しています。サンプリングレートが高いほど、アプリが受け取る信号は詳細になります — ゲームでは200–400 Hz、歩数計測では10–50 Hzで十分です。センサーノイズは測定精度に影響を与え、OSレベルのローパスフィルターで補償されます。
MEMSアクセルロメーターは内部的に、固定電極間に弾性カンチレバーに吊るされた微小なシリコン構造からなります: 微小プルーフ質量。加速度がかかると質量が屈み、動作要素と固定要素の間の電容が変化します — この変化を測定して電気信号に変換します。クローズドループ応答回路が静電力を使って質量を中央位置に保ち、全範囲で線形性を確保します。オープンループシステムでは、質量が自由に動き、計算は簡単ですが精度は低くなります。STMicroelectronics (2025)によると、クローズドループアクセルロメーターは、0.1 mg/°C未満の温度ドリフトで、0.001gの精度を達成します。
アクセルロメーターの三軸は、三次元空間の三つの尺度に対応します: X (左右の傾き)、Y (上下)、Z (画面に対して前後)。画面を上にしてデバイスをテーブルに置くと、重力加速度ベクトルはZ軸に沿って9.8 m/s²となります。デバイスを傾けると、重力の投影が軸間に再分配されます — これらの投影から、0.1度の精度で傾き角度を計算できます。重力の影響を受けない運動検出には、ハイパスフィルターを使用して加速度の動的要素 (デバイス自身の運動) を静的要素 (重力) から分離します。
Androidでは、アクセルロメーターへのアクセスは、SensorManagerクラスとSensorEventListenerインタフェースを通じて提供されます。アプリはSENSOR_SERVICEシステムサービスを取得し、TYPE_ACCELEROMETERセンサーをリクエストし、指定された更新レートでリスナーを登録します。システムは新しい測定ごとに値の配列を伴ってonSensorChangedをコールします: values[0] = X, values[1] = Y, values[2] = Z。以下は、Kotlinでアクセルロメーターデータを読み取る完全な例です。
val sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
val sensorEventListener = object : SensorEventListener {
override fun onSensorChanged(event: SensorEvent) {
val x = event.values[0]
val y = event.values[1]
val z = event.values[2]
// 傾き角度の計算
val pitch = Math.atan2(
x.toDouble(),
Math.sqrt(y.toDouble() * y + z.toDouble() * z)
)
// 新しい角度でUIを更新
textViewAngle.text = "傾き: ${Math.toDegrees(pitch)}°"
}
override fun onAccuracyChanged(
sensor: Sensor, accuracy: Int
) { }
}
sensorManager.registerListener(
sensorEventListener,
accelerometer,
SensorManager.SENSOR_DELAY_GAME
)
例では、SensorManager.SENSOR_DELAY_GAMEが更新レートを約50 Hz に設定します。ゲームやインタラクティブアプリに最適です。歩数計測にはSENSOR_DELAY_NORMAL (~5 Hz)を使用し、精密測定にはSENSOR_DELAY_FASTEST (~200 Hz)を使用します。onSensorChangedでは、event.values配列に現在のセンサー読み値が含まれています。X、Y、Z値に基づいて、atan2を使用して傾き角度 (ピッチ) を計算します — これは、向きセンサーを使わずにデバイスの向きを決定する基本式です。バッテリーを節約するために、onPauseでリスナーを解除することを忘れないでください。
private val alpha = 0.8f
private val gravity = FloatArray(3)
private val linearAcceleration = FloatArray(3)
override fun onSensorChanged(event: SensorEvent) {
// 重力抽出用ローパスフィルター (LPF)
gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0]
gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1]
gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2]
// 重力を減算 — 直線加速度を取得
linearAcceleration[0] = event.values[0] - gravity[0]
linearAcceleration[1] = event.values[1] - gravity[1]
linearAcceleration[2] = event.values[2] - gravity[2]
}
系数alphaのローパスフィルターが重力コンポーネント (静止ベクトル) を抽出します; これを減じるとデバイスの純状加速度 (直線加速度) が得られます。これは、向きを考慮せずに運動を検出するために必要です — 例えば、歩き、振っている、衝撃の検出。alpha = 0.8は、フィルターが新しい信号の約20%を通し、前回の80%を保持することを意味します — 大きな遅延なしでノイズを除去するのに十分です。
iOSでは、アクセルロメーターへのアクセスは、Core MotionフレームワークのCMMotionManagerクラスを通じて提供されます。アプリはマネージャーのインスタンスを作成し、キューとハンドラーを伴ってstartAccelerometerUpdatesをコールします。データはCMAccelerometerDataとして返され、x、y、zフィールドを含むCMAcceleration構造体を持ちます。以下は、ノイズフィルタリング付きのSwiftでのアクセルロメーターデータ取得例です。
import CoreMotion
let motionManager = CMMotionManager()
motionManager.accelerometerUpdateInterval = 1.0 / 60.0
guard motionManager.isAccelerometerAvailable else { return }
motionManager.startAccelerometerUpdates(to: OperationQueue.current!) {
data, error in
guard let acceleration = data?.acceleration,
error == nil else { return }
// g単位の値 (1 g = 9.8 m/s²)
let magnitude = sqrt(
acceleration.x * acceleration.x +
acceleration.y * acceleration.y +
acceleration.z * acceleration.z
)
// magnitude > 2.5 g なら振っている状態を検出
if magnitude > 2.5 {
DispatchQueue.main.async {
self.handleShake()
}
}
}
例では、accelerometerUpdateIntervalを約1/60秒 (~60 Hz) に設定します — スムーズなアニメーションとゲームに最適です。isAccelerometerAvailableメソッドで、デバイスにセンサーがあるかを確認できます。加速度値はg単位 (1 g = 9.8 m/s²) で返されます。ベクトルmagnitudeは、3つの要素のユークリッドノルムとして計算されます — 2.5 gを超えると、デバイスの振っている状態と判断されます。更新を停止するには、画面を退くときに必ずstopAccelerometerUpdatesを実行してください。
アクセルロメーターは、様々なモバイルアプリで使用されています。最も明確なシナリオは自動画面回転です: システムがアクセルロメーターデータに基づいて縦横を切り替えます。ゲームでは、アクセルロメーターが制御入力となります — デバイスを傾けるとステアリングホイールが回ったり、キャラクターが動きます。フィットネスアプリは、歩行中の特徴的な加速度ピークに基づいて歩数を計算します。以下は、シナリオ別のセンサー要件の表です。
| シナリオ | 周波数 (Hz) | 精度 | フィルタリング |
|---|---|---|---|
| 自動画面回転 | 5–10 | 低 | LPF |
| 歩数計測 | 20–50 | 中 | HPF + ピーク検出 |
| ゲーム (レーシング) | 50–200 | 高 | キลリブレーション + LPF |
| カメラ安定 | 200–1000 | 最高 | 補完フィルター |
| ジェスチャー認識 | 50–100 | 中 | HPF + 番以下検出 |
アクセルロメーターを実装する際は、デバイスの発熱やセンサーの老化が読み取り精度に影響する可能性があることに注意してください。クリティカルな測定 (ビデオ安定、コンパス) には、センサーフュージョンの一部としてジャイロスコープと磁気計も使用することをお勧めします。
アクセルロメーターにはいくつかの誤差があります: ゼロバイアス — 静止時にセンサーが零以外の値を示す、スケールファクター誤差 — 軸によってセンシティビティが異なる、ノイズ — 単体の読み取り精度を低下させます。MEMSセンサーは製造時にキลリブレーションされますが、温度や機械的応力によってパラメーターが漸走することがあります。アプリ内の補償には、簡単なキลリブレーションを実装できます: 静止時に平均値 (バイアス) を記録し、後の測定から差し引きます。より精密なキลリブレーションには、デバイスを全ての軸で回転させる必要があります — この方法を六点キลリブレーションと呼び、0.5%未満の誤差を達成します。
よくある質問
アクセルロメーターは、約1 mmのMEMSセンサーで、三軸の加速度を測定します。外部ソースを使わずに、デバイスの向き (縦横)、振っている状態、歩き、運動を検出できます。
アクセルロメーターは直線加速度 (重力を含む) を測定し、ジャイロスコープは角速度 (回転) を測定します。アクセルロメーターは向きを決定し、ジャイロスコープは回転を検出します。両方を組み合わせると、空間内の精確な運動追跡 (センサーフュージョン) が可能になります。
SensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)を使用してセンサーを取得し、SensorEventListenerでregisterListenerを行います。onSensorChangedでは、event.values配列にX、Y、Z値 (m/s²) が含まれます。onPauseで必ず登録解除を行ってください。
magnitude = sqrt(x² + y² + z²) を計算します。2–3 g (重力フィルタリング後) を超えると、デバイスが振られたと判断されます。iOSでは番以下2.5 gのCMMotionManagerを使用し、Androidでは番以下15 m/s²のSensor.TYPE_LINEAR_ACCELERATIONを使用します。
はい、簡単なキลリブレーションでは、デバイスを平らな面に置き、2–3秒間各軸の平均値を記録し、その値を後の測定から減じます。これでゼロバイアスは補償できますが、スケール誤差は補償できません。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。