แพลตฟอร์ม Android มีเซ็นเซอร์หลายตัวที่ช่วยให้คุณตรวจสอบการเคลื่อนไหว ของอุปกรณ์ได้
สถาปัตยกรรมที่เป็นไปได้ของเซ็นเซอร์จะแตกต่างกันไปตามประเภทเซ็นเซอร์ ดังนี้
- เซ็นเซอร์แรงโน้มถ่วง ความเร่งเชิงเส้น เวกเตอร์การหมุน การเคลื่อนไหวที่สำคัญ ตัวนับก้าว และตัวตรวจจับก้าวเป็นเซ็นเซอร์ที่อิงตามฮาร์ดแวร์หรือซอฟต์แวร์
- เซ็นเซอร์ตัวตรวจวัดความเร่งและเครื่องวัดการหมุนจะเป็นแบบฮาร์ดแวร์เสมอ
อุปกรณ์ที่ใช้ระบบปฏิบัติการ Android ส่วนใหญ่มีเครื่องวัดความเร่ง และปัจจุบันหลายรุ่นมี ไจโรสโคปด้วย ความพร้อมใช้งานของเซ็นเซอร์แบบซอฟต์แวร์จะมีความ ผันแปรมากกว่า เนื่องจากมักต้องอาศัยเซ็นเซอร์ฮาร์ดแวร์อย่างน้อย 1 ตัวเพื่อดึงข้อมูล เซ็นเซอร์ที่ใช้ซอฟต์แวร์เหล่านี้สามารถดึงข้อมูลจากตัวตรวจวัดความเร่งและเครื่องวัดสนามแม่เหล็ก หรือจากเครื่องวัดการหมุน ทั้งนี้ขึ้นอยู่กับอุปกรณ์
เซ็นเซอร์ตรวจจับการเคลื่อนไหวมีประโยชน์ในการตรวจสอบการเคลื่อนไหวของอุปกรณ์ เช่น การเอียง การเขย่า การหมุน หรือ การแกว่ง โดยปกติแล้ว การเคลื่อนไหวจะเป็นผลจากการป้อนข้อมูลโดยตรงของผู้ใช้ (เช่น ผู้ใช้บังคับรถในเกมหรือผู้ใช้ควบคุมลูกบอลในเกม) แต่ก็อาจเป็นผลจากสภาพแวดล้อมทางกายภาพที่อุปกรณ์อยู่ด้วย (เช่น เคลื่อนที่ไปกับคุณขณะขับรถ) ในกรณีแรก คุณกำลังตรวจสอบการเคลื่อนไหวที่สัมพันธ์กับกรอบอ้างอิงของอุปกรณ์ หรือกรอบอ้างอิงของแอปพลิเคชัน ส่วนในกรณีที่สอง คุณกำลังตรวจสอบการเคลื่อนไหวที่สัมพันธ์กับ กรอบอ้างอิงของโลก โดยปกติแล้วจะไม่ใช้เซ็นเซอร์ตรวจจับการเคลื่อนไหวเพียงอย่างเดียวเพื่อตรวจสอบตำแหน่งของอุปกรณ์ แต่สามารถใช้ร่วมกับเซ็นเซอร์อื่นๆ เช่น เซ็นเซอร์สนามแม่เหล็กโลก เพื่อกำหนดตำแหน่งของอุปกรณ์ที่สัมพันธ์กับกรอบอ้างอิงของโลก (ดูข้อมูลเพิ่มเติมได้ที่เซ็นเซอร์ตำแหน่ง)
เซ็นเซอร์ตรวจจับความเคลื่อนไหวทั้งหมดจะแสดงผลอาร์เรย์แบบหลายมิติของค่าเซ็นเซอร์สำหรับแต่ละ SensorEvent
ตัวอย่างเช่น ในระหว่างเหตุการณ์เซ็นเซอร์เดียว ตัวตรวจวัดความเร่งจะส่งคืนข้อมูลแรงเร่งสำหรับแกนพิกัดทั้ง 3 แกน และเครื่องวัดการหมุนจะส่งคืนข้อมูลอัตราการหมุนสำหรับแกนพิกัดทั้ง 3 แกน ระบบจะแสดงค่าข้อมูลเหล่านี้ในอาร์เรย์ float
(values
) พร้อมกับพารามิเตอร์ SensorEvent
อื่นๆ ตารางที่ 1 สรุปเซ็นเซอร์ตรวจจับความเคลื่อนไหวที่มีให้บริการในแพลตฟอร์ม Android
ตารางที่ 1 เซ็นเซอร์ตรวจจับความเคลื่อนไหวที่รองรับในแพลตฟอร์ม Android
เซ็นเซอร์ | ข้อมูลเหตุการณ์เซ็นเซอร์ | คำอธิบาย | หน่วยวัด |
---|---|---|---|
TYPE_ACCELEROMETER |
SensorEvent.values[0] |
แรงเร่งตามแกน x (รวมถึงแรงโน้มถ่วง) | ม./วินาที2 |
SensorEvent.values[1] |
แรงเร่งตามแกน y (รวมถึงแรงโน้มถ่วง) | ||
SensorEvent.values[2] |
แรงเร่งตามแกน z (รวมถึงแรงโน้มถ่วง) | ||
TYPE_ACCELEROMETER_UNCALIBRATED |
SensorEvent.values[0] |
การเร่งความเร็วที่วัดได้ตามแกน X โดยไม่มีการชดเชยความเอนเอียง | ม./วินาที2 |
SensorEvent.values[1] |
ความเร่งที่วัดตามแกน Y โดยไม่มีการชดเชยความเอนเอียง | ||
SensorEvent.values[2] |
ความเร่งที่วัดตามแกน Z โดยไม่มีการชดเชยความเอนเอียง | ||
SensorEvent.values[3] |
การเร่งความเร็วที่วัดได้ตามแกน X พร้อมการชดเชยอคติโดยประมาณ | ||
SensorEvent.values[4] |
การเร่งที่วัดได้ตามแกน Y พร้อมการชดเชยอคติโดยประมาณ | ||
SensorEvent.values[5] |
การเร่งความเร็วที่วัดได้ตามแกน Z พร้อมการชดเชยอคติโดยประมาณ | ||
TYPE_GRAVITY |
SensorEvent.values[0] |
แรงโน้มถ่วงตามแกน x | ม./วินาที2 |
SensorEvent.values[1] |
แรงโน้มถ่วงตามแกน Y | ||
SensorEvent.values[2] |
แรงโน้มถ่วงตามแกน z | ||
TYPE_GYROSCOPE |
SensorEvent.values[0] |
อัตราการหมุนรอบแกน x | เรเดียน/วินาที |
SensorEvent.values[1] |
อัตราการหมุนรอบแกน y | ||
SensorEvent.values[2] |
อัตราการหมุนรอบแกน z | ||
TYPE_GYROSCOPE_UNCALIBRATED |
SensorEvent.values[0] |
อัตราการหมุน (ไม่มีการชดเชยการดริฟต์) รอบแกน x | เรเดียน/วินาที |
SensorEvent.values[1] |
อัตราการหมุน (ไม่มีการชดเชยการดริฟต์) รอบแกน y | ||
SensorEvent.values[2] |
อัตราการหมุน (ไม่มีการชดเชยการดริฟต์) รอบแกน z | ||
SensorEvent.values[3] |
การเลื่อนโดยประมาณรอบแกน x | ||
SensorEvent.values[4] |
การเลื่อนโดยประมาณรอบแกน y | ||
SensorEvent.values[5] |
การดริฟต์โดยประมาณรอบแกน z | ||
TYPE_LINEAR_ACCELERATION |
SensorEvent.values[0] |
แรงเร่งตามแกน x (ไม่รวมแรงโน้มถ่วง) | ม./วินาที2 |
SensorEvent.values[1] |
แรงเร่งตามแกน y (ไม่รวมแรงโน้มถ่วง) | ||
SensorEvent.values[2] |
แรงเร่งตามแกน z (ไม่รวมแรงโน้มถ่วง) | ||
TYPE_ROTATION_VECTOR |
SensorEvent.values[0] |
คอมโพเนนต์เวกเตอร์การหมุนตามแกน x (x * sin(θ/2)) | ไม่มีหน่วย |
SensorEvent.values[1] |
คอมโพเนนต์เวกเตอร์การหมุนตามแกน y (y * sin(θ/2)) | ||
SensorEvent.values[2] |
คอมโพเนนต์เวกเตอร์การหมุนตามแกน z (z * sin(θ/2)) | ||
SensorEvent.values[3] |
องค์ประกอบสเกลาร์ของเวกเตอร์การหมุน ((cos(θ/2)).1 | ||
TYPE_SIGNIFICANT_MOTION |
ไม่มี | ไม่มีข้อมูล | ไม่มี |
TYPE_STEP_COUNTER |
SensorEvent.values[0] |
จำนวนก้าวที่ผู้ใช้เดินนับตั้งแต่รีบูตครั้งล่าสุดขณะที่เซ็นเซอร์ เปิดใช้งานอยู่ | จำนวนก้าว |
TYPE_STEP_DETECTOR |
ไม่มี | ไม่มีข้อมูล | ไม่มี |
1 คอมโพเนนต์สเกลาร์เป็นค่าที่ไม่บังคับ
เซ็นเซอร์เวกเตอร์การหมุนและเซ็นเซอร์แรงโน้มถ่วงเป็นเซ็นเซอร์ที่ใช้บ่อยที่สุดสำหรับการตรวจจับและการตรวจสอบการเคลื่อนไหว เซ็นเซอร์เวกเตอร์การหมุนมีความอเนกประสงค์เป็นพิเศษและใช้สำหรับงานที่เกี่ยวข้องกับการเคลื่อนไหวได้หลากหลาย เช่น การตรวจจับท่าทางสัมผัส การตรวจสอบการเปลี่ยนแปลงเชิงมุม และการตรวจสอบการเปลี่ยนแปลงการวางแนวสัมพัทธ์ ตัวอย่างเช่น เซ็นเซอร์เวกเตอร์การหมุนเหมาะอย่างยิ่งหากคุณ กำลังพัฒนาเกม แอปพลิเคชันความเป็นจริงเสริม เข็มทิศ 2 มิติหรือ 3 มิติ หรือแอปการทรงตัวของกล้อง ในกรณีส่วนใหญ่ การใช้เซ็นเซอร์เหล่านี้เป็นตัวเลือกที่ดีกว่าการใช้ เซ็นเซอร์วัดความเร่งและเซ็นเซอร์สนามแม่เหล็กโลก หรือเซ็นเซอร์การวางแนว
เซ็นเซอร์ของโครงการโอเพนซอร์ส Android
โครงการโอเพนซอร์ส Android (AOSP) มีเซ็นเซอร์ตรวจจับความเคลื่อนไหวที่ใช้ซอฟต์แวร์ 3 ตัว ได้แก่ เซ็นเซอร์แรงโน้มถ่วง
เซ็นเซอร์ตรวจวัดความเร่งเชิงเส้น และเซ็นเซอร์เวกเตอร์การหมุน เซ็นเซอร์เหล่านี้ได้รับการอัปเดตใน
Android 4.0 และตอนนี้ใช้ไจโรสโคปของอุปกรณ์ (นอกเหนือจากเซ็นเซอร์อื่นๆ) เพื่อปรับปรุงความเสถียรและ
ประสิทธิภาพ หากต้องการลองใช้เซ็นเซอร์เหล่านี้ คุณสามารถระบุเซ็นเซอร์ได้โดยใช้วิธี getVendor()
และวิธี getVersion()
(ผู้จำหน่ายคือ Google LLC และหมายเลขเวอร์ชันคือ 3) การระบุเซ็นเซอร์เหล่านี้ตามผู้จำหน่ายและหมายเลขเวอร์ชันเป็นสิ่งจำเป็นเนื่องจากระบบ Android ถือว่าเซ็นเซอร์ทั้ง 3 ตัวนี้เป็นเซ็นเซอร์รอง ตัวอย่างเช่น หากผู้ผลิตอุปกรณ์มีเซ็นเซอร์แรงโน้มถ่วงของตนเอง เซ็นเซอร์แรงโน้มถ่วงของ AOSP
จะปรากฏเป็นเซ็นเซอร์แรงโน้มถ่วงรอง เซ็นเซอร์ทั้ง 3 ตัวนี้ต้องอาศัย
ไจโรสโคป หากอุปกรณ์ไม่มีไจโรสโคป เซ็นเซอร์เหล่านี้จะไม่ปรากฏและไม่
พร้อมใช้งาน
ใช้เซ็นเซอร์แรงโน้มถ่วง
เซ็นเซอร์แรงโน้มถ่วงจะให้เวกเตอร์ 3 มิติที่ระบุ ทิศทางและขนาดของแรงโน้มถ่วง โดยปกติแล้ว เซ็นเซอร์นี้จะใช้เพื่อกำหนด การวางแนวสัมพัทธ์ของอุปกรณ์ในพื้นที่ โค้ดต่อไปนี้แสดงวิธี รับอินสแตนซ์ของเซ็นเซอร์แรงโน้มถ่วงเริ่มต้น
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);
หน่วยจะเหมือนกับที่ใช้โดยเซ็นเซอร์วัดความเร่ง (ม./วินาที2) และระบบพิกัดจะเหมือนกับที่ใช้โดยเซ็นเซอร์วัดความเร่ง
หมายเหตุ: เมื่ออุปกรณ์อยู่นิ่ง ค่าเอาต์พุตของเซ็นเซอร์แรงโน้มถ่วง ควรเหมือนกับของตัวตรวจวัดความเร่ง
ใช้เครื่องวัดความเร่งเชิงเส้น
เซ็นเซอร์ความเร่งเชิงเส้นจะให้เวกเตอร์สามมิติ ซึ่งแสดงถึงความเร่งตามแกนแต่ละแกนของอุปกรณ์ โดยไม่รวมแรงโน้มถ่วง คุณสามารถใช้ ค่านี้เพื่อตรวจจับท่าทางสัมผัสได้ ค่านี้ยังใช้เป็นอินพุตให้กับ ระบบนำทางเฉื่อย ซึ่งใช้การคาดคะเนได้ด้วย โค้ดต่อไปนี้แสดงวิธีรับอินสแตนซ์ของเซ็นเซอร์ความเร่งเชิงเส้นเริ่มต้น
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);
ในเชิงแนวคิด เซ็นเซอร์นี้จะให้ข้อมูลการเร่งความเร็วตามความสัมพันธ์ต่อไปนี้
linear acceleration = acceleration - acceleration due to gravity
โดยปกติแล้ว คุณจะใช้เซ็นเซอร์นี้เมื่อต้องการรับข้อมูลการเร่งความเร็วโดยไม่มีอิทธิพลจากแรงโน้มถ่วง เช่น คุณอาจใช้เซ็นเซอร์นี้เพื่อดูว่ารถวิ่งเร็วแค่ไหน เซ็นเซอร์ ความเร่งเชิงเส้นจะมีออฟเซ็ตเสมอ ซึ่งคุณต้องนำออก วิธีที่ง่ายที่สุดในการทำเช่นนี้คือ การสร้างขั้นตอนการปรับเทียบในแอปพลิเคชัน ในระหว่างการปรับเทียบ คุณสามารถขอให้ผู้ใช้วางอุปกรณ์บนโต๊ะ แล้วอ่านค่าออฟเซ็ตสำหรับทั้ง 3 แกน จากนั้นคุณจะลบออฟเซ็ตนั้นออกจากค่าที่อ่านได้โดยตรงของเซ็นเซอร์วัดความเร่งเพื่อหาความเร่งเชิงเส้นที่แท้จริงได้
ระบบพิกัดของเซ็นเซอร์จะเหมือนกับที่ใช้ในเซ็นเซอร์ตรวจจับความเร่ง รวมถึงหน่วยวัด (ม./วินาที2)
ใช้เซ็นเซอร์เวกเตอร์การหมุน
เวกเตอร์การหมุนแสดงการวางแนวของอุปกรณ์เป็นการรวมกันของมุมและแกน โดยที่อุปกรณ์หมุนผ่านมุม θ รอบแกน (x, y หรือ z) โค้ดต่อไปนี้แสดงวิธีรับอินสแตนซ์ของเซ็นเซอร์เวกเตอร์การหมุนเริ่มต้น
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);
องค์ประกอบทั้ง 3 ของเวกเตอร์การหมุนแสดงได้ดังนี้

โดยขนาดของเวกเตอร์การหมุนเท่ากับ sin(θ/2) และทิศทางของ เวกเตอร์การหมุนเท่ากับทิศทางของแกนการหมุน

รูปที่ 1 ระบบพิกัดที่ใช้โดยเซ็นเซอร์เวกเตอร์การหมุน
องค์ประกอบทั้ง 3 ของเวกเตอร์การหมุนจะเท่ากับองค์ประกอบ 3 อย่างสุดท้ายของควอเทอร์เนียนหน่วย (cos(θ/2), x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)) องค์ประกอบของเวกเตอร์การหมุนไม่มีหน่วย แกน x, y และ z มีคำจำกัดความเช่นเดียวกับเซ็นเซอร์ตรวจวัดความเร่ง ระบบพิกัดอ้างอิง กำหนดเป็นฐานตั้งฉากโดยตรง (ดูรูปที่ 1) ระบบพิกัดนี้ มีลักษณะดังนี้
- X จะกำหนดเป็นผลคูณเชิงเวกเตอร์ Y x Z โดยจะสัมผัสกับ พื้นดินที่ตำแหน่งปัจจุบันของอุปกรณ์และชี้ไปทางทิศตะวันออกโดยประมาณ
- Y สัมผัสกับพื้นดินที่ตำแหน่งปัจจุบันของอุปกรณ์และชี้ไปยังขั้วโลกเหนือ แม่เหล็กโลก
- Z ชี้ขึ้นไปบนท้องฟ้าและตั้งฉากกับระนาบพื้น
ดูแอปพลิเคชันตัวอย่างที่แสดงวิธีใช้เซ็นเซอร์เวกเตอร์การหมุนได้ที่ RotationVectorDemo.java
ใช้เซ็นเซอร์ตรวจจับการเคลื่อนไหวที่สำคัญ
เซ็นเซอร์ตรวจจับการเคลื่อนไหวที่สําคัญจะทริกเกอร์เหตุการณ์ทุกครั้งที่ตรวจพบการเคลื่อนไหวที่สําคัญ และ จากนั้นจะปิดตัวเอง การเคลื่อนไหวที่สำคัญคือการเคลื่อนไหวที่อาจทําให้เกิดการเปลี่ยนแปลงตําแหน่งของผู้ใช้ เช่น การเดิน การปั่นจักรยาน หรือการนั่งในรถที่กําลังเคลื่อนที่ โค้ดต่อไปนี้แสดงวิธี รับอินสแตนซ์ของเซ็นเซอร์ตรวจจับความเคลื่อนไหวที่สำคัญเริ่มต้นและวิธีลงทะเบียนเครื่อง ฟังเหตุการณ์
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);
ดูข้อมูลเพิ่มเติมได้ที่ TriggerEventListener
ใช้เซ็นเซอร์ตัวนับก้าว
เซ็นเซอร์ตัวนับก้าวจะแสดงจำนวนก้าวที่ผู้ใช้เดินนับตั้งแต่รีบูตครั้งล่าสุด ขณะที่เซ็นเซอร์เปิดใช้งานอยู่ ตัวนับก้าวมีเวลาในการตอบสนองมากกว่า (สูงสุด 10 วินาที) แต่มีความแม่นยำมากกว่าเซ็นเซอร์ตรวจจับก้าว
หมายเหตุ: คุณต้องประกาศสิทธิ์
ACTIVITY_RECOGNITION
เพื่อให้แอปใช้เซ็นเซอร์นี้ในอุปกรณ์ที่ใช้
Android 10 (API ระดับ 29) ขึ้นไปได้
โค้ดต่อไปนี้แสดงวิธีรับอินสแตนซ์ของเซ็นเซอร์ตัวนับก้าวเริ่มต้น
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);
หากต้องการรักษาแบตเตอรี่ในอุปกรณ์ที่เรียกใช้แอป คุณควรใช้คลาส
JobScheduler
เพื่อดึงค่าปัจจุบันจาก
เซ็นเซอร์ตัวนับก้าวในช่วงเวลาที่เฉพาะเจาะจง แม้ว่าแอปประเภทต่างๆ
จะต้องมีช่วงเวลาการอ่านเซ็นเซอร์ที่แตกต่างกัน แต่คุณควรตั้งช่วงเวลานี้ให้
นานที่สุดเท่าที่จะเป็นไปได้ เว้นแต่แอปของคุณจะต้องใช้ข้อมูลแบบเรียลไทม์จากเซ็นเซอร์
ใช้เซ็นเซอร์ตรวจจับการก้าว
เซ็นเซอร์ตรวจจับการก้าวจะทริกเกอร์เหตุการณ์ทุกครั้งที่ผู้ใช้ก้าว เวลาในการตอบสนองคาดว่าจะน้อยกว่า 2 วินาที
หมายเหตุ: คุณต้องประกาศสิทธิ์
ACTIVITY_RECOGNITION
เพื่อให้แอปใช้เซ็นเซอร์นี้ในอุปกรณ์ที่ใช้
Android 10 (API ระดับ 29) ขึ้นไปได้
โค้ดต่อไปนี้แสดงวิธีรับอินสแตนซ์ของเซ็นเซอร์ตรวจจับการก้าวเริ่มต้น
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);
ทำงานกับข้อมูลดิบ
เซ็นเซอร์ต่อไปนี้จะให้ข้อมูลดิบเกี่ยวกับแรงเชิงเส้นและ แรงหมุนที่ใช้กับอุปกรณ์แก่แอป หากต้องการใช้ค่าจากเซ็นเซอร์เหล่านี้อย่างมีประสิทธิภาพ คุณต้องกรองปัจจัยจากสภาพแวดล้อม เช่น แรงโน้มถ่วง ออก นอกจากนี้ คุณอาจต้องใช้อัลกอริทึมการปรับค่าให้เรียบกับแนวโน้ม ของค่าเพื่อลดสัญญาณรบกวน
ใช้เครื่องวัดความเร่ง
เซ็นเซอร์ตรวจวัดความเร่งจะวัดความเร่งที่ใช้กับอุปกรณ์ รวมถึงแรงโน้มถ่วง โค้ดต่อไปนี้แสดงวิธีรับอินสแตนซ์ของเซ็นเซอร์วัดความเร่งเริ่มต้น
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);
หมายเหตุ: หากแอปกำหนดเป้าหมายเป็น Android 12 (API ระดับ 31) ขึ้นไป เซ็นเซอร์นี้จะจำกัดอัตรา
ในเชิงแนวคิด เซ็นเซอร์วัดความเร่งจะกำหนดความเร่งที่ใช้กับอุปกรณ์ (Ad) โดยการวัดแรงที่ใช้กับเซ็นเซอร์เอง (Fs) โดยใช้ความสัมพันธ์ต่อไปนี้

อย่างไรก็ตาม แรงโน้มถ่วงจะส่งผลต่อความเร่งที่วัดได้เสมอตามความสัมพันธ์ต่อไปนี้

ด้วยเหตุนี้ เมื่อวางอุปกรณ์ไว้บนโต๊ะ (และไม่มีการเร่งความเร็ว) มาตรวัดความเร่งจะอ่านค่าขนาดเป็น g = 9.81 m/s2 ในทำนองเดียวกัน เมื่ออุปกรณ์อยู่ใน การตกอย่างอิสระและเร่งความเร็วลงสู่พื้นอย่างรวดเร็วที่ 9.81 ม./วินาที2 มาตรวัดความเร่งจะอ่านค่าขนาดของ g = 0 ม./วินาที2 ดังนั้น หากต้องการวัดความเร่งจริงของอุปกรณ์ คุณต้องนำส่วนประกอบของแรงโน้มถ่วงออกจากข้อมูลมาตรวัดความเร่ง ซึ่งทำได้โดยใช้ตัวกรอง High-Pass ในทางกลับกัน คุณสามารถใช้ตัวกรองแบบผ่านต่ำเพื่อแยกแรงโน้มถ่วงได้ ตัวอย่างต่อไปนี้แสดงวิธีดำเนินการนี้
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]; }
หมายเหตุ: คุณใช้เทคนิคต่างๆ มากมายเพื่อกรองข้อมูลเซ็นเซอร์ได้ ตัวอย่างโค้ดด้านบนใช้ค่าคงที่ตัวกรองอย่างง่าย (alpha) เพื่อสร้างตัวกรองแบบผ่านต่ำ ค่าคงที่ของตัวกรองนี้ ได้มาจากค่าคงที่ของเวลา (t) ซึ่งเป็นการแสดงค่าคร่าวๆ ของเวลาในการตอบสนองที่ ตัวกรองเพิ่มลงในเหตุการณ์ของเซ็นเซอร์ และอัตราการนำส่งเหตุการณ์ของเซ็นเซอร์ (dt) ตัวอย่างโค้ด ใช้ค่าอัลฟ่าเป็น 0.8 เพื่อวัตถุประสงค์ในการสาธิต หากใช้วิธีการกรองนี้ คุณอาจต้องเลือกค่าอัลฟ่าอื่น
มาตรความเร่งใช้ระบบ พิกัดเซ็นเซอร์มาตรฐาน ในทางปฏิบัติ หมายความว่าเงื่อนไขต่อไปนี้จะมีผลเมื่อวางอุปกรณ์ราบลงบนโต๊ะในแนวนอนปกติ
- หากคุณดันอุปกรณ์ทางด้านซ้าย (เพื่อให้เคลื่อนที่ไปทางขวา) ค่าความเร่ง x จะเป็นบวก
- หากคุณดันอุปกรณ์ที่ด้านล่าง (เพื่อให้อุปกรณ์เคลื่อนที่ออกจากตัวคุณ) ค่าการเร่งความเร็วในแนวแกน y จะเป็นบวก
- หากคุณดันอุปกรณ์ขึ้นไปบนท้องฟ้าด้วยความเร่ง A m/s2 ค่าความเร่งในแนวแกน z จะเท่ากับ A + 9.81 ซึ่งสอดคล้องกับความเร่งของอุปกรณ์ (+A m/s2) ลบด้วยแรงโน้มถ่วง (-9.81 m/s2)
- อุปกรณ์ที่อยู่กับที่จะมีค่าความเร่งเป็น +9.81 ซึ่งสอดคล้องกับ ความเร่งของอุปกรณ์ (0 ม./วินาที2 ลบด้วยแรงโน้มถ่วง ซึ่งเท่ากับ -9.81 ม./วินาที2)
โดยทั่วไปแล้ว ตัวตรวจวัดความเร่งเป็นเซ็นเซอร์ที่ดีที่ควรใช้หากคุณกำลังตรวจสอบการเคลื่อนไหวของอุปกรณ์ โทรศัพท์มือถือและแท็บเล็ตที่ใช้ Android เกือบทุกรุ่นมีมาตรวัดความเร่ง และใช้พลังงานน้อยกว่าเซ็นเซอร์ตรวจจับความเคลื่อนไหวอื่นๆ ประมาณ 10 เท่า ข้อเสียอย่างหนึ่งคือคุณอาจต้องใช้ ตัวกรองแบบผ่านต่ำและแบบผ่านสูงเพื่อกำจัดแรงโน้มถ่วงและลดสัญญาณรบกวน
ใช้เครื่องวัดการหมุน
ไจโรสโคปจะวัดอัตราการหมุนในหน่วยเรเดียน/วินาทีรอบแกน x, y และ z ของอุปกรณ์ โค้ดต่อไปนี้แสดงวิธีรับอินสแตนซ์ของไจโรสโคปเริ่มต้น
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);
หมายเหตุ: หากแอปกำหนดเป้าหมายเป็น Android 12 (API ระดับ 31) ขึ้นไป เซ็นเซอร์นี้จะจำกัดอัตรา
ระบบพิกัดของเซ็นเซอร์ จะเหมือนกับที่ใช้สำหรับเซ็นเซอร์ตรวจวัดความเร่ง การหมุนเป็นบวกในทิศทางทวนเข็มนาฬิกา กล่าวคือ ผู้สังเกตการณ์ที่มองจากตำแหน่งบวกบนแกน x, y หรือ z ไปยังอุปกรณ์ที่วางอยู่บนจุดกำเนิดจะรายงานการหมุนเป็นบวกหากอุปกรณ์ดูเหมือนจะหมุนทวนเข็มนาฬิกา นี่คือ คำจำกัดความทางคณิตศาสตร์มาตรฐานของการหมุนในทิศทางบวก และไม่เหมือนกับคำจำกัดความของ การหมุนที่ใช้โดยเซ็นเซอร์การวางแนว
โดยปกติแล้ว เอาต์พุตของไจโรสโคปจะรวมกันเมื่อเวลาผ่านไปเพื่อคำนวณการหมุนที่อธิบาย การเปลี่ยนแปลงของมุมในช่วงเวลาที่กำหนด เช่น
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; }
ไจโรสโคปมาตรฐานให้ข้อมูลการหมุนดิบโดยไม่มีการกรองหรือแก้ไขสัญญาณรบกวนและ ดริฟต์ (อคติ) ในทางปฏิบัติ สัญญาณรบกวนและการดริฟต์ของไจโรสโคปจะทำให้เกิดข้อผิดพลาดที่ต้อง ชดเชย โดยปกติแล้ว คุณจะกำหนดดริฟต์ (อคติ) และสัญญาณรบกวนได้ด้วยการตรวจสอบเซ็นเซอร์อื่นๆ เช่น เซ็นเซอร์แรงโน้มถ่วงหรือตัวตรวจวัดความเร่ง
ใช้เครื่องวัดการหมุนที่ยังไม่ได้ปรับเทียบ
ไจโรสโคปที่ยังไม่ได้ปรับเทียบจะคล้ายกับไจโรสโคป
เว้นแต่ว่าจะไม่มีการชดเชยการดริฟต์ของไจโรกับอัตราการหมุน การปรับเทียบจากโรงงาน
และการชดเชยอุณหภูมิจะยังคงมีผลกับอัตราการหมุน ไจโรสโคปที่ยังไม่ได้ปรับเทียบมีประโยชน์สำหรับการประมวลผลภายหลังและการผสานข้อมูลการวางแนว โดยทั่วไปแล้ว
gyroscope_event.values[0]
จะใกล้เคียงกับ
uncalibrated_gyroscope_event.values[0] - uncalibrated_gyroscope_event.values[3]
กล่าวคือ
calibrated_x ~= uncalibrated_x - bias_estimate_x
หมายเหตุ: เซ็นเซอร์ที่ไม่ได้ปรับเทียบจะให้ผลลัพธ์ดิบมากกว่าและอาจ มีอคติอยู่บ้าง แต่การวัดของเซ็นเซอร์จะมีการเปลี่ยนแปลงน้อยกว่าจากการแก้ไขที่ใช้ผ่าน การปรับเทียบ แอปพลิเคชันบางอย่างอาจต้องการผลลัพธ์ที่ไม่ได้ปรับเทียบเหล่านี้เนื่องจากมีความราบรื่นและ เชื่อถือได้มากกว่า เช่น หากแอปพลิเคชันพยายามทำการรวมเซ็นเซอร์ด้วยตัวเอง การแนะนำการปรับเทียบอาจทำให้ผลลัพธ์บิดเบือนได้
นอกเหนือจากอัตราการหมุนแล้ว ไจโรสโคปที่ยังไม่ได้ปรับเทียบยังให้ค่าประมาณ การดริฟต์รอบแกนแต่ละแกนด้วย โค้ดต่อไปนี้แสดงวิธีรับอินสแตนซ์ของไจโรสโคปเริ่มต้นที่ไม่ได้ปรับเทียบ
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);
ตัวอย่างโค้ดเพิ่มเติม
ตัวอย่าง BatchStepSensor แสดงให้เห็นถึงการใช้ API ที่กล่าวถึงในหน้านี้เพิ่มเติม