2012-06-17 32 views
12

Làm thế nào tôi có thể nhận được một vector hướng đại diện cho hướng mà mặt sau của thiết bị trỏ đến các tọa độ của trái đất? Ví dụ: nếu đặt xuống trên bàn (màn hình hướng lên trên), nó phải đọc [0,0, -1] và nếu được giữ theo chiều dọc hướng về phía bắc thì phải đọc [1,0,0], v.v.Nhận hướng Vector trong Android

Tôi biết cách tính toán nó từ tiêu đề, quảng cáo chiêu hàng và cuộn, miễn là chúng có liên quan đến tọa độ trái đất. Để được rõ ràng ở đây tôi không tìm kiếm vận tốc góc, nhưng góc hiện tại thực tế liên quan đến mặt phẳng tiếp xúc với trái đất. Vì vậy, nếu thiết bị được giữ theo chiều dọc và hướng về phía bắc, góc "alpha" phải đọc 0 hoặc 360, góc "beta" phải đọc 90 và "gamma" phải đọc 0. Tôi không thể tìm ra cách để có được các giá trị này hoặc.

Tôi đã đọc API cả ngày và tôi vẫn không thể tìm thấy cách nhận một trong những thứ này.

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

Cảm ơn mọi thông tin chi tiết.

Trả lời

9

SensorManager.getRotationMatrix() làm những gì được nêu bên dưới, được viết trước khi tôi phát hiện ra điều này. Tôi sẽ để lại lời giải thích thêm bởi vì nếu bạn muốn sửa chữa cho sự khác biệt giữa phía bắc từ tính và thực sự bạn vẫn sẽ cần nó.

Thuật toán thô là lấy ma trận xoay, nhân vectơ [0,0,-1] với nó, sau đó điều chỉnh điều này theo hệ tọa độ của bạn. Tại sao? docs Android cung cấp cho các hệ thống phối hợp dành cho điện thoại và trên thế giới

deviceworld

Note [0,0,-1] trong coords thiết bị Android điểm vuông góc lùi ra khỏi màn hình. Nếu bạn nhân ma trận xoay R bằng véc-tơ này, bạn sẽ nhận được [0,0,-1] trong coords thế giới khi thiết bị nằm trên bàn đối diện như bạn mong muốn. Khi đứng thẳng về phía bắc, bạn sẽ nhận được [0,-1,0], cho biết rằng bạn đã chọn một hệ tọa độ nơi xy được đổi chỗ với hệ thống Android, nhưng đó chỉ đơn giản là thay đổi quy ước.

Lưu ý R * [0,0,-1]^T chỉ là cột thứ ba của R bị từ chối. Từ đây tôi nhận được mã giả:

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

Điều này nên nhận được những gì bạn muốn.

Thông tin bổ sung về những gì getRotationMatrix() đang thực hiện sau.


Bạn cần cả dữ liệu kế trọng số để thiết lập hướng "xuống" và dữ liệu từ kế để xác định hướng "phía bắc". Bạn sẽ phải giả định rằng gia tốc kế chỉ cảm nhận được lực hấp dẫn (thiết bị là tĩnh hoặc di chuyển với tốc độ ổn định). Sau đó, bạn cần phải chiếu vector từ kế lên mặt phẳng vuông góc với vector trọng lực (vì từ trường thường không tiếp xúc với bề mặt trái đất). Điều này cung cấp cho bạn hai trục. Thứ ba là trực giao, vì vậy có thể được tính bằng sản phẩm chéo. Điều này cung cấp cho bạn các vectơ phối hợp đất trong hệ thống thiết bị. Có vẻ như bạn muốn nghịch đảo: tọa độ thiết bị trong tọa độ trái đất. Đối với điều này chỉ cần xây dựng ma trận của hướng cosin và đảo ngược.

Tôi sẽ thêm rằng cuộc thảo luận ở trên giả thiết rằng vector từ kế trỏ về phía bắc. Tôi nghĩ (từ khoa học trung học!nó thực sự hướng về phía nam từ tính, nhưng không có thiết bị nào trong tầm tay nên không thể thử nó. Tất nhiên, từ bắc/nam là khác nhau từ 0 đến 180 độ tùy thuộc vào nơi bạn ở trên trái đất. Bạn có thể truy xuất tọa độ GPS và tính toán mức bù thực tế.

Nếu bạn không quen thuộc với toán cần thiết để làm điều này, tôi có thể giải thích thêm, nhưng nó sẽ phải sau này.

+0

Cảm ơn rất nhiều, đây là thực sự hữu ích. Cả hai bạn đã đưa ra những câu trả lời tốt như vậy, tôi ước có một cách để chọn cả hai. Có vẻ như tôi có thể lấy vector trọng lực chỉ với Sensor.TYPE_GRAVITY - chúng đã làm việc đó cho tôi. Tôi ước nó dễ dàng để có được một vector "phía bắc". – Joey

+0

Tôi đã nhận được nó bằng cách sử dụng lời giải thích của bạn. Hóa ra tôi vượt qua các giá trị được trả lại từ một cảm biến trọng lực và một cảm biến từ trường trực tiếp vào getRotationMatrix() và nó hoạt động mọi thứ. Sau đó, nhân ma trận đó với [0,0, -1] và nhận dv. – Joey

8

đọc trang này: http://developer.android.com/reference/android/hardware/Sensor.html

Trong API 8 trở lên, có cảm biến "ảo" được tạo ra bằng cách kết hợp các yếu tố đầu của tất cả các cảm biến có sẵn và các bộ lọc thích hợp. Cảm biến "TYPE_ORIENTATION" cung cấp cho bạn định hướng allover của thiết bị nhưng giao diện này không được chấp nhận do trạng thái lỗi ở các hướng nhất định. Cảm biến mới là TYPE_ROTATION_VECTOR (API 9 trở lên), cho phép định hướng thiết bị của bạn như một quaternion. Đây thực sự là cảm biến tốt nhất để sử dụng, nhưng toán học đằng sau nó hơi nặng.

Nếu không, những gì bạn làm là gọi SensorManager.getRotationMatrix(), truyền dữ liệu trọng lực và từ kế mới nhất. Điều này sẽ trả về một ma trận xoay có thể được sử dụng để chuyển đổi một vector từ các tọa độ thiết bị thành các tọa độ thế giới hoặc ngược lại (chỉ cần chuyển đổi ma trận để đảo ngược nó).

Hàm getOrientation() có thể cung cấp cho bạn tiêu đề, quảng cáo chiêu hàng và cuộn, nhưng chúng có cùng trạng thái lỗi như cảm biến 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 

Dưới đây là một số mẫu mã bạn có thể thấy hữu ích:

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

Cảm ơn bạn đã trả lời - Tôi chỉ có hai câu hỏi, nếu tôi sử dụng TYPE_ROTATION_VECTOR, là lượng tử được thể hiện trong các tọa độ thế giới? Nó đã được tích hợp chưa, hoặc tôi có phải tích hợp nó để lấy véc tơ hiện tại không? – Joey

+0

tọa độ thế giới của thiết bị, tôi tin. Đã được chuyển đổi thành một đơn vị quaternion, và đôi khi các thuật ngữ w được bỏ qua. Thành thật mà nói, tôi chưa bao giờ sử dụng nó. Mã tôi hiển thị ở trên là từ ứng dụng điều hướng chuyến bay tôi đã viết cho 1.5, trước khi có các loại cảm biến mới. –