我正在尝试为标准HC-SR04超声波传感器创建Android Things驱动程序。我相信我已经确定了一系列事件正确:see footer,但无法将其注册为UserSensor。
userSensor = UserSensor.Builder()
.setName("HC-SR04 Ultrasonic Distance Sensor")
.setVersion(1)
// If boolean "on face or not," should I use something linear like TYPE_LIGHT
.setType(Sensor.TYPE_PROXIMITY)
.setDriver(this) // UserSensorDriver
.build()
此时,将UserSensor注册到UserDriverManager(已完成)并将其注册到SensorManager之间有什么区别?有什么东西阻止它出现在传感器列表中吗?我需要等到传感器准备好了吗?与sensorManager.registerDynamicSensorCallback?
一样val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensorManager.registerListener(this, // SensorEventListener.onSensorChanged
sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY),
SensorManager.SENSOR_DELAY_NORMAL)
无论我尝试什么,我都会得到" E / SensorManager:传感器或监听器为空" (这在Kotlin中更令人惊讶,因为无法使用空值偷偷溜进去)
我的传感器/ also a gist:
/** Callback for when the distance changes "enough to care" */
interface SignificantDistanceChangeListener {
fun onDistanceChanged(distanceCm: Float)
}
/**
* User Sensor - Ultrasonic range finder
*/
class HCSR04(context: Context, val sdcl: SignificantDistanceChangeListener) : UserSensorDriver(), SensorEventListener, AutoCloseable {
private val LOG = Logger.getLogger(this.javaClass.name)
private val gpio = PeripheralManagerService().openGpio("BCM23")
private val distanceReading: BlockingQueue<Float> = ArrayBlockingQueue(1)
// Choreography of each ping
private val scheduler: ScheduledExecutorService = Executors.newScheduledThreadPool(1)
private val userSensor: UserSensor
init {
userSensor = UserSensor.Builder()
.setName("HC-SR04 Ultrasonic Distance Sensor")
.setVersion(1)
.setType(Sensor.TYPE_PROXIMITY) // Could this be something more linear like TYPE_LIGHT
.setDriver(this)
.build()
UserDriverManager.getManager().registerSensor(userSensor)
val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
LOG.info("ALL Sensors: ${sensorManager.getSensorList(Sensor.TYPE_ALL)}")
sensorManager.registerDynamicSensorCallback(object : SensorManager.DynamicSensorCallback() {
override fun onDynamicSensorConnected(sensor: Sensor) {
LOG.info("onDynamicSensorConnected")
if (sensor.type == Sensor.TYPE_PROXIMITY) {
sensorManager.registerListener(
this@HCSR04,
sensor,
SensorManager.SENSOR_DELAY_NORMAL
)
}
}
})
}
val gpioEdgeCallback = object : GpioCallback() {
// Track the reply rise/fall
private val startMs = AtomicLong()
private val startValid = AtomicBoolean(false)
private fun calculate() {
val elapsed = (System.nanoTime() / 1000) - startMs.get()
if (startValid.get() && elapsed > 0) {
distanceReading.put(elapsed * 34000 / 2f)
} else {
LOG.warning("Discarding edge callback ${startMs.get()} ${startValid.get()} $elapsed")
}
startValid.set(false)
}
override fun onGpioEdge(gpio: Gpio?): Boolean {
if (gpio != null) {
if (gpio.value) {
startMs.set(System.nanoTime() / 1000)
startValid.set(true)
} else {
calculate()
}
LOG.finer("GPIO input edge: ${System.nanoTime() / 1000} ${gpio.value}")
}
return true
}
override fun onGpioError(gpio: Gpio?, error: Int) = LOG.severe("$gpio Error event $error")
}
/** Launch a new thread to get the distance, then block until we have a result */
override fun read(): UserSensorReading {
distanceReading.clear()
gpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW)
gpio.setActiveType(Gpio.ACTIVE_HIGH)
gpio.value = false
scheduler.schedule({ gpio.value = true }, 1, TimeUnit.MICROSECONDS)
scheduler.schedule({ gpio.value = false }, 11, TimeUnit.MICROSECONDS)
scheduler.schedule({
gpio.setDirection(Gpio.DIRECTION_IN)
gpio.setActiveType(Gpio.ACTIVE_HIGH) // redundant?
gpio.setEdgeTriggerType(Gpio.EDGE_BOTH)
gpio.registerGpioCallback(gpioEdgeCallback)
}, 12, TimeUnit.MICROSECONDS)
val distanceCm = distanceReading.take()
gpio.unregisterGpioCallback(gpioEdgeCallback)
LOG.info("New distance reading: $distanceCm")
return UserSensorReading(floatArrayOf(distanceCm))
}
/** from @SensorEventListener */
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) = LOG.info("$sensor accuracy change: $accuracy")
/**
* from @SensorEventListener
*/
override fun onSensorChanged(event: SensorEvent) = sdcl.onDistanceChanged(event.values[0])
/** from @AutoCloseable */
override fun close() {
LOG.warning("Closing Sensor HCSR04")
UserDriverManager.getManager().unregisterSensor(userSensor)
gpio.close()
scheduler.shutdownNow()
}
}
答案 0 :(得分:0)
您可能会考虑改变传感器类型。 TYPE_PROXIMITY
是一个变化中的传感器,在当前预览中受支持。然而,它也是一个唤醒传感器,可能尚未完全支持。您可以尝试修改传感器定义以改为使用自定义类型:
userSensor = UserSensor.Builder()
.setName("HC-SR04 Ultrasonic Distance Sensor")
.setVersion(1)
.setCustomType(Sensor.TYPE_DEVICE_PRIVATE_BASE,
"com.example.ultrasonic",
Sensor.REPORTING_MODE_CONTINUOUS)
.setDriver(this)
.build()
此时,将UserSensor注册到UserDriverManager(已完成)并将其注册到SensorManager之间有什么区别?
您无法直接向UserSensor
注册SensorManager
。存在Android SensorManager
API,以使客户端应用程序能够从设备内置的传感器中读取数据。 UserDriverManager
API的存在是为了让 Android Things 开发人员能够使用相同的SensorManager
API将新传感器添加到您可能希望在代码中其他位置读取的系统。
换句话说,您构建UserSensor
以通过UserDriverManager
将自定义传感器数据注入框架。您使用SensorManager
提取提供给框架的数据并在客户端应用程序中使用它。
是否有任何阻止它出现在传感器列表中的内容?
在传感器回调触发后,您应该能够使用SensorManager.getDynamicSensorList()
(与getSensorList()
方法不同)进行测试。
我是否需要等到传感器“准备就绪”,就像使用sensorManager.registerDynamicSensorCallback一样?
动态回调告诉您新驱动程序何时已成功注册到框架。在调用onDynamicSensorConnected()
之前,您将无法附加侦听器或查询传感器本身。