Android Things:用户驱动-传感器

一、传感器简介

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

二、使用步骤

要实现我们自己的传感器驱动,有如下步骤:
1. 继承UserSensorDriver类并且覆盖read():

  • 当监听器被注册用于传感器更新,框架定期轮询驱动程序。为了响应轮询请求新数据,继承UserSensorDriver类并且覆盖read()方法。每次调用读应该返回一个新的usersensorreading包含当前的传感器数据。
  • 框架可能在驱动没有产生传感器读取数据的时候调用read()方法。当这个发生的时候,你的驱动将会抛出一个IOException。
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个
  • 杜邦线(母对公,公对公) 若干

2. 搭建电路

《Android Things:用户驱动-传感器》 电路图

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. 运行结果
按照上面的电路图,搭建电路如下:

《Android Things:用户驱动-传感器》 搭建电路

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

《Android Things:用户驱动-传感器》 显示温度

1.抛弃各种找元器件的烦恼,来“1024工场”旗舰店,一次性买到你所想要的:树莓派套装—专为Android Things打造。

《Android Things:用户驱动-传感器》 树莓派套装

电脑用户,点击如下链接进入淘宝宝贝页面:

https://item.taobao.com/item.htm?spm=686.1000925.0.0.3f11c9ed68fPu7&id=549263158263

手机用户,打开淘宝客户端扫描二维码:

《Android Things:用户驱动-传感器》 宝贝二维码

2.完整和持续更新的《使用Android打开物联网开发大门——Andoid Thigns开发》文档,欢迎大家阅读!

https://www.kancloud.cn/workshop1024/android_things_develop/360773

《Android Things:用户驱动-传感器》 这里写图片描述

3.新技术,新未来!欢迎大家关注“1024工场”微信服务号,时刻关注我们的最新的技术讯息。(甭客气!尽情的扫描或者长按!)

《Android Things:用户驱动-传感器》 服务号

4.加入“Android Things开发”QQ讨论群,一起学习一起Hi。(甭客气!尽情的扫描或者长按!)

《Android Things:用户驱动-传感器》 qq群

    原文作者:1024工场
    原文地址: https://www.jianshu.com/p/6d7d4f991d46
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞