一、传感器简介


Android传感器框架支持多种传感器类型来测量物理环境的状况,并且从应用程序读取原始数据。使用传感器驱动,你的应用可以扩展框架,并且添加新的通过Peripheral I/O连接的传感器设备;
和Android内置的传感器一样,来自这些传感器的数据通过相同的SensorManager API进行分发。你的应用可以实现一个驱动程序来连接一个已知类型的新传感器,如加速度计,或者一个Android目前没有定义的传感器类型,如血糖传感器。

二、使用步骤


要实现我们自己的传感器驱动,有如下步骤:

  1. 继承UserSensorDriver类并且覆盖read():
    • 当监听器被注册用于传感器更新,框架定期轮询驱动程序。为了响应轮询请求新数据,继承UserSensorDriver类并且覆盖read()方法。每次调用读应该返回一个新的usersensorreading包含当前的传感器数据。
    • 框架可能在驱动没有产生传感器读取数据的时候调用read()方法。当这个发生的时候,你的驱动将会抛出一个IOException。
      注意: 更多关于已知传感器类型的数据格式信息,请查阅Sensor event values。

      UserSensorDriver mDriver = new UserSensorDriver() {
      // Sensor data values
      float x, y, z;
      @Override
      public UserSensorReading read() {
         try {
             // ...read the sensor hardware...
      
             // Return a new reading
             return new UserSensorReading(new float[]{x, y, z});
         } (catch Exception e) {
             // Error occurred reading the sensor hardware
             throw new IOException("Unable to read sensor");
         }
      }
      };
    • 如果您的传感器支持低功耗或睡眠模式,覆盖你的驱动实现的setEnabled()方法来激活它们。框架调用这个方法与为这传感器应该加紧提供读数,或者为节省电力而休眠;
      UserSensorDriver mDriver = new UserSensorDriver() {
      ...
      // Called by the framework to toggle low power modes
      @Override
      public void setEnabled(boolean enabled) {
         if (enabled) {
             // Exit low power mode
         } else {
             // Enter low power mode
         }
      }
      };

      注意:没有低功耗模式的传感器仍然可以使用此回调来增加或减少数据的报告频率以管理功耗;

  2. 描述传感器:
    向Android框架添加一个新的传感器驱动:

    • 使用UserSensor.Builder来声明传感器的类型。对于大多数app,传感器类型应该匹配Android现有的已知传感器类型之一。
    • 提供传感器名称和你的驱动供应商名称。
    • 向Builder应用你的传感器的范围,分辨率,更新频率(延迟),和电源要求(如果有的话)。这些值将会帮助框架根据SensorManager接收到的请求选择最好的传感器。
    • 使用setDriver()方法设置你的UserSensorDriver实现。
      UserSensor accelerometer = UserSensor.builder()
         .setName("GroveAccelerometer")
         .setVendor("Seeed")
         .setType(Sensor.TYPE_ACCELEROMETER)
         .setDriver(mDriver)
         .build();
    • 当实现了一个Android没有定义的传感器类型时:
      • 在builder中使用setCustomType()替代setType();
      • 提供一个数字传感器类型,是TYPE_DEVICE_PRIVATE_BASE或者更大;
      • 包含一个传感器类型的唯一字符串名称。这个名字应该是系统范围唯一的,因此建议使用反向符号;
      • 包含传感器的报告模式;
      UserSensor custom = UserSensor.builder()
         .setName("MySensor")
         .setVendor("MyCompany")
         .setCustomType(Sensor.TYPE_DEVICE_PRIVATE_BASE,
                 "com.example.mysensor",
                 Sensor.REPORTING_MODE_CONTINUOUS)
         .setDriver(mDriver)
         .build();
  3. 注册传感器
    • 通过使用UserDriverManager注册它,将你的新的传感器连接到框架上:
      public class SensorDriverService extends Service {
      UserSensor mAccelerometer;
      @Override
      public void onCreate() {
         super.onCreate();
         ...
         UserDriverManager manager = UserDriverManager.getManager();
      
         // Create a new driver implementation
         mAccelerometer = ...;
         // Register the new driver with the framework
         manager.registerSensor(mAccelerometer);
      }
      
      @Override
      public void onDestroy() {
         super.onDestroy();
         ...
         UserDriverManager manager = UserDriverManager.getManager();
         // Unregister the driver when finished
         manager.unregisterSensor(mAccelerometer);
      }
      }
    • 随着驱动正确的被注册,应用程序使用现在的Android Sensor framework service可以从相关的设备获取更新。
    • 在传感器对客户有效之前,注册的过程可能需要花费一些时间。对一个用户传感器感兴趣的应用应该注册一个DynamicSensorCallback,当它在注册传感器读取监听器之前有效时被通知:
      public class SensorDriverService extends Service implements SensorEventListener {
      private SensorManager mSensorManager;
      
      @Override
      public void onCreate() {
         super.onCreate();
         ...
         mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
         mSensorManager.registerDynamicSensorCallback(new SensorCallback());
      }
      
      @Override
      public void onSensorChanged(SensorEvent event) {
         ...
      }
      
      @Override
      public void onAccuracyChanged(Sensor sensor, int accuracy) {
         ...
      }
      
      // Listen for registration events from the sensor driver
      private class SensorCallback extends SensorManager.DynamicSensorCallback {
         @Override
         public void onDynamicSensorConnected(Sensor sensor) {
             Log.i(TAG, sensor.getName() + " has been connected");
      
             // Begin listening for sensor readings
             mSensorManager.registerListener(SensorDriverService.this, sensor,
                     SensorManager.SENSOR_DELAY_NORMAL);
         }
      
         @Override
         public void onDynamicSensorDisconnected(Sensor sensor) {
             Log.i(TAG, sensor.getName() + " has been disconnected");
      
             // Stop receiving sensor readings
             mSensorManager.unregisterListener(SensorDriverService.this);
         }
      }
      }

三、案例展示


下面我们就以如何实现HCSR40超声波传感器为例,为大家演示如何实现自己的传感器驱动。

  1. 硬件要求
    • 树莓派3开发板 1块
    • 面板板 1块
    • HCSR40超声波传感器 1个
    • 杜邦线(母对公,公对公) 若干

      广告时间咯:经过我们小伙伴的不懈努力和精心筹备,容重推出了我们的首款产品树莓派套装—专为Android Things打造(链接可以直接点击进入噢)。

  2. 搭建电路

    电路图
  3. 代码编写
    SensorDemo\app\src\main\java\com\chengxiang\sensordemo\Hcsr04.java

    public class Hcsr04 implements AutoCloseable {
     private static final String TAG = Hcsr04.class.getSimpleName();
     private Gpio trigGpio, echoGpio;
     private Handler handler = new Handler();
     private static final int pauseInMicro = 10;
    
     private long startTime, ellapsedTime;
     private float distanceInCm;
    
     public Hcsr04(String trigPin, String echoPin) throws IOException {
         try {
             PeripheralManagerService service = new PeripheralManagerService();
             trigGpio = service.openGpio(trigPin);
             echoGpio = service.openGpio(echoPin);
             configureGpio(trigGpio, echoGpio);
         } catch (IOException e) {
             throw e;
         }
     }
    
     @Override
     public void close() throws Exception {
         handler.removeCallbacks(startTrigger);
         try {
             trigGpio.close();
             echoGpio.close();
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
    
     private void configureGpio(Gpio trigGpio, Gpio echoGpio) throws IOException {
         try {
             trigGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
             echoGpio.setDirection(Gpio.DIRECTION_IN);
    
             trigGpio.setActiveType(Gpio.ACTIVE_HIGH);
             echoGpio.setActiveType(Gpio.ACTIVE_HIGH);
             echoGpio.setEdgeTriggerType(Gpio.EDGE_BOTH);
             handler.post(startTrigger);
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
    
     private Runnable startTrigger = new Runnable() {
         @Override
         public void run() {
             try {
                 trigGpio.setValue(!trigGpio.getValue());
                 busyWaitMicros(pauseInMicro);
                 trigGpio.setValue(!trigGpio.getValue());
                 while (!echoGpio.getValue())
                     startTime = System.nanoTime();
                 while (echoGpio.getValue())
                     ellapsedTime = System.nanoTime() - startTime;
                 ellapsedTime = TimeUnit.NANOSECONDS.toMicros(ellapsedTime);
                 distanceInCm = ellapsedTime / 58;
                 Log.i(TAG,"distanceInCm = " + distanceInCm);
                 handler.postDelayed(startTrigger, 1000);
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
     };
    
     public float[] getProximityDistance() {
         return new float[]{distanceInCm};
     }
    
     public static void busyWaitMicros(long micros) {
         long waitUntil = System.nanoTime() + (micros * 1_000);
         while (waitUntil > System.nanoTime()) {
             ;
         }
     }
    }

    SensorDemo\app\src\main\java\com\chengxiang\sensordemo\Hcsr04UltrasonicDriver.java

    public class Hcsr04UltrasonicDriver implements AutoCloseable {
    
     private static final String TAG = Hcsr04UltrasonicDriver.class.getSimpleName();
     private static final int DRIVER_VERSION = 1;
     private static final String DRIVER_NAME = "HC-SR04 Ultrasonic Sensor";
    
     private UserSensor userSensor;
     private Hcsr04 device;
    
     public Hcsr04UltrasonicDriver(String trigPin, String echoPin) throws IOException {
         device = new Hcsr04(trigPin, echoPin);
     }
    
     @Override
     public void close() throws Exception {
         unregister();
         if (device != null) {
             try {
                 device.close();
             } finally {
                 device = null;
             }
         }
     }
    
     public void register() {
         if (device == null) {
             throw new IllegalStateException("cannot registered closed driver");
         }
         if (userSensor == null) {
             userSensor = build(device);
             UserDriverManager.getManager().registerSensor(userSensor);
         }
     }
    
     public void unregister() {
         if (userSensor != null) {
             UserDriverManager.getManager().unregisterSensor(userSensor);
             userSensor = null;
         }
     }
    
     private static UserSensor build(final Hcsr04 hcsr04) {
         return UserSensor.builder()
                 .setName(DRIVER_NAME)
                 .setVersion(DRIVER_VERSION)
                 .setType(Sensor.TYPE_PROXIMITY)
                 .setDriver(new UserSensorDriver() {
                     @Override
                     public UserSensorReading read() throws IOException {
                         float[] distance = hcsr04.getProximityDistance();
                         return new UserSensorReading(distance);
                     }
                 })
                 .build();
     }
    }

    SensorDemo\app\src\main\java\com\chengxiang\sensordemo\MainActivity.java

    public class MainActivity extends AppCompatActivity implements SensorEventListener {
     private static final String TAG = "Sensor";
    
     private TextView textView;
     private Hcsr04UltrasonicDriver hcsr04UltrasonicDriver;
     private SensorManager mSensorManager;
    
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         textView = (TextView) findViewById(R.id.textview1);
         try {
             hcsr04UltrasonicDriver = new Hcsr04UltrasonicDriver("BCM20", "BCM21");
    
             mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
             mSensorManager.registerDynamicSensorCallback(new Hcsr04SensorCallback());
    
             hcsr04UltrasonicDriver.register();
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
    
     @Override
     public void onSensorChanged(SensorEvent sensorEvent) {
         textView.setText("distanceInCm = " + sensorEvent.values[0] + "cm");
     }
    
     @Override
     public void onAccuracyChanged(Sensor sensor, int i) {
    
     }
    
     private class Hcsr04SensorCallback extends SensorManager.DynamicSensorCallback {
         @Override
         public void onDynamicSensorConnected(Sensor sensor) {
             Log.i(TAG, sensor.getName() + " has been connected");
             mSensorManager.registerListener(MainActivity.this, sensor, SensorManager.SENSOR_DELAY_NORMAL);
         }
    
         @Override
         public void onDynamicSensorDisconnected(Sensor sensor) {
             Log.i(TAG, sensor.getName() + " has been disconnected");
             mSensorManager.unregisterListener(MainActivity.this);
         }
     }
    }
  4. 运行结果
    按照上面的电路图,搭建电路如下:

搭建电路

程序运行后,通过传感器检测到障碍物距离,显示在屏幕上:

显示温度

来自http://www.jianshu.com/p/6d7d4f991d46

Android Things:用户驱动-传感器

发表评论

电子邮件地址不会被公开。