มาทำลองเล่น Sensor API บนแอนดรอยด์กัน
อย่างที่รู้กันว่าบนแอนดรอยด์นั้นมี Sensor มากมายเพื่อช่วยเพิ่มลูกเล่นและความสามารถต่างๆให้กับ Android OS อีกทั้งยังมี Sensor API เพื่อให้นักพัฒนาสามารถสร้างแอปที่เรียกใช้งาน Sensor เหล่านั้นได้อีกด้วย
ดังนั้นในบทความนี้เจ้าของบล็อกก็จะพามาดูกันว่าการเรียกใช้งาน Sensor API บนแอนดรอยด์นั้นต้องทำอย่างไร และมี Sensor สำหรับวัดค่าอะไรให้เรียกใช้งานบ้าง
Sensor ที่มีให้ใช้บนแอนดรอยด์สามารถวัดค่าอะไรได้บ้าง
บอกเลยว่าประเภทของ Sensor ที่มีให้ใช้งานบนแอนดรอยด์นั้นมีหลายประเภทมาก โดยสามารถวัดค่าต่างๆได้ดังนี้
Accelerometer
Sensor.TYPE_ACCELEROMETER
(API Level 3)Sensor.TYPE_ACCELEROMETER_UNCALIBRATED
(API Level 26)
วัดความเร่งที่เกิดขึ้นกับอุปกรณ์แอนดรอยด์ในแนวแกน X, Y และ Z
โดยมีหน่วยเป็น Metre/Second²
ค่าจาก Accelerometer จะเป็นผลรวมของความเร่งที่เกิดจากแรงโน้มถ่วง (Gravity) ของโลกและความเร่งที่เกิดจากการเคลื่อนที่ของอุปกรณ์แอนดรอยด์ (Linear Accelerometer)
Gravity
Sensor.TYPE_GRAVITY
(API Level 9)
วัดความเร่งที่เกิดจากแรงโน้มถ่วงของโลกโดยอ้างอิงจากทิศทางของอุปกรณ์แอนดรอยด์ในแนวแกน X, Y และ Z
โดยมีหน่วยเป็น Metre/Second²
ค่าจาก Gravity จะเป็นความเร่งที่เกิดจากแรงโน้มถ่วงของโลกเท่านั้น ไม่รวมไปถึงความเร่งที่เกิดจากการเคลื่อนที่ของอุปกรณ์แอนดรอยด์ (Linear Accelerometer)
Linear Accelerometer
Sensor.TYPE_LINEAR_ACCELEROMETER
(API Level 9)
วัดความเร่งที่เกิดการจากเคลื่อนที่ของอุปกรณ์แอนดรอยด์ในแนวแกน X, Y และ Z
โดยมีหน่วยเป็น Metre/Second²
ค่าจาก Linear Accelerometer จะเกิดจากความเร่งในการเคลื่อนที่ของอุปกรณ์แอนดรอยด์เท่านั้น ไม่รวมไปถึงความเร่งที่เกิดจากแรงโน่มถ่วงของโลก (Gravity)
Gyroscope
Sensor.TYPE_GYROSCOPE
(API Level 3)Sensor.TYPE_GYROSCOPE_UNCALIBRATED
(API Level 18)
วัดความเร็วในการหมุนของอุปกรณ์แอนดรอยด์ในแนวแกน X, Y และ Z
โดยมีหน่วยเป็น Radian/Second
Rotation Vector
Sensor.TYPE_ROTATION_VECTOR
(API Level 9)
วัดทิศทางในแนวแกน X, Y และ Z โดยมีการอ้างอิงตำแหน่งจากสนามแม่เหล็กโลกและองศาในการหมุนของอุปกรณ์แอนดรอยด์
โดยมีหน่วยเป็น Degree ในแนวแกน X, Y, Z และความแม่นยำในหน่วย Radian
Geomagnetic Rotation Vector
Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR
(API Level 19)
คล้ายกับ Rotation Vector แต่จะใช้ Magnetometer แทน Gyroscope ซึ่งใช้พลังงานน้อยกว่า
Game Rotation Vector
Sensor.TYPE_GAME_ROTATION_VECTOR
(API Level 18)
คล้ายกับ Rotation Vector แต่ต่างกันตรงที่การวัดทิศทางในแนวแกน X, Y และ Z จะไม่ได้มีการอ้างอิงจากสนามแม่เหล็กโลก แต่จะใช้แรงโน้มถ่วงในการอ้างอิงแทน
Magnetic Field
Sensor.TYPE_MAGNETIC_FIELD
(API Level 3)Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED
(API Level 18)
วัดค่าเหนี่ยวนำทางแม่เหล็กไฟฟ้าที่กระทำต่ออุปกรณ์แอนดรอยด์ในแนวแกน X, Y และ Z
โดยมีหน่วยเป็น micro-Tesla (uT)
Pose 6 Degrees of Freedom
Sensor.TYPE_POSE_6DOF
(API Level 24)
การวัดค่าในการเคลื่อนไหวของอุปกรณ์แอนดรอยด์ในรูปแบบของ 6 Degree of Freedom (Forward/Back, Up/Down, Left/Right, Yaw, Pitch และ Roll) โดยจะรวมไปถึงผลต่างขององศาและระยะทางในการเคลื่อนที่ที่เปลี่ยนไปโดยเทียบกับตำแหน่งก่อนหน้า
Significant Motion
Sensor.TYPE_SIGNIFICANT_MOTION
(API Level 18)
ตรวจจับการเคลื่อนไหวใดๆก็ตามที่มีนัยยะสำคัญ โดยใช้ Sensor ที่เกี่ยวข้องกับการเคลื่อนไหวของอุปกรณ์แอนดรอยด์ที่มีอยู่ภายในเครื่อง
Motion Detect
Sensor.TYPE_MOTION_DETECT
(API Level 24)
ตรวจจับการเคลื่อนไหวของอุปกรณ์แอนดรอยด์ เมื่อเคลื่อนไหวอย่างต่อเนื่องเป็นระยะเวลานาน 5-10 วินาที
Stationary Detect
Sensor.TYPE_STATIONARY_DETECT
(API Level 24)
ตรวจจับการเคลื่อนไหวของอุปกรณ์แอนดรอยด์ เมื่อถูกวางไว้กับที่เป็นระยะเวลานาน 5-10 วินาที
Step Counter
Sensor.TYPE_STEP_COUNTER
(API Level 19)
นับจำนวนก้าวเดินจากการเคลื่อนไหวของอุปกรณ์แอนดรอยด์ที่สัมพันธ์กับการเดินของผู้ใช้
Step Detector
Sensor.TYPE_STEP_DETECTOR
(API Level 19)
ตรวจจับการเดินจากการเคลื่อนไหวของอุปกรณ์แอนดรอยด์ที่สัมพันธ์กับการเดินของผู้ใช้
Low Latency Off-body Detect
Sensor.TYPE_LOW_LATENCY_OFFBODY_DETECT
(API Level 26)
ตรวจจับการสวม/ถอดอุปกรณ์แอนดรอยด์ เช่น ผู้ใช้สวม/ถอดอุปกรณ์แอนดรอยด์ที่เป็นแบบ Wearable Device
Heart Rate
Sensor.TYPE_HEART_RATE
(API Level 20)
วัดอัตราการเต้นของหัวใจ โดยมีหน่วยเป็น Beat/Minute
Heart Beat
Sensor.TYPE_HEART_BEAT
(API Level 24)
ตรวจจับสัญญาณการเต้นของหัวใจที่มีค่าสูงสุดในช่วงเวลานั้นๆ โดยคำนวณด้วย QRS Complex ของสัญญาณ ECG
Hinge Angle
Sensor.TYPE_HINGE_ANGLE
(API Level 30)
วัดองศาในการกาง/พับหน้าจอของอุปกรณ์แอนดรอยด์ที่เป็น Foldable Device
โดยมีหน่วยเป็น Degree
Ambient Temperature
Sensor.TYPE_AMBIENT_TEMPERATURE
(API Level 14)
วัดอุณหภูมิโดยรอบอุปกรณ์แอนดรอยด์ มีหน่วยเป็น Degree Celcius
Relative Humidity
Sensor.TYPE_RELATIVE_HUMIDITY
(API Level 14)
วัดความชื้นสัมพัทธ์ของอากาศโดยรอบอุปกรณ์แอนดรอยด์ มีหน่วยเป็น %
Light
Sensor.TYPE_LIGHT
(API Level 3)
วัดระดับความเข้มของแสงที่กระทำต่อ Sensor โดยมีหน่วยเป็น Lux
Proximity
Sensor.TYPE_PROXIMITY
(API Level 3)
วัดระยะห่างของวัตถุที่กระทำต่อ Sensor โดยค่าที่ได้จะขึ้นอยู่กับ Proximity Sensor ของเครื่องนั้นๆ
บางเครื่องที่สามารถวัดระยะห่างได้ก็จะส่งค่ามาเป็น Centimetre ในขณะที่บางเครื่องวัดได้แค่ 2 สถานะเท่านั้นคือมีวัตถุใดๆบังอยู่กับไม่มีวัตถุบัง
Pressure
Sensor.TYPE_PRESSURE
(API Level 3)
วัดความดันบรรยากาศ โดยมีหน่วยเป็น Millibar (hPa)
จะเห็นว่า Sensor บางประเภทนั้นก็ไม่ได้มีมาตั้งแต่แอนดรอยด์เวอร์ชันแรกๆ แต่ถูกเพิ่มเข้ามาในเวอร์ชันใหม่ๆ และถึงแม้ว่าระบบแอนดรอยด์จะรองรับ Sensor ได้มากมาย แต่ก็อย่าลืมว่า Sensor บางประเภทนั้น อาจจะมีแค่เฉพาะบางเครื่องเท่านั้น ในขณะที่บาง Sensor ก็มีอยู่แทบทุกเครื่องทุกรุ่นเลย
และขอตัด Sensor บางประเภทออกไป เนื่องจากบนแอนดรอยด์ไม่แนะนำให้ใช้แล้ว
ทำไม Sensor บางตัวมี Uncalibrated ด้วย มันคืออะไร?
จากประเภทของ Sensor ทั้งหมด ผู้ที่หลงเข้ามาอ่านก็อาจจะสังเกตเห็นว่า Sensor อย่าง Accelerometer, Gyroscope และ Magnetic Field นั้นมีแบบ Uncalibrated ด้วย
โดยปกติแล้ว Sensor จำพวก Hardware Sensor ที่อยู่ในอุปกรณ์นั้นจะไม่ได้ค่าที่ถูกต้องเป๊ะๆเสมอไป จึงต้องมีการทดสอบและวัดค่าจากนั้นก็ทำการปรับเพื่อชดเชยค่าให้แม่นยำที่สุด ซึ่งนั้นคือ Calibrated
ดังนั้น Uncalibrated จึงหมายถึงการเรียกใช้งาน Sensor เหล่านั้นโดยไม่สนใจการชดเชยค่าแต่อย่างใด ซึ่งจะเหมาะกับการใช้งานในบางกรณีเท่านั้น สำหรับนักพัฒนาทั่วไปไม่ต้องสนใจค่าจาก Sensor แบบ Uncalibrated ก็ได้
การเรียกใช้งาน Sensor API บนแอนดรอยด์
ในการเรียกใช้งานนั้นจะเรียกผ่านคลาสที่ชื่อว่า SensorManager ซึ่งเป็นหนึ่งใน System Service ของระบบแอนดรอยด์นั่นเอง
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
และไม่ว่าจะเป็นอุปกรณ์แอนดรอยด์แบบไหนก็ตาม ก็จะมี SensorManager ให้เรียกใช้งานอยู่เสมอ อยู่ที่ว่าจะมี Sensor ที่ต้องการเรียกใช้งานอยู่หรือป่าว
ในกรณีที่อยากรู้ว่าอุปกรณ์แอนดรอยด์เครื่องนั้นมี Sensor อะไรให้ใช้งานบ้าง ก็สามารถใช้คำสั่งแบบนี้ได้เลย
val sensorManager: SensorManager = /* ... */
val sensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)
โดยที่ Sensor.TYPE_ALL
นั้นหมายถึง Sensor ทุกประเภทนั่นเอง แต่ถ้าอยากรู้ว่าอุปกรณ์แอนดรอยด์เครื่องนั้นมี Sensor ประเภทไหนกี่ตัว ก็สามารถกำหนดเป็น Sensor ที่ต้องการได้เช่นกัน
บนแอนดรอยด์ไม่จำเป็นต้องมี Sensor ละ 1 ตัวเสมอไป อาจจะมีมากกว่า 1 ก็ได้ ขึ้นอยู่กับจุดประสงค์ในการออกแบบของอุปกรณ์แอนดรอยด์เครื่องนั้นๆ
และถ้าอยากเรียกใช้งาน Sensor ก็ให้ใช้คำสั่ง
val sensorManager: SensorManager = /* ... */
val lightSensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)
จะเห็นว่าคำสั่ง getDefaultSensor(...)
นั้นให้ค่าออกมาเป็น Sensor?
นั่นหมายความว่าถ้าไม่มี Sensor ดังกล่าว ก็จะได้ค่าออกมาเป็น null
นั่นเอง
val sensorManager: SensorManager = /* ... */
sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)?.let { lightSensor: Sensor ->
// Light sensor is available
} ?: run {
// No light sensor
}
โดยคลาส Sensor ที่ได้นั้นจะมีข้อมูลของ Sensor แต่ละตัวอยู่ข้างในด้วย
การอ่านค่าจาก Sensor
ในการอ่านค่าจาก Sensor ใดๆก็ตามจะต้องกำหนดผ่าน SensorManager ทุกครั้ง โดย Sensor จะทำการอ่านค่าอยู่ตลอดเวลาและส่งข้อมูลมาให้ในลักษณะของ Event Listener ที่ชื่อว่า SensorEventListener
val sensorEventListener = object : SensorEventListener {
override fun onSensorChanged(event: SensorEvent) {
// Sensor's value changed
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
// Sensor's accuracy changed
}
}
โดยนักพัฒนาจะต้องใช้คำสั่ง registerListener(...)
ของ SensorManager เพื่อเริ่มการอ่านค่าจาก Sensor ที่ต้องการ และจะต้องใช้คำสั่ง unregisterListener(...)
เพื่อเลิกใช้งาน Sensor นั้นๆด้วย
private val sensorManager: SensorManager = /* ... */
private fun startLightSensor() {
sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)?.let { sensor: Sensor ->
sensorManager.registerListener(
sensorEventListener,
sensor,
SensorManager.SENSOR_DELAY_NORMAL
)
}
}
private fun stopLightSensor() {
sensorManager.unregisterListener(sensorEventListener)
}
private val sensorEventListener: SensorEventListener = /* ... */
ใน onSensorChanged(...)
ก็จะทำการอัปเดตค่าให้ตลอดเวลาที่ Sensor ทำงาน โดยจะส่งค่ามาเป็นคลาส SensorEvent
และสำหรับค่าที่อยู่ใน SensorEvent นั้นจะเป็นลักษณะของ FloatArray โดยที่จำนวนข้อมูลใน FloatArray นั้นจะขึ้นอยู่กับว่าเป็น Sensor แบบไหน
จากตัวอย่างข้างบน เจ้าของบล็อกอ่านค่าจาก Sensor.TYPE_LIGHT
ซึ่งมีข้อมูลตัวเดียวเป็นค่า Lux ดังนั้นจะต้องใช้คำสั่งแบบนี้
val sensorEventListener = object : SensorEventListener {
override fun onSensorChanged(event: SensorEvent) {
val lux: Float = event.values.getOrNull(0) ?: 0f
// Do something
}
/* ... */
}
และถ้าเป็น Sensor.TYPE_ACCELEROMETER
ก็จะดึงค่าในรูปแบบเดียวกัน แต่จำนวนใน FloatArray ต่างกัน
val sensorEventListener = object : SensorEventListener {
override fun onSensorChanged(event: SensorEvent) {
val x: Float = event.values.getOrNull(0) ?: 0f
val y: Float = event.values.getOrNull(1) ?: 0f
val z: Float = event.values.getOrNull(2) ?: 0f
}
/* ... */
}
โดยค่าที่ได้จาก Sensor แต่ละประเภทสามารถดูข้อมูลเพิ่มเติมได้จาก Value - Sensor Event [Android Developer]
และนอกจากค่าที่ต้องการแล้ว ใน SensorEvent ก็ยังมีข้อมูลอื่นๆให้ด้วย
val event: SensorEvent = /* ... */
val accuracy: Int = event.accuracy
val sensor: Sensor = event.sensor
val timestamp: Long = event.timestamp
Sensor บางตัวก็ต้องขอ Permission ก่อนใช้งาน เนื่องจากเกี่ยวข้องกับ User Privacy
บนแอนดรอยด์เวอร์ชันใหม่ๆอย่าง Android 10 เป็นต้นไปที่ให้ความสำคัญกับเรื่อง User Privacy มากขึ้น จึงทำให้การอ่านข้อมูลจาก Sensor ที่เกี่ยวข้องกับข้อมูลส่วนตัวของผู้ใช้ จำเป็นจะต้องขอ Permission จากผู้ใช้ก่อน ซึ่งจะประกอบไปด้วย
android.permission.BODY_SENSORS
: สำหรับSensor.TYPE_HEART_RATE
android.permission.ACTIVITY_RECOGNITION
: สำหรับSensor.TYPE_STEP_COUNTER
หรือSensor.TYPE_STEP_DETECTOR
สรุป
ในทุกวันนี้บนอุปกรณ์แอนดรอยด์นั้นมี Sensor ต่างๆมากมายที่ถูกติดตั้งไว้อยู่ในเครื่อง เพื่อเพิ่มความสามารถและลูกเล่นต่างๆให้ผู้ใช้สามารถใช้งานได้สะดวกมากขึ้น ทำอะไรได้เยอะขึ้น ซึ่งไม่ใช่แค่ระบบแอนดรอยด์เพียงอย่างเดียวเท่านั้นที่จะเรียกใช้งาน Sensor เหล่านั้นได้ แต่จะรวมไปถึงแอปต่างๆที่เขียนขึ้นมาจากฝีมือของนักพัฒนาแอนดรอยด์เพื่อประยุกต์ใช้งาน Sensor เหล่านี้ให้เกิดเป็นฟีเจอร์หรือลูกเล่นต่างๆภายในแอป ผ่านการเรียกใช้งาน Sensor API นั่นเอง