Gyro + Accelerometerを使用して、iPhoneの正確な移動距離(長距離ではない)を計算するアプリを作成したい。ここにはGPSは必要ありません。
この問題にどのように取り組むべきですか?
この問題の背後にある基本的な計算は式にあります
(およびyおよびzの変位の同様の式)および基本的なジオメトリはピタゴラスの定理です。
したがって、加速度計の信号がローパスフィルターを通過し、サンプリング間隔dtに合わせてビニングされると、xの変位を(pardon my C ...)として見つけることができます
float dx=0.0f;
float vx=0.0f;
for (int i=1; i<n; i++)
{
vx+=(acceleration_x[i-1] + acceleration_x[i])/2.0f*dt;
dx+=vx*dt;
}
dyおよびdzについても同様です。ここに
float acceleration_x[n];
時間0、dt、2 * dt、3 * dt、...(n-1)* dtでの測定の開始から終了までのx加速度値が含まれます。
総変位を見つけるには、ただ
dl=sqrt(dx*dx + dy*dy + dz*dz);
これにはジャイロスコープは必要ありませんが、直線距離を測定する場合は、ジャイロスコープの読み取り値を使用して、デバイスの回転が大きすぎないことを制御できます。回転が強すぎる場合は、ユーザーに測定をやり直させます。
直線加速度を2回積分することで位置を取得できますが、エラーは恐ろしいです。実際には役に立ちません。
理由(Google Tech Talk)の説明 23:20です。このビデオを強くお勧めします。
同様の質問:
加速度計を使用してAndroidアプリケーション開発 の距離を測定する方法
Update(2013年2月24日):@Simonはい、動きについて詳しく知っている場合、たとえば人が歩いていてセンサーが足に付いている場合、その後、さらに多くのことができます。これらは呼ばれます
ドメイン固有の仮定。
仮定が成り立たないとひどく壊れてしまい、実装するのが非常に面倒になります。それでも、それらが機能すれば、楽しいことができます。私の答えのリンクを参照してください Androidの加速度センサーの精度(慣性航法) 屋内での測位。
Simple iPhone motion detect で説明されているようなCore Motionインターフェイスを使用する必要があります。特に、すべての回転は非常に正確に追跡できます。直線運動に関連する何かをするつもりなら、これは非常に難しいことです。 Core Motionで加速度計データから変位を取得する をご覧ください。
私はこれにひびを取り、あきらめました(夜遅く、どこにも行かないようでした)。これはUnity3dプロジェクト用です。
誰かが私が中断したところを取り戻したいと思うなら、私はこのすべてが何をするかについて詳しく述べたいです。
基本的に誤検知であることが判明した後、ローパスフィルターを使用してこれをフィルター処理し、トレンドを見つけてバウンスを削除しようとした後、(acc_x [i-1] + acc_x [i] )/ 2。
誤検知はまだ傾きから生じているように見えますが、私はそれを削除しようとしました。
このコードが有用であるか、どこかにあなたを導くならば、私に知らせてください!
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// [email protected]
/// </summary>
public class AccelerometerInput : MonoBehaviour
{
Transform myTransform;
Gyroscope gyro;
GyroCam gyroCam;
void Awake()
{
gyroCam= FindObjectOfType<GyroCam> ();
myTransform = transform;
if (SystemInfo.supportsGyroscope) {
gyro = Input.gyro;
gyro.enabled = true;
}
}
bool shouldBeInitialized = false;
void Update ()
{
transform.Translate (GetAccelerometer ());// * Time.deltaTime * speed);
//GetComponent<Rigidbody> ().AddForce (GetAccelerometer ());
}
public float speed = 10.0F;
public Vector3 dir;
public float f;
Vector3 GetAccelerometer()
{
dir = Input.acceleration;
dir.x *= gyro.attitude.x;
dir.z *= gyro.attitude.z;
if (Mathf.Abs (dir.x) < .001f)
dir.x = 0;
dir.y = 0;
if (Mathf.Abs (dir.z) < .001f)
dir.z = 0;
RecordPointsForFilter (dir);
//print ("Direction : " + dir.ToString("F7"));
return TestPointsForVelocity();
}
Vector3[] points = new Vector3[20];
int index;
void RecordPointsForFilter(Vector3 recentPoint)
{
if (index >= 20)
index = 0;
points [index] = EvaluateTrend (recentPoint);;
index++;
}
//try to remove bounces
float xTrend = 0;
float zTrend = 0;
float lastTrendyX = 0;
float lastTrendyZ = 0;
Vector3 EvaluateTrend(Vector3 recentPoint)
{
//if the last few points were positive, and this point is negative, don't pass it along
//accumulate points into a trend
if (recentPoint.x > 0)
xTrend += .01f;
else
xTrend -= .1f;
if (recentPoint.z > 0)
zTrend += .1f;
else
zTrend -= .1f;
//if point matches trend, keep it
if (xTrend > 0) {
if (recentPoint.x > 0)
lastTrendyX = recentPoint.x;
} else // xTrend < 0
if (recentPoint.x < 0)
lastTrendyX = recentPoint.x;
if (zTrend > 0) {
if (recentPoint.z > 0)
lastTrendyZ = recentPoint.z;
} else // xTrend < 0
if (recentPoint.z < 0)
lastTrendyZ = recentPoint.z;
return new Vector3( lastTrendyX, 0, lastTrendyZ);
}
Vector3 TestPointsForVelocity()
{
float x = 0;
float z = 0;
float xAcc = 0;
float zAcc = 0;
int successfulHits = 0;
for(int i = 0; i < points.Length; i++)
{
if(points[i]!=null)
{
successfulHits ++;
xAcc += points[i].x;
zAcc += points[i].z;
}
}
x = xAcc / successfulHits;
z = zAcc / successfulHits;
return new Vector3 (x, 0, z);
}
}
これが answer です。誰かが前に尋ねました。
RangeFinder という同じことを行うアプリ(App Storeで入手可能)があります。
(acc_x [i-1] + acc_x [i])/ 2はローパスフィルターであり、時間内の2つのメジャー間の平均値です。
こちらもご覧ください: http://www.freescale.com/files/sensors/doc/app_note/AN3397.pdf pag:3