2017-05-24 48 views
0

我正在嘗試爲標準HC-SR04超聲波傳感器創建Android Things驅動程序。我相信我已經得到正確的事件序列:see footer,但一直無法將其註冊爲UserSensor。Android Things UserSensor.Builder - 無法創建距離傳感器驅動程序

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:傳感器或listener爲null」(因爲空值不應該在儘可能多的潛行這甚至在科特林更令人驚訝)


我的傳感器/ 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(
          [email protected], 
          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

除非我讀錯了你的代碼。它看起來像'HCSR04'不擴展'服務'?它在示例中執行https://developer.android.com/things/sdk/drivers/sensors.html – Blundell

回答

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() 

在這一點上,就是與UserDriverManager(完成)註冊UserSensor,並與註冊的SensorManager它有什麼區別?

您無法直接註冊UserSensorSensorManager。 Android SensorManager API的存在使客戶端應用程序能夠讀取內置於設備中的傳感器的數據。 UserDriverManager API的存在使Android Things開發人員能夠使用相同的SensorManager API將新傳感器添加到系統中,您可能想要在代碼的其他位置讀取它們。

換句話說,你建立一個UserSensor來通過UserDriverManager將你的自定義傳感器數據注入框架。您使用SensorManager來提取提供給框架的數據並將其用於客戶端應用程序。

是否有任何東西阻止它在傳感器列表中顯示?

你應該能夠測試此使用SensorManager.getDynamicSensorList()(不一樣的getSensorList()方法)的傳感器觸發回調之後。

我是否需要等到sensorManager.registerDynamicSensorCallback的傳感器「準備就緒」?

動態回調會告訴您新驅動程序何時成功註冊到框架。在調用onDynamicSensorConnected()之前,您將無法附加偵聽器或查詢傳感器本身。

+0

這很有道理,但看起來很尷尬:我需要:上下文 - > SensorManager - > registerDynamicSensorCallback - > onDynamicSensorConnected - > sensorManager.registerListener - > sensorEventListener - > onSensorChanged - >我真的在哪裏使用新的範圍? –

+0

不確定「新範圍」是什麼意思,但如果您正在註冊傳感器驅動程序並從代碼中的相同位置使用它,則這是一般流程。您通常不會將任何代碼放入UserSensorDriver本身。該代碼將存在於嘗試使用該驅動程序的應用程序中。 – Devunwired

相關問題