Cảm biến chuyển động

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 một thiết bị.

Cảm biến các cấu trúc có thể khác nhau tuỳ theo loại cảm biến:

  • Trọng lực, gia tốc tuyến tính, vectơ quay, chuyển động có ý nghĩa, bước bộ đếm và cảm biến của trình phát hiện bước là dựa trên phần cứng hoặc dựa trên 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 thiết bị chạy Android đều có gia tốc kế và nhiều thiết bị hiện có con quay hồi chuyển. Các cảm biến dựa trên phần mềm ngày càng trở nên phổ biến 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 tín hiệu 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 trong việc theo dõi chuyển động của thiết bị, chẳng hạn như độ nghiêng, độ rung, xoay hoặc đung đưa. Chuyển động 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 điều khiển một ô tô trong trò chơi hoặc người dùng đang điều khiển bóng trong trò chơi), nhưng hình ảnh đó cũng có thể là sự phản ánh của môi trường thực tế mà bạn đặt thiết bị (ví dụ: di chuyển cùng bạn khi bạn lái xe ô tô). Trong trường hợp đầu tiên, bạn đang theo dõi chuyển động tương ứng với hệ quy chiếu của thiết bị hoặc hệ quy chiếu của ứng dụng của bạn; trong trường hợp thứ hai, bạn theo dõi chuyển động liên quan đến hệ quy chiếu của thế giới. Cảm biến chuyển động thường không được dùng để giám sát thông tin vị trí của thiết bị nhưng có thể sử dụng chúng với các cảm biến khác, chẳng hạn như cảm biến trường địa từ để xác định vị trí của thiết bị so với hệ quy chiếu của thế giới (xem Cảm biến vị trí để biết thêm ).

Tất cả cảm biến chuyển động đều trả về các mảng giá trị cảm biến đa chiều cho mỗi SensorEvent. Ví dụ: trong một sự kiện cảm biến, gia tốc kế trả về dữ liệu lực gia tốc cho ba trục toạ độ và con quay hồi chuyển trả về tốc độ quay dữ liệu về 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 SensorEvent khác tham số. Bảng 1 tóm tắt các cảm biến chuyển động có sẵn trên nền tảng Android.

Bảng 1. 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ủa cảm biến Mô tả Đơn vị đo
TYPE_ACCELEROMETER SensorEvent.values[0] Lực tăng tốc dọc theo trục x (bao gồm cả trọng lực). m/giây2
SensorEvent.values[1] Lực tăng tốc dọc theo trục y (bao gồm cả trọng lực).
SensorEvent.values[2] Lực tăng 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ù chênh lệch. m/giây2
SensorEvent.values[1] Gia tốc đo được dọc theo trục Y mà không có bù chênh lệch.
SensorEvent.values[2] Gia tốc đo được dọc theo trục Z mà không có bù chênh lệch.
SensorEvent.values[3] Gia tốc đo được dọc theo trục X với bù sai lệch ước tính.
SensorEvent.values[4] Gia tốc đo được dọc theo trục Y với bù sai lệch ước tính.
SensorEvent.values[5] Gia tốc đo được dọc theo trục Z với bù sai lệch ước tính.
TYPE_GRAVITY SensorEvent.values[0] Trọng lực dọc theo trục x. m/giây2
SensorEvent.values[1] Trọng lực dọc theo trục y.
SensorEvent.values[2] Trọng lực dọc theo trục z.
TYPE_GYROSCOPE SensorEvent.values[0] Tốc độ quay xung quanh trục x. Rad/giây
SensorEvent.values[1] Tốc độ quay xung quanh trục y.
SensorEvent.values[2] Tốc độ quay xung quanh trục z.
TYPE_GYROSCOPE_UNCALIBRATED SensorEvent.values[0] Tốc độ quay (không bù độ trôi) xung quanh trục x. Rad/giây
SensorEvent.values[1] Tốc độ quay (không bù độ trôi) xung quanh trục y.
SensorEvent.values[2] Tốc độ quay (không bù độ trôi) xung quanh trục z.
SensorEvent.values[3] Độ trôi ước tính xung quanh trục x.
SensorEvent.values[4] Độ trôi ước tính xung quanh trục y.
SensorEvent.values[5] Độ trôi ước tính xung quanh trục z.
TYPE_LINEAR_ACCELERATION SensorEvent.values[0] Lực tăng tốc dọc theo trục x (không bao gồm trọng lực). m/giây2
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 tăng 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(9/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 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ơ quay và cảm biến trọng lực là những cảm biến được sử dụng thường xuyên nhất để chuyển động phát hiện và giám sát. Cảm biến vectơ quay đặc biệt linh hoạt và có thể được dùng để một loạt các công việc liên quan đến chuyển động (ví dụ: phát hiện cử chỉ, theo dõi sự thay đổi góc) theo dõi các thay đổi về hướng tương đối. Ví dụ: cảm biến vectơ quay là lý tưởng nếu bạn đang phát triển 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 máy ảnh. Trong hầu hết mọi 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 gia tốc kế và cảm biến trường địa từ hoặc cảm biến hướng.

Cảm biến của 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: trọng lực cảm biến, cảm biến gia tốc tuyến tính và cảm biến vectơ quay. 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ị (cùng với các cảm biến khác) để cải thiện độ ổn định và hiệu suất. Nếu muốn dùng thử các cảm biến này, bạn có thể xác định chúng bằng cách sử dụ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). Nhận dạng các cảm biến này theo nhà cung cấp và cần có số phiên bản vì hệ thống Android coi 3 cảm biến này là cảm biến phụ các cảm biến. Ví dụ: nếu nhà sản xuất thiết bị cung cấp cảm biến trọng lực riêng, thì AOSP (Dự án nguồn mở Android) cảm biến trọng lực xuất hiện dưới dạng cảm biến trọng lực phụ. Cả ba cảm biến này 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, những cảm biến này sẽ không hiển thị và không có sẵn để sử dụng.

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 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. Mã sau đây hướng dẫn bạn cách lấy một thực thể 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);

Đơn vị này giống với đơn vị được sử dụng bởi gia tốc cảm biến (m/s2) và hệ toạ độ cũng giống như hệ thống được sử dụng bởi cảm biến gia tốc.

Lưu ý: Khi một 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 kích thước 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 vectơ ba 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ể sử dụng giá trị này để thực hiện 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 định vị quán tính, sử dụng phương thức xác định vị trí chết. Đoạn mã sau đây cho thấy bạn cách lấy 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 lý thuyết, cảm biến này cung cấp cho bạn dữ liệu gia tốc theo các mối quan hệ:

linear acceleration = acceleration - acceleration due to gravity

Bạn thường sử dụng cảm biến này khi muốn lấy dữ liệu gia tốc mà không ảnh hưởng đến trọng lực. Ví dụ: bạn có thể sử dụng cảm biến này để xem tốc độ của ô tô. Tuyến tính cảm biến gia tốc luôn có độ lệch mà bạn cần loại bỏ. Cách đơn giản nhất để làm việc này là để tạo một bước hiệu chỉnh cho ứng dụng của bạn. Trong khi hiệu chỉnh, bạn có thể yêu cầu người dùng đặt thiết bị trên bảng, sau đó đọc độ lệch của cả ba trục. Sau đó, bạn có thể trừ đi bù với giá trị đo trực tiếp của cảm biến gia tốc để có được giá trị tuyến tính thực tế tăng tốc.

Tọa độ của cảm biến system giống như hệ thống mà cảm biến gia tốc sử dụng, giống như các đơn vị đo (m/giây2).

Sử dụng cảm biến vectơ xoay

Vectơ xoay biểu thị hướng của thiết bị dưới dạng tổng hợp của một góc và trục, trong đó thiết bị đã quay qua một góc Trái xung quanh trục (x, y hoặc z). Nội dung sau đây mã cho bạn biết cách tải một thực thể 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 diễn như sau:

x*sin(;2), y*sin(;2), z*sin(;2)

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

Hình 1. Hệ toạ độ mà cảm biến vectơ xoay sử dụng.

Ba phần tử của vectơ xoay bằng ba thành phần cuối của một đơn vị quaternion (cos(góc/2 ), x*sin(tại/2 ), y*sin(tại/2 ), z*sin(tại/2 ). Các phần tử của vectơ xoay là vô tận. 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. Tham chiếu hệ toạ độ được định nghĩa là cơ sở chỉnh hình trực tiếp (xem hình 1). Hệ toạ độ này có các đặc điểm sau:

  • X được định nghĩa là tích vectơ Y x Z. Đây là tiếp tuyến của mặt đất tại vị trí hiện tại của thiết bị và trỏ vào khoảng Đông.
  • Y là tiếp tuyến với mặt đất tại vị trí hiện tại của thiết bị và chỉ về phía địa từ Bắc Cực.
  • Z trỏ tới bầu trời và vuông góc với mặt phẳng mặt đất.

Để xem ứng dụng mẫu trình bày 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 quan trọng

Cảm biến chuyển động quan trọng sẽ kích hoạt một sự kiện mỗi khi phát hiện thấy chuyển động quan trọng và thì thiết bị sẽ tự tắt. Một chuyển động đáng kể là một chuyển động có thể dẫn đến một thay đổi trong vị trí của người dùng; ví dụ như đi bộ, đi xe đạp hoặc ngồi trong ô tô chuyển động. Mã sau đây cho bạn biết cách lấy phiên bản của cảm biến chuyển động quan trọng mặc định và cách đăng ký một sự kiện trình nghe:

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 bộ đếm số bước

Cảm biến bộ đếm bước cho biết số bước mà người dùng đã đi 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 nhiều hơn chính xác hơn cảm biến phát hiện bước.

Lưu ý: Bạn phải khai báo ACTIVITY_RECOGNITION để ứng dụng của bạn có thể dùng cảm biến này trên những thiết bị đang chạy Android 10 (API cấp 29) trở lên.

Đoạn mã sau đây cho bạn biết cách lấy một thực thể của bước mặc định cảm biến bộ đếm:

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ì thời lượng 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 tại một khoảng thời gian cụ thể. Mặc dù các loại ứng dụng khác nhau đòi hỏi khoảng thời gian đọc cảm biến khác nhau, bạn nên đặt khoảng thời gian này như lâu nhất có thể trừ phi ứng dụng 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 phát hiện số bước

Cảm biến trình phát hiện số bước sẽ kích hoạt một sự kiện mỗi khi người dùng đi một bước. Độ trễ là dự kiến dưới 2 giây.

Lưu ý: Bạn phải khai báo ACTIVITY_RECOGNITION để ứng dụng của bạn có thể dùng cảm biến này trên những thiết bị đang chạy Android 10 (API cấp 29) trở lên.

Đoạn mã sau đây cho bạn biết cách lấy một thực thể của bước mặc định cảm biến của máy phát hiện:

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ề tuyến tính và lực quay tác dụng lên thiết bị. Để sử dụng các giá trị từ những cảm biến này một cách hiệu quả, bạn cần lọc bỏ các yếu tố khỏi môi trường, chẳng hạn như trọng lực. Có thể bạn cũng cần áp dụng thuật toán làm mượt cho xu hướng để giảm nhiễu.

Sử dụng gia tốc kế

Cảm biến gia tốc đo gia tốc của thiết bị, bao gồm cả lực trọng lực. Đoạn mã sau đây cho bạn 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) hoặc cao hơn, cảm biến này bị giới hạn tỷ lệ.

Về mặt lý thuyết, cảm biến gia tốc xác định gia tốc được áp dụng một thiết bị (Ad) bằng cách đo các lực tác dụng lên cảm biến (Fs) bằng mối quan hệ sau:

A_D=-(1/khối lượng)∑F_S

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:

A_D=-g-(1/khối lượng)∑F_S

Vì lý do này, khi thiết bị được đặt trên bàn (và không tăng tốc), gia tốc kế đọc cường độ là g = 9,81 m/s2. Tương tự, khi thiết bị ở rơi tự do và do đó nhanh chóng chuyển động về phía mặt đất với vận tốc 9, 81 m/s2 gia tốc kế đọc cường độ g = 0 m/s2. Do đó, để đo lường gia tốc thực của thiết bị, phần đóng góp của trọng lực phải được loại bỏ khỏi dữ liệu gia tốc kế. Điều này có thể đạt được bằng cách áp dụng bộ lọc thông cao. Ngược lại, đường thấp có thể dùng bộ lọc để tách trọng lực. Ví dụ sau đây cho thấy cách bạn có thể sau:

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 để lọc dữ liệu cảm biến. Mã mẫu ở trên sử dụng hằng số bộ lọc đơn giản (alpha) để tạo bộ lọc thông thấp. Bộ lọc này hằng số này được tính từ hằng số thời gian (t), là hằng số biểu diễn gần đúng độ trễ bộ lọc sẽ thêm 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 sử dụng giá trị alpha là 0,8 cho mục đích minh hoạ. Nếu 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 toạ độ cảm biến tiêu chuẩn hệ thống. Trong thực tế, điều này có nghĩa là các điều kiện sau áp dụng khi thiết bị được đặt phẳng trên bàn theo hướng tự nhiên:

  • Nếu bạn đẩy thiết bị sang phía bên trái (để thiết bị di chuyển sang bên phải), giá trị gia tốc x đều tích cực.
  • 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 là tích cực.
  • Nếu bạn đẩy thiết bị về phía bầu trời với gia tốc A m/s2 thì giá trị tăng tốc của z bằng A + 9,81, tương ứng với gia tốc của thiết bị (+A m/s2) trừ đi trọng lực (-9,81 m/s2).
  • Thiết bị đứng yên sẽ có giá trị gia tốc +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 thích 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 di động và máy tính bảng chạy Android đều có gia tốc kế và nó sử dụng khoảng 10 lần tiết kiệm năng lượng hơ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 các bộ lọc thông thấp và thông cao để loại bỏ lực hấp dẫn và giảm nhiễu.

Sử dụng con quay hồi chuyển

Con quay hồi chuyển đo tốc độ quay theo Rad/s xung quanh x, y, của thiết bị và trục z. Đoạn mã sau đây cho bạn biết cách tải 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) hoặc cao hơn, cảm biến này bị giới hạn tỷ lệ.

Hệ thống toạ độ của cảm biến giống như loại dùng cho cảm biến gia tốc. Xoay có giá trị dương trong ngược chiều kim đồng hồ; tức là một người quan sát đang nhìn từ vị trí dương nào đó trên trục x, y hoặc z tại một thiết bị được định vị trên điểm gốc sẽ báo cáo xoay thuận nếu thiết bị có vẻ như đang xoay ngược chiều kim đồng hồ. Đây là định nghĩa toán học chuẩn của phép xoay dương và không giống với định nghĩa cho 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 vòng quay 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 chuẩn cung cấp dữ liệu quay thô mà không có bộ lọc hay chỉnh sửa nhiễu và độ trôi (thiên vị). Trong thực tế, tiếng ồn và độ trôi của con quay hồi chuyển sẽ tạo ra các lỗi cần phải được trả thù lao. Bạn thường xác định độ lệch (độ lệch) và độ nhiễu bằng cách theo dõi các cảm biến khác, chẳng hạn như làm 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 áp dụng phần bù con quay hồi chuyển cho tốc độ quay. Hiệu chuẩn tại nhà máy và bù nhiệt độ vẫn được áp dụng cho tốc độ xoay. Chưa được hiệu chỉnh gyroscope rất hữu ích cho việc xử lý hậu kỳ và hợp nhất 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 kết quả thô hơn và có thể bao gồm một số độ chệch, nhưng các phép đo của chúng có ít bước nhảy hơn từ các hiệu chỉnh được áp dụng qua lấy mẫu. Một số ứng dụng có thể muốn các kết quả chưa được hiệu chỉnh này mượt mà hơn và hiệu quả hơn đáng tin cậy. Ví dụ: nếu một ứng dụng đang cố gắng tiến hành hợp nhất cảm biến của riêng mình, thực sự có thể làm sai lệch kết quả.

Ngoài tốc độ quay, con quay hồi chuyển không được hiệu chỉnh còn cung cấp trôi quanh từng trục. Mã sau đây cho bạn biết cách tải một phiên bản của giá trị mặc định con quay hồi chuyển không được hiệu chỉ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

Chiến lược phát hành đĩa đơn Mẫu BatchStepSensor minh hoạ thêm việc sử dụng các API được đề cập trên trang này.

Bạn cũng nên đọc