Nền tảng Android cung cấp một số cảm biến cho phép bạn theo dõi chuyển động của thiết bị.
Cấu trúc có thể có của các cảm biến sẽ khác nhau tuỳ theo loại cảm biến:
- Các cảm biến trọng lực, gia tốc tuyến tính, vectơ xoay, chuyển động đáng kể, bộ đếm bước và bộ phát hiện bước đều dựa trên phần cứng hoặc phần mềm.
- Cảm biến gia tốc kế và con quay hồi chuyển luôn dựa trên phần cứng.
Hầu hết các thiết bị chạy Android đều có gia tốc kế và nhiều thiết bị hiện có cả con quay hồi chuyển. Tính khả dụng của các cảm biến dựa trên phần mềm có nhiều biến số hơn vì chúng thường dựa vào một hoặc nhiều cảm biến phần cứng để lấy dữ liệu. Tuỳ thuộc vào thiết bị, các cảm biến dựa trên phần mềm này có thể lấy dữ liệu từ gia tốc kế và từ kế hoặc từ con quay hồi chuyển.
Cảm biến chuyển động rất hữu ích khi theo dõi chuyển động của thiết bị, chẳng hạn như nghiêng, rung, xoay hoặc vung. Chuyển động này thường phản ánh hoạt động đầu vào trực tiếp của người dùng (ví dụ: người dùng lái xe trong một trò chơi hoặc người dùng điều khiển một quả bóng trong một trò chơi), nhưng cũng có thể phản ánh môi trường thực tế mà thiết bị đang ở (ví dụ: di chuyển cùng bạn khi bạn lái xe). Trong trường hợp đầu tiên, bạn đang theo dõi chuyển động tương ứng với khung tham chiếu của thiết bị hoặc khung tham chiếu của ứng dụng; trong trường hợp thứ hai, bạn đang theo dõi chuyển động tương ứng với khung tham chiếu của thế giới. Bản thân cảm biến chuyển động thường không được dùng để theo dõi vị trí của thiết bị, nhưng có thể được dùng với các cảm biến khác, chẳng hạn như cảm biến từ trường, để xác định vị trí của thiết bị so với khung tham chiếu của thế giới (xem Cảm biến vị trí để biết thêm thông tin).
Tất cả các cảm biến chuyển động đều trả về mảng đa chiều gồm các giá trị cảm biến cho mỗi SensorEvent
. Ví dụ: trong một sự kiện cảm biến duy nhất, gia tốc kế sẽ trả về dữ liệu về lực gia tốc cho 3 trục toạ độ và con quay hồi chuyển sẽ trả về dữ liệu về tốc độ quay cho 3 trục toạ độ. Các giá trị dữ liệu này được trả về trong một mảng float
(values
) cùng với các tham số SensorEvent
khác. Bảng 1 tóm tắt các cảm biến chuyển động có trên nền tảng Android.
Bảng 1. Các cảm biến chuyển động được hỗ trợ trên nền tảng Android.
Cảm biến | Dữ liệu sự kiện cảm biến | Mô tả | Đơn vị đo lường |
---|---|---|---|
TYPE_ACCELEROMETER |
SensorEvent.values[0] |
Lực gia tốc dọc theo trục x (bao gồm cả trọng lực). | m/s2 |
SensorEvent.values[1] |
Lực gia tốc dọc theo trục y (bao gồm cả trọng lực). | ||
SensorEvent.values[2] |
Lực gia tốc dọc theo trục z (bao gồm cả trọng lực). | ||
TYPE_ACCELEROMETER_UNCALIBRATED |
SensorEvent.values[0] |
Gia tốc đo được dọc theo trục X mà không có bất kỳ sự bù đắp nào cho độ lệch. | m/s2 |
SensorEvent.values[1] |
Gia tốc đo được dọc theo trục Y mà không có bất kỳ sự bù đắp thiên vị nào. | ||
SensorEvent.values[2] |
Gia tốc đo được dọc theo trục Z mà không có bất kỳ sự bù đắp thiên vị nào. | ||
SensorEvent.values[3] |
Gia tốc đo được dọc theo trục X với mức bù thiên vị ước tính. | ||
SensorEvent.values[4] |
Gia tốc đo được dọc theo trục Y với mức bù sai số ước tính. | ||
SensorEvent.values[5] |
Gia tốc đo được dọc theo trục Z với mức bù thiên vị ước tính. | ||
TYPE_GRAVITY |
SensorEvent.values[0] |
Lực hấp dẫn dọc theo trục x. | m/s2 |
SensorEvent.values[1] |
Lực hấp dẫn dọc theo trục y. | ||
SensorEvent.values[2] |
Lực hấp dẫn dọc theo trục z. | ||
TYPE_GYROSCOPE |
SensorEvent.values[0] |
Tốc độ xoay quanh trục x. | rad/s |
SensorEvent.values[1] |
Tốc độ xoay quanh trục y. | ||
SensorEvent.values[2] |
Tốc độ xoay quanh trục z. | ||
TYPE_GYROSCOPE_UNCALIBRATED |
SensorEvent.values[0] |
Tốc độ xoay (không bù độ lệch) quanh trục x. | rad/s |
SensorEvent.values[1] |
Tốc độ xoay (không bù độ lệch) quanh trục y. | ||
SensorEvent.values[2] |
Tốc độ xoay (không bù độ lệch) quanh trục z. | ||
SensorEvent.values[3] |
Độ lệch ước tính xung quanh trục x. | ||
SensorEvent.values[4] |
Độ lệch ước tính xung quanh trục y. | ||
SensorEvent.values[5] |
Độ lệch ước tính xung quanh trục z. | ||
TYPE_LINEAR_ACCELERATION |
SensorEvent.values[0] |
Lực gia tốc dọc theo trục x (không bao gồm trọng lực). | m/s2 |
SensorEvent.values[1] |
Lực gia tốc dọc theo trục y (không bao gồm trọng lực). | ||
SensorEvent.values[2] |
Lực gia tốc dọc theo trục z (không bao gồm trọng lực). | ||
TYPE_ROTATION_VECTOR |
SensorEvent.values[0] |
Thành phần vectơ xoay dọc theo trục x (x * sin(θ/2)). | Không có đơn vị |
SensorEvent.values[1] |
Thành phần vectơ xoay dọc theo trục y (y * sin(θ/2)). | ||
SensorEvent.values[2] |
Thành phần vectơ xoay dọc theo trục z (z * sin(θ/2)). | ||
SensorEvent.values[3] |
Thành phần vô hướng của vectơ xoay ((cos(θ/2)).1 | ||
TYPE_SIGNIFICANT_MOTION |
Không áp dụng | Không có câu trả lời thích hợp | Không áp dụng |
TYPE_STEP_COUNTER |
SensorEvent.values[0] |
Số bước mà người dùng đã thực hiện kể từ lần khởi động lại gần đây nhất trong khi cảm biến được kích hoạt. | Các bước |
TYPE_STEP_DETECTOR |
Không áp dụng | Không có câu trả lời thích hợp | Không áp dụng |
1 Thành phần vô hướng là một giá trị không bắt buộc.
Cảm biến vectơ xoay và cảm biến trọng lực là những cảm biến thường được dùng nhất để phát hiện và theo dõi chuyển động. Cảm biến vectơ xoay có tính linh hoạt cao và có thể dùng cho nhiều tác vụ liên quan đến chuyển động, chẳng hạn như phát hiện cử chỉ, theo dõi sự thay đổi về góc và theo dõi các thay đổi về hướng tương đối. Ví dụ: cảm biến vectơ xoay là lựa chọn lý tưởng nếu bạn đang phát triển một trò chơi, ứng dụng thực tế tăng cường, la bàn 2 chiều hoặc 3 chiều hoặc ứng dụng ổn định camera. Trong hầu hết các trường hợp, việc sử dụng các cảm biến này là lựa chọn tốt hơn so với việc sử dụng cảm biến gia tốc và cảm biến từ trường hoặc cảm biến hướng.
Các cảm biến trong Dự án nguồn mở Android
Dự án nguồn mở Android (AOSP) cung cấp 3 cảm biến chuyển động dựa trên phần mềm: cảm biến trọng lực, cảm biến gia tốc tuyến tính và cảm biến vectơ xoay. Các cảm biến này đã được cập nhật trong Android 4.0 và hiện sử dụng con quay hồi chuyển của thiết bị (ngoài các cảm biến khác) để cải thiện độ ổn định và hiệu suất. Nếu muốn thử các cảm biến này, bạn có thể xác định chúng bằng phương thức getVendor()
và phương thức getVersion()
(nhà cung cấp là Google LLC; số phiên bản là 3). Bạn cần xác định các cảm biến này theo nhà cung cấp và số phiên bản vì hệ thống Android coi 3 cảm biến này là cảm biến phụ. Ví dụ: nếu một nhà sản xuất thiết bị cung cấp cảm biến trọng lực riêng, thì cảm biến trọng lực AOSP sẽ xuất hiện dưới dạng cảm biến trọng lực phụ. Cả 3 cảm biến này đều dựa vào con quay hồi chuyển: nếu một thiết bị không có con quay hồi chuyển, thì các cảm biến này sẽ không xuất hiện và không dùng được.
Sử dụng cảm biến trọng lực
Cảm biến trọng lực cung cấp một vectơ ba chiều cho biết hướng và độ lớn của trọng lực. Thông thường, cảm biến này được dùng để xác định hướng tương đối của thiết bị trong không gian. Đoạn mã sau đây cho biết cách lấy một phiên bản của cảm biến trọng lực mặc định:
Kotlin
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY)
Java
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
Các đơn vị này giống với đơn vị mà cảm biến gia tốc sử dụng (m/s2) và hệ toạ độ cũng giống với hệ toạ độ mà cảm biến gia tốc sử dụng.
Lưu ý: Khi thiết bị ở trạng thái nghỉ, đầu ra của cảm biến trọng lực phải giống với đầu ra của gia tốc kế.
Sử dụng gia tốc kế tuyến tính
Cảm biến gia tốc tuyến tính cung cấp cho bạn một vectơ 3 chiều biểu thị gia tốc dọc theo từng trục của thiết bị, không bao gồm trọng lực. Bạn có thể dùng giá trị này để thực hiện tính năng phát hiện cử chỉ. Giá trị này cũng có thể đóng vai trò là dữ liệu đầu vào cho hệ thống dẫn đường quán tính, sử dụng phương pháp ước tính vị trí. Đoạn mã sau đây cho biết cách lấy một thực thể của cảm biến gia tốc tuyến tính mặc định:
Kotlin
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION)
Java
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
Về mặt khái niệm, cảm biến này cung cấp cho bạn dữ liệu gia tốc theo mối quan hệ sau:
linear acceleration = acceleration - acceleration due to gravity
Bạn thường dùng cảm biến này khi muốn thu thập dữ liệu gia tốc mà không bị ảnh hưởng bởi trọng lực. Ví dụ: bạn có thể dùng cảm biến này để xem tốc độ của ô tô. Cảm biến gia tốc tuyến tính luôn có độ lệch mà bạn cần loại bỏ. Cách đơn giản nhất để thực hiện việc này là tích hợp một bước hiệu chuẩn vào ứng dụng của bạn. Trong quá trình hiệu chuẩn, bạn có thể yêu cầu người dùng đặt thiết bị lên bàn, sau đó đọc các độ lệch cho cả 3 trục. Sau đó, bạn có thể trừ độ lệch đó khỏi các chỉ số trực tiếp của cảm biến gia tốc để nhận được gia tốc tuyến tính thực tế.
Hệ toạ độ của cảm biến giống với hệ toạ độ mà cảm biến gia tốc sử dụng, cũng như các đơn vị đo (m/s2).
Sử dụng cảm biến vectơ xoay
Véc tơ xoay biểu thị hướng của thiết bị dưới dạng tổ hợp của một góc và một trục, trong đó thiết bị đã xoay qua một góc θ quanh một trục (x, y hoặc z). Đoạn mã sau đây cho biết cách lấy một phiên bản của cảm biến vectơ xoay mặc định:
Kotlin
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
Java
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
Ba phần tử của vectơ xoay được biểu thị như sau:

Trong đó, độ lớn của vectơ xoay bằng sin(θ/2) và hướng của vectơ xoay bằng hướng của trục xoay.

Hình 1. Hệ toạ độ do cảm biến vectơ xoay sử dụng.
Ba phần tử của vectơ xoay bằng với 3 thành phần cuối cùng của một đơn vị quaternion (cos(θ/2), x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)). Các phần tử của vectơ xoay không có đơn vị. Các trục x, y và z được xác định theo cách tương tự như cảm biến gia tốc. Hệ toạ độ tham chiếu được xác định là cơ sở trực giao trực tiếp (xem hình 1). Hệ toạ độ này có các đặc điểm sau:
- X được xác định là tích vectơ Y x Z. Đường này tiếp tuyến với mặt đất tại vị trí hiện tại của thiết bị và chỉ hướng Đông.
- Y tiếp tuyến với mặt đất tại vị trí hiện tại của thiết bị và hướng về Cực Bắc địa từ.
- Z hướng lên trời và vuông góc với mặt phẳng tiếp đất.
Để xem ứng dụng mẫu minh hoạ cách sử dụng cảm biến vectơ xoay, hãy xem RotationVectorDemo.java.
Sử dụng cảm biến chuyển động đáng kể
Cảm biến chuyển động đáng kể sẽ kích hoạt một sự kiện mỗi khi phát hiện thấy chuyển động đáng kể, sau đó tự vô hiệu hoá. Chuyển động đáng kể là chuyển động có thể dẫn đến thay đổi vị trí của người dùng; ví dụ: đi bộ, đi xe đạp hoặc ngồi trong ô tô đang di chuyển. Đoạn mã sau đây cho biết cách lấy một thực thể của cảm biến chuyển động đáng kể mặc định và cách đăng ký một trình nghe sự kiện:
Kotlin
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val mSensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION) val triggerEventListener = object : TriggerEventListener() { override fun onTrigger(event: TriggerEvent?) { // Do work } } mSensor?.also { sensor -> sensorManager.requestTriggerSensor(triggerEventListener, sensor) }
Java
private SensorManager sensorManager; private Sensor sensor; private TriggerEventListener triggerEventListener; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION); triggerEventListener = new TriggerEventListener() { @Override public void onTrigger(TriggerEvent event) { // Do work } }; sensorManager.requestTriggerSensor(triggerEventListener, mSensor);
Để biết thêm thông tin, hãy xem TriggerEventListener
.
Sử dụng cảm biến đếm bước
Cảm biến bộ đếm bước cung cấp số bước mà người dùng đã thực hiện kể từ lần khởi động lại gần đây nhất trong khi cảm biến được kích hoạt. Bộ đếm bước có độ trễ cao hơn (tối đa 10 giây) nhưng độ chính xác cao hơn so với cảm biến phát hiện bước.
Lưu ý: Bạn phải khai báo quyền ACTIVITY_RECOGNITION
để ứng dụng của bạn có thể sử dụng cảm biến này trên các thiết bị chạy Android 10 (API cấp 29) trở lên.
Đoạn mã sau đây cho biết cách lấy một phiên bản của cảm biến bộ đếm bước mặc định:
Kotlin
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
Java
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
Để duy trì pin trên các thiết bị chạy ứng dụng của bạn, bạn nên sử dụng lớp JobScheduler
để truy xuất giá trị hiện tại từ cảm biến bộ đếm bước trong một khoảng thời gian cụ thể. Mặc dù các loại ứng dụng khác nhau yêu cầu các khoảng thời gian đọc cảm biến khác nhau, nhưng bạn nên đặt khoảng thời gian này càng dài càng tốt, trừ phi ứng dụng của bạn yêu cầu dữ liệu theo thời gian thực từ cảm biến.
Sử dụng cảm biến trình phát hiện bước chân
Cảm biến phát hiện bước sẽ kích hoạt một sự kiện mỗi khi người dùng thực hiện một bước. Độ trễ dự kiến là dưới 2 giây.
Lưu ý: Bạn phải khai báo quyền ACTIVITY_RECOGNITION
để ứng dụng của bạn có thể sử dụng cảm biến này trên các thiết bị chạy Android 10 (API cấp 29) trở lên.
Đoạn mã sau đây cho biết cách lấy một phiên bản của cảm biến bộ phát hiện bước mặc định:
Kotlin
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR)
Java
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);
Làm việc với dữ liệu thô
Các cảm biến sau đây cung cấp cho ứng dụng của bạn dữ liệu thô về lực tuyến tính và lực xoay đang tác dụng lên thiết bị. Để sử dụng hiệu quả các giá trị từ những cảm biến này, bạn cần lọc ra các yếu tố từ môi trường, chẳng hạn như trọng lực. Bạn cũng có thể cần áp dụng một thuật toán làm mượt cho xu hướng của các giá trị để giảm nhiễu.
Sử dụng gia tốc kế
Cảm biến gia tốc đo gia tốc tác dụng lên thiết bị, bao gồm cả lực hấp dẫn. Đoạn mã sau đây cho biết cách lấy một thực thể của cảm biến gia tốc mặc định:
Kotlin
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
Java
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Lưu ý: Nếu ứng dụng của bạn nhắm đến Android 12 (API cấp 31) trở lên, thì cảm biến này sẽ bị giới hạn tốc độ.
Về mặt khái niệm, cảm biến gia tốc xác định gia tốc được áp dụng cho một thiết bị (Ad) bằng cách đo lực được áp dụng cho chính cảm biến (Fs) theo mối quan hệ sau:

Tuy nhiên, lực hấp dẫn luôn ảnh hưởng đến gia tốc đo được theo mối quan hệ sau:

Vì lý do này, khi thiết bị đặt trên bàn (và không tăng tốc), gia tốc kế sẽ đọc một độ lớn là g = 9,81 m/s2. Tương tự, khi thiết bị rơi tự do và do đó tăng tốc nhanh chóng về phía mặt đất ở tốc độ 9,81 m/s2, gia tốc kế sẽ đọc được độ lớn là g = 0 m/s2. Do đó, để đo gia tốc thực của thiết bị, bạn phải loại bỏ ảnh hưởng của lực hấp dẫn khỏi dữ liệu gia tốc kế. Bạn có thể đạt được điều này bằng cách áp dụng bộ lọc thông cao. Ngược lại, bạn có thể dùng bộ lọc thông thấp để cô lập lực hấp dẫn. Ví dụ sau đây cho thấy cách bạn có thể thực hiện việc này:
Kotlin
override fun onSensorChanged(event: SensorEvent) { // In this example, alpha is calculated as t / (t + dT), // where t is the low-pass filter's time-constant and // dT is the event delivery rate. val alpha: Float = 0.8f // Isolate the force of gravity with the low-pass filter. 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] // Remove the gravity contribution with the high-pass filter. linear_acceleration[0] = event.values[0] - gravity[0] linear_acceleration[1] = event.values[1] - gravity[1] linear_acceleration[2] = event.values[2] - gravity[2] }
Java
public void onSensorChanged(SensorEvent event){ // In this example, alpha is calculated as t / (t + dT), // where t is the low-pass filter's time-constant and // dT is the event delivery rate. final float alpha = 0.8; // Isolate the force of gravity with the low-pass filter. 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]; // Remove the gravity contribution with the high-pass filter. linear_acceleration[0] = event.values[0] - gravity[0]; linear_acceleration[1] = event.values[1] - gravity[1]; linear_acceleration[2] = event.values[2] - gravity[2]; }
Lưu ý: Bạn có thể sử dụng nhiều kỹ thuật khác nhau để lọc dữ liệu cảm biến. Đoạn mã mẫu ở trên sử dụng một hằng số bộ lọc đơn giản (alpha) để tạo bộ lọc thông thấp. Hằng số bộ lọc này được lấy từ hằng số thời gian (t), là một giá trị biểu thị sơ bộ độ trễ mà bộ lọc thêm vào các sự kiện cảm biến và tốc độ phân phối sự kiện của cảm biến (dt). Mã mẫu này sử dụng giá trị alpha là 0,8 cho mục đích minh hoạ. Nếu sử dụng phương pháp lọc này, bạn có thể cần chọn một giá trị alpha khác.
Gia tốc kế sử dụng hệ toạ độ cảm biến tiêu chuẩn. Trên thực tế, điều này có nghĩa là các điều kiện sau đây sẽ áp dụng khi một thiết bị nằm phẳng trên bàn theo hướng tự nhiên:
- Nếu bạn đẩy thiết bị ở bên trái (để thiết bị di chuyển sang phải), thì giá trị gia tốc x sẽ dương.
- Nếu bạn đẩy thiết bị xuống dưới (để thiết bị di chuyển ra xa bạn), giá trị gia tốc y sẽ dương.
- Nếu bạn đẩy thiết bị lên trời với gia tốc A m/s2, giá trị gia tốc z sẽ bằng A + 9,81, tương ứng với gia tốc của thiết bị (+A m/s2) trừ đi lực hấp dẫn (-9,81 m/s2).
- Thiết bị ở trạng thái tĩnh sẽ có giá trị gia tốc là +9,81, tương ứng với gia tốc của thiết bị (0 m/s2 trừ đi lực hấp dẫn là -9,81 m/s2).
Nhìn chung, gia tốc kế là một cảm biến phù hợp để sử dụng nếu bạn đang theo dõi chuyển động của thiết bị. Hầu hết mọi điện thoại và máy tính bảng chạy Android đều có gia tốc kế và gia tốc kế này tiêu thụ ít hơn khoảng 10 lần so với các cảm biến chuyển động khác. Một nhược điểm là bạn có thể phải triển khai bộ lọc thông thấp và bộ lọc thông cao để loại bỏ lực hấp dẫn và giảm tiếng ồn.
Sử dụng con quay hồi chuyển
Con quay hồi chuyển đo tốc độ xoay theo đơn vị rad/giây quanh trục x, y và z của thiết bị. Đoạn mã sau đây hướng dẫn bạn cách lấy một thực thể của con quay hồi chuyển mặc định:
Kotlin
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
Java
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
Lưu ý: Nếu ứng dụng của bạn nhắm đến Android 12 (API cấp 31) trở lên, thì cảm biến này sẽ bị giới hạn tốc độ.
Hệ toạ độ của cảm biến này giống với hệ toạ độ được dùng cho cảm biến gia tốc. Góc xoay dương theo chiều ngược chiều kim đồng hồ; tức là một người quan sát nhìn từ một vị trí dương nào đó trên trục x, y hoặc z tại một thiết bị được đặt ở gốc sẽ báo cáo góc xoay dương nếu thiết bị có vẻ đang xoay ngược chiều kim đồng hồ. Đây là định nghĩa toán học tiêu chuẩn về phép xoay dương và không giống với định nghĩa về chuyển động xoay tròn mà cảm biến hướng sử dụng.
Thông thường, đầu ra của con quay hồi chuyển được tích hợp theo thời gian để tính toán một phép xoay mô tả sự thay đổi của các góc theo bước thời gian. Ví dụ:
Kotlin
// Create a constant to convert nanoseconds to seconds. private val NS2S = 1.0f / 1000000000.0f private val deltaRotationVector = FloatArray(4) { 0f } private var timestamp: Float = 0f override fun onSensorChanged(event: SensorEvent?) { // This timestep's delta rotation to be multiplied by the current rotation // after computing it from the gyro sample data. if (timestamp != 0f && event != null) { val dT = (event.timestamp - timestamp) * NS2S // Axis of the rotation sample, not normalized yet. var axisX: Float = event.values[0] var axisY: Float = event.values[1] var axisZ: Float = event.values[2] // Calculate the angular speed of the sample val omegaMagnitude: Float = sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ) // Normalize the rotation vector if it's big enough to get the axis // (that is, EPSILON should represent your maximum allowable margin of error) if (omegaMagnitude > EPSILON) { axisX /= omegaMagnitude axisY /= omegaMagnitude axisZ /= omegaMagnitude } // Integrate around this axis with the angular speed by the timestep // in order to get a delta rotation from this sample over the timestep // We will convert this axis-angle representation of the delta rotation // into a quaternion before turning it into the rotation matrix. val thetaOverTwo: Float = omegaMagnitude * dT / 2.0f val sinThetaOverTwo: Float = sin(thetaOverTwo) val cosThetaOverTwo: Float = cos(thetaOverTwo) deltaRotationVector[0] = sinThetaOverTwo * axisX deltaRotationVector[1] = sinThetaOverTwo * axisY deltaRotationVector[2] = sinThetaOverTwo * axisZ deltaRotationVector[3] = cosThetaOverTwo } timestamp = event?.timestamp?.toFloat() ?: 0f val deltaRotationMatrix = FloatArray(9) { 0f } SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector); // User code should concatenate the delta rotation we computed with the current rotation // in order to get the updated rotation. // rotationCurrent = rotationCurrent * deltaRotationMatrix; }
Java
// Create a constant to convert nanoseconds to seconds. private static final float NS2S = 1.0f / 1000000000.0f; private final float[] deltaRotationVector = new float[4](); private float timestamp; public void onSensorChanged(SensorEvent event) { // This timestep's delta rotation to be multiplied by the current rotation // after computing it from the gyro sample data. if (timestamp != 0) { final float dT = (event.timestamp - timestamp) * NS2S; // Axis of the rotation sample, not normalized yet. float axisX = event.values[0]; float axisY = event.values[1]; float axisZ = event.values[2]; // Calculate the angular speed of the sample float omegaMagnitude = sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ); // Normalize the rotation vector if it's big enough to get the axis // (that is, EPSILON should represent your maximum allowable margin of error) if (omegaMagnitude > EPSILON) { axisX /= omegaMagnitude; axisY /= omegaMagnitude; axisZ /= omegaMagnitude; } // Integrate around this axis with the angular speed by the timestep // in order to get a delta rotation from this sample over the timestep // We will convert this axis-angle representation of the delta rotation // into a quaternion before turning it into the rotation matrix. float thetaOverTwo = omegaMagnitude * dT / 2.0f; float sinThetaOverTwo = sin(thetaOverTwo); float cosThetaOverTwo = cos(thetaOverTwo); deltaRotationVector[0] = sinThetaOverTwo * axisX; deltaRotationVector[1] = sinThetaOverTwo * axisY; deltaRotationVector[2] = sinThetaOverTwo * axisZ; deltaRotationVector[3] = cosThetaOverTwo; } timestamp = event.timestamp; float[] deltaRotationMatrix = new float[9]; SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector); // User code should concatenate the delta rotation we computed with the current rotation // in order to get the updated rotation. // rotationCurrent = rotationCurrent * deltaRotationMatrix; }
Con quay hồi chuyển tiêu chuẩn cung cấp dữ liệu thô về độ xoay mà không có bất kỳ hoạt động lọc hoặc điều chỉnh nào đối với nhiễu và độ lệch (thiên vị). Trên thực tế, độ nhiễu và độ trôi của con quay hồi chuyển sẽ gây ra những lỗi cần được bù đắp. Bạn thường xác định độ lệch (thiên vị) và nhiễu bằng cách theo dõi các cảm biến khác, chẳng hạn như cảm biến trọng lực hoặc gia tốc kế.
Sử dụng con quay hồi chuyển chưa được hiệu chỉnh
Con quay hồi chuyển chưa được hiệu chỉnh tương tự như con quay hồi chuyển, ngoại trừ việc không có chế độ bù độ lệch con quay hồi chuyển được áp dụng cho tốc độ xoay. Quy trình hiệu chuẩn tại nhà máy và bù nhiệt độ vẫn được áp dụng cho tốc độ xoay. Con quay hồi chuyển chưa được hiệu chỉnh rất hữu ích cho việc xử lý hậu kỳ và kết hợp dữ liệu hướng. Nhìn chung, gyroscope_event.values[0]
sẽ gần với uncalibrated_gyroscope_event.values[0] - uncalibrated_gyroscope_event.values[3]
.
Tức là
calibrated_x ~= uncalibrated_x - bias_estimate_x
Lưu ý: Cảm biến chưa được hiệu chỉnh cung cấp nhiều kết quả thô hơn và có thể có một số sai lệch, nhưng các phép đo của cảm biến này có ít bước nhảy hơn do các điểm điều chỉnh được áp dụng thông qua quy trình hiệu chuẩn. Một số ứng dụng có thể ưu tiên những kết quả chưa được hiệu chỉnh này vì chúng mượt mà và đáng tin cậy hơn. Ví dụ: nếu một ứng dụng đang cố gắng thực hiện tính năng kết hợp cảm biến của riêng mình, thì việc đưa ra các chế độ hiệu chuẩn có thể làm sai lệch kết quả.
Ngoài tốc độ xoay, con quay hồi chuyển chưa được hiệu chỉnh cũng cung cấp độ lệch ước tính xung quanh mỗi trục. Đoạn mã sau đây cho biết cách lấy một thực thể của con quay hồi chuyển chưa hiệu chỉnh mặc định:
Kotlin
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED)
Java
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED);
Mã mẫu khác
Mẫu BatchStepSensor minh hoạ thêm về cách sử dụng các API được trình bày trên trang này.