2012-06-17 43 views
12

如何獲取表示設備背面相對於地球座標指向的方向矢量?在Android中獲取方向矢量

例如,如果放在桌子上(屏幕朝上),它應該讀取[0,0,-1],並且如果垂直朝向北方,則應該讀取[1,0,0]等。

我知道如何從標題,俯仰和滾轉來計算它,只要它們是相對於地球座標。在這裏要明確我不是在尋找角速度,而是相對於與地球相切平面的實際當前角度。因此,如果設備垂直握住並朝北,則角度「alpha」應爲0或360,角度「beta」應爲90,「gamma」應爲0.我無法弄清楚如何獲取這些值無論是。

我一直在閱讀API,我仍然無法找到如何得到這些東西。

public void onSensorChanged(SensorEvent event) { 
    // ?  
} 

感謝您的任何見解。

回答

9

SensorManager.getRotationMatrix()做了以下概述,寫在我發現之前。我會留下補充說明,因爲如果你想糾正磁性和真正北方之間的差異,你仍然需要它。

粗略的算法是獲得旋轉矩陣,乘以它的矢量[0,0,-1],然後調整它到你的座標系。爲什麼? Android的文檔給出了設備和世界

deviceworld

[0,0,-1]座標系中垂直向下遠離屏幕的Android設備COORDS點。如果您將旋轉矩陣R乘以此矢量,則當設備在桌面上時,您將在世界座標系中獲得[0,0,-1]。當它向北直立時,您會得到[0,-1,0],這表示您已經選擇了一個座標系,其中xy與Android系統交換,但這只是一個約定的更改。

注意R * [0,0,-1]^T只是R的第三列否定。從這我得到的僞代碼:

getRotationMatrix(R); 
Let v = first three elements of third column of R. 
swap v[0] and v[1] 

這應該得到你想要的。

關於getRotationMatrix()正在做什麼的其他信息如下。


同時需要accerometer數據確立方向「向下」和磁力數據來確定方向「北」。您必須假定加速度計只感應重力(設備靜止或以穩定速度移動)。然後,您需要將磁強計矢量投影到垂直於重力矢量的平面上(因爲磁場通常不與地球表面相切)。這給你兩個軸。第三個是正交的,所以可以通過交叉積來計算。這給出了設備系統中的地球座標向量。它看起來像你想要的反轉:地球座標中的設備座標。爲此只需構造方向餘弦矩陣和反轉矩陣。

我會補充一點,上面的討論假設磁力儀矢量指向北方。我想(從高中科學!)它實際上是向南磁性的,但手頭沒有裝置,所以不能嘗試。當然,磁北/南與真的不同,從零到180度取決於你在地球上的位置。您可以檢索GPS座標並計算實際偏移量。

如果您不熟悉這些所需的數學運算,我可以進一步解釋,但必須晚一些。

+0

太感謝了,這是真的很有幫助。你們都給出了這麼好的答案,我希望有一種方法可以選擇它們。看起來我只能用Sensor.TYPE_GRAVITY獲得重力矢量 - 他們確實對我有用。我希望得到一個「北方」矢量也很容易。 – Joey

+0

我最終使用你的解釋得到它。原來,我將重力傳感器和磁場傳感器返回的值直接傳遞給getRotationMatrix(),它將所有東西都處理完畢。然後,將該矩陣乘以[0,0,-1]並得到dv。 – Joey

8

閱讀此頁:http://developer.android.com/reference/android/hardware/Sensor.html

在API 8及以上,存在通過組合所有可用的傳感器和相應的過濾器的輸入端產生的「虛擬」的傳感器。 「TYPE_ORIENTATION」傳感器爲您提供設備的全方位定位,但由於某些方向的故障狀態,此接口已棄用。新的傳感器是TYPE_ROTATION_VECTOR(API 9及以上版本),它使您的設備定位爲四元數。這真的是最好的傳感器,但它背後的數學有點沉重。

失敗的是,您要做的就是調用SensorManager.getRotationMatrix(),傳遞最新的重力和磁力計數據。這將返回一個旋轉矩陣,該矩陣可用於將矢量從設備座標轉換爲世界座標,反之亦然(只需對矩陣進行轉置以將其反轉)。

getOrientation()函數可以爲您提供標題,俯仰和滾動,但它們與TYPE_ORIENTATION傳感器具有相同的故障狀態。

Examples: 

    Device flat on a table, top facing north: 
    1 0 0 
    0 1 0 
    0 0 1 

    Tilted up 30 degrees (rotated about X axis) 
    1 0  0 
    0 0.86 -0.5 
    0 0.5 0.86 

    Device vertical (rotated about X axis), facing north: 
    1 0 0 
    0 0 -1 
    0 1 0 

    Device flat on a table, top facing west: 
    0 -1 0 
    1 0 0 
    0 0 1 

    Device rotated about its Y axis, onto its left side, top 
    facing north: 
    0 0 -1 
    0 1 0 
    1 0 0 

這裏是你可能會發現一些有用的示例代碼:

public void onSensorChanged(SensorEvent event) { 
    long now = event.timestamp;  // ns 

    switch(event.sensor.getType()) { 
     case Sensor.TYPE_ACCELEROMETER: 
     gData[0] = event.values[0]; 
     gData[1] = event.values[1]; 
     gData[2] = event.values[2]; 
     break; 
     case Sensor.TYPE_MAGNETIC_FIELD: 
     mData[0] = event.values[0]; 
     mData[1] = event.values[1]; 
     mData[2] = event.values[2]; 
     haveData = true; 
     break; 
    } 

    if(haveData) { 
     double dt = (now - last_time) * .000000001; 

     SensorManager.getRotationMatrix(R1, Imat, gData, mData); 
     getOrientation(R1, orientation); 
     pfdView.newOrientation(orientation[2], (float)dt); 


     Log.d(TAG, "yaw: " + (int)(orientation[0]*DEG)); 
     Log.d(TAG, "pitch: " + (int)(orientation[1]*DEG)); 
     Log.d(TAG, "roll: " + (int)(orientation[2]*DEG)); 

     acft.compass = orientation[0]; 

     last_time = now; 
    } 
} 
+0

感謝您的答覆 - 我只有兩個問題,如果我使用TYPE_ROTATION_VECTOR,是以世界座標表示的量子位?它是否已經集成,還是我必須將它集成以獲取當前矢量? – Joey

+0

設備的世界座標,我相信。已經轉換爲四元數單位,有時w項被省略。說實話,我從來沒有用過它。我上面顯示的代碼來自我爲1.5編寫的一個航班導航應用程序,在新的傳感器類型可用之前。 –