Android Things UserSensor.Builder – не удалось создать драйвер датчика расстояния

Я пытаюсь создать драйвер Android Things для стандартного ультразвукового датчика HC-SR04. Я считаю, что последовательность событий правильная: см. Нижний колонтитул , но не удалось зарегистрировать его как 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, потому что нули не должны проникать так же)


Мой датчик / также суть :

 /** 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() } } 

Одна вещь, которую вы можете рассмотреть, это изменение типа датчика. 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 . API Android SensorManager существует, чтобы позволить клиентским приложениям считывать данные с датчиков, встроенных в устройство. API UserDriverManager существует, чтобы позволить разработчикам Android Things добавлять в систему новые датчики, которые вы, возможно, захотите прочитать в другом месте кода, используя тот же API SensorManager .

UserSensor словами, вы UserSensor для ввода пользовательских данных датчиков в структуру через UserDriverManager . Вы используете SensorManager для извлечения данных, предоставленных в фреймворк, и использования их в клиентском приложении.

Есть ли что-то, что мешает ему появляться в списке датчиков?

Вы должны проверить это, используя SensorManager.getDynamicSensorList() (не то же самое, что и метод getSensorList() ) после срабатывания обратного вызова датчика.

Нужно ли ждать, пока датчик «готов», как с sensorManager.registerDynamicSensorCallback?

Динамический обратный вызов сообщает вам, когда новый драйвер был успешно зарегистрирован в фреймворке. Вы не сможете подключить слушателя или запросить сам датчик, пока не onDynamicSensorConnected() .