Android Things 开发入门

本文由玉刚说写作平台提供写作赞助,版权归玉刚说微信公众号所有
原作者:AndroFarmer
版权声明:未经玉刚说许可,不得以任何形式转载

Android Tings 是什么

android things(后面正文内容简称ats)是一个物联网平台,他基于android,并做了相当多的改造以适合在一些低配置的物联网设备上运行,同时它又是安卓,因为其保留了绝大部分android framework的功能。因此借助ats平台我们不需要了解嵌入式(准确的说还是需要了解一些的)相关的知识就可以开发出一系列智能硬件产品

Android Tings 能做什么

要说明这个问题,我们不如从反面说明,ats不能做什么。
先看张ats的框架图:


从图上可以看出,ats是在标准安卓的framework层上增加了things support library,同时为了保证嵌入式性能以及根据嵌入式设备的特点的需要,精简和修改了部分标准framework层的东西。
那么具体ats不能做什么,除了下图中的这些标准android的特性不支持外,其他都支持(gms除外,因为ats的gms框架是定制的跟标准android不通用):


可以看出ats对标准android framework的支持还是挺多的,这也就保证了app开发者们可以很轻松的做ats的开发。

开发Android Tings的硬件条件

由于android studio 并未有提供ats的模拟器,所以我们必须要有一个能刷ats系统的硬件(比如树莓派)才行,同时为了还需要一些传感器、电阻、电子按钮、面包板、led灯等一些列配套外设,因为iot(物联网)的开发很多时候都是对硬件的操作,有了这些外设才能更好的去实验一些demo。
下面贴出我购买的硬件全家桶套装:

树莓派针脚说明

ats的开发很多时候都是操作硬件,所以我们就有必要去研究,如何去操作外设设备,一个很重要的方法就是通过外设接口去操作。
看下图:



第一张图画红线的地方,按照针脚一对一的顺序分别对应下面的这张图说明。
看到这可能有些晕,这这是什么鬼,当然电子工程相关专业的应该一看就懂,没错这就是总线。

何为总线

总线,总线,就是总让你陷进去

请原谅我不会搞笑还胡说的坏毛病。
树莓派支持的总线类型:GPIO,I2C,I2S,SPI,PWM,UART
关于总线我也不是专业的。以我的理解就是为了控制不同的硬件设备,而对电信号做不同的处理而划分的标准。这里我们先混个脸熟,后面用的最多的是GPIO,也就是以名称BCM开通的针脚,后面我们会通过名称去控制这个针脚上的设备。
关于总线详细的介绍,大家可以参考下这篇文章:
https://blog.csdn.net/haima1998/article/details/18729929

如何刷写ats到树莓派开发板上

关于这方面的介绍,网上还是挺多的,我搜了一下最不缺的就是这类文章,所以这里就不做详细介绍了,简单介绍下
步骤:

  1. 进入android things console,创建属于自己硬件的rom,这是google的云管理平台(在这里可以创建硬件设备的rom,发布ota更新等)
    地址为:https://partner.android.com/things/console/

  2. 通过软件刷写rom到内存卡上,这里推荐使用Etcher这个软件

    这个软件的使用还是很简单的,一键式的。

  3. 刷写完成后通电,插入显示器,不出什么意外就可以正常开机了
    至此刷写rom的工作就完成了

  4. 这里推荐另一种更简便的方式:使用官方提供工具的:android-things-setup-utility
    下载地址:https://partner.android.com/things/console/#/tools
    解压完了以后如图:

    可以根据自己的平台选择操作。

如何操作Android Things

由于物联网设配的特殊性,我们没有像安卓一样的触摸屏和按键等外设来操作设备。所以我们需要通过如下两种方式去连接设备

1.通过usb转ttl设备直接连接

具体如何操作,可以自行百度

2.通过局域网连接(推荐方式)
先让ats设备连接到路由器,这里推荐连接显示器鼠标键盘可视化操作连接网络等操作,连接上显示器如下图:


WechatIMG16.jpeg

常用的adb 命令

通过这些命令我们可以更好的管理和使用ats

  1. 连接AndroidThings
    adb connect <ip-address>
  2. 断开AndroidThings
    adb disconnect <ip-address>
  3. 关机
    adb shell reboot -p
    4.卸载应用
    adb shell uninstall <applicationid>
    使用adb connect <ip-address>命令连接到ats设备后就可以像开发app一样用android studio去开发部署和调试了。

Demo展示及硬件搭建-light

这是一个操作LED让其闪烁的demo,
我们通过这个demo来介绍基本的操作硬件的方法
先看下最终效果:

硬件搭建步骤:

  1. 通过面包板串联一个电阻和一个LED灯并连接到面包板的正极
  2. 面包板的正极连接到树莓派一个GPIO总线端口
  3. LED另一个针脚通过跳线连接到树莓派的GROUND针脚上
    附上我的连接图:

至此硬件模块的搭建就完毕了。

更直观一点的参考如下官方图片:


这里需要着重说明是:Ground为地线,用来模拟零电压线,GPIO总线端口可以根据所加的电阻以及LED选择不同的电压,我这里选择的是电压3.3v名为BCM2的端口

light代码分析

public class LightActivity extends Activity {
    Handler mHandler;
    PeripheralManager mPeripheralManager;
    Gpio mLightGpio;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_light);
        mHandler = new Handler();
        mPeripheralManager = PeripheralManager.getInstance();
        try {
            mLightGpio = mPeripheralManager.openGpio("BCM2");
            mLightGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
            mHandler.post(mBlinkRunnable);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    private Runnable mBlinkRunnable = new Runnable() {
        @Override
        public void run() {
            try {
                if (mLightGpio == null)
                    return;
                mLightGpio.setValue(!mLightGpio.getValue());
                mHandler.postDelayed(mBlinkRunnable, 1000);
            } catch (IOException e) {

            }
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mLightGpio != null) {
            try {
                mLightGpio.close();
                mLightGpio = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

代码不多,就全贴上去了,下面我们分析下代码 mPeripheralManager=PeripheralManager.getInstance();
mLightGpio= mPeripheralManager.openGpio("BCM2");
我们通过PeripheralManager单例后调用openGpio方法,传入的参数为GPIO端口对应的名称,这样就拿到这个端口控制对象Gpio的一个实例mLightGpio。
mLightGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_HIGH);
这句话代码有两个作用:1.设置电平方向为输出方向。2设置初始电平为高电平并立即激活。
这句代码执行后,LED会变为常亮状态
我们还可以通过以下三行代码实现跟上面一句同样的效果:
//设置电平方向为输出方向,设置初始电平为低电平并立即激活
mLightGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
//设置激活状态为高电平
mLightGpio.setActiveType(Gpio.ACTIVE_HIGH)
//进行激活
mLightGpio.setValue(true);
在mBlinkRunnable中通过 mLightGpio.setValue(!mLightGpio.getValue());来循环
改变电平的激活状态来实现LED的闪烁。
至此LED就可以blingbling的闪了。

最后看下ats项目和标准安卓有和区别
主要区别有两点:

  1. ats项目权限不需要用户动态授权,直接在manifest中声名即可,如访问GPIO总线端口以及下面需要讲到的注册用户驱动所需要的权限
<uses-permission android:name="com.google.android.things.permission.USE_PERIPHERAL_IO"/>
<uses-permission android:name="com.google.android.things.permission.MANAGE_INPUT_DRIVERS" />
  1. ats项目部署到硬件后可以设置其意外关闭重启和开机自启动,这样可以保证物联网设备的高可用状态,不至于程序崩溃导致设备无法使用
    具体步骤只需要在入口Activity加入如下intent-filter:
 <intent-filter>
     <action android:name="android.intent.action.MAIN"/>
     <category android:name="android.intent.category.HOME"/>
     <category android:name="android.intent.category.DEFAULT"/>
 </intent-filter>

用户驱动-userdriver

所谓用户驱动就是ats允许你把相应的硬件的电信号转化成系统事件,比如按钮的点按事件注册成系统的键盘按键事件,温度感应器的电信号注册成系统已存在的感应器事件,这样各个组件都可以很方便的使用标准的framework api去操作硬件了。

举个栗子

本例展现的内容是把按钮的点按事件电信号注册成键盘的key事件,这样按钮就变成一个键盘了,可以点击和长按。注册成系统事件后可以在应用程序的各个组件中进行使用了。
演示效果:

硬件安装图:

看下代码:

package com.androfarmer.button;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.view.KeyEvent;

import com.google.android.things.pio.Gpio;
import com.google.android.things.pio.GpioCallback;
import com.google.android.things.pio.PeripheralManager;
import com.google.android.things.userdriver.UserDriverManager;
import com.google.android.things.userdriver.input.InputDriver;
import com.google.android.things.userdriver.input.InputDriverEvent;
import java.io.IOException;

public class KeyCodeDriverService extends Service {

    private InputDriver mDriver;
    private Gpio mButtonGpio;
    private static final int KEY_CODE = KeyEvent.KEYCODE_A;

    @Override
    public void onCreate() {
        super.onCreate();

        //创建输入驱动,并设置驱动的基本信息
        mDriver = new InputDriver.Builder()
                .setName("Button2Keyboard")
                .setSupportedKeys(new int[]{KEY_CODE})
                .build();

        // 通过 UserDriverManager注册上面创建的驱动
        UserDriverManager manager = UserDriverManager.getInstance();
        manager.registerInputDriver(mDriver);

        PeripheralManager peripheralManager = PeripheralManager.getInstance();
        try {
            mButtonGpio = peripheralManager.openGpio("BCM21");
           //设置电平方向为输入
            mButtonGpio.setDirection(Gpio.DIRECTION_IN);
            //设置激活类型
            mButtonGpio.setActiveType(Gpio.ACTIVE_LOW);
            //设置监听事件为:电平中断变化事件,Gpio.EDGE_BOTH意味着电平从低到高中断以及从高到低中断都会触发回调
            mButtonGpio.setEdgeTriggerType(Gpio.EDGE_BOTH);
            //设置电平变化的监听器
            mButtonGpio.registerGpioCallback(new GpioCallback() {
                @Override
                public boolean onGpioEdge(Gpio gpio) {
                    try {
                        Log.d("-------------button",gpio.getValue()+"");
                        boolean pressed=gpio.getValue();
                        InputDriverEvent event = new InputDriverEvent();
                        event.setKeyPressed(KEY_CODE, pressed);
                        mDriver.emit(event);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    //返回true代表一直监听,false代表监听一次
                    return true;
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



    @Override
    public void onDestroy() {
        super.onDestroy();
        //接触注册
        UserDriverManager manager = UserDriverManager.getInstance();
        manager.unregisterInputDriver(mDriver);
        //关闭gpio端口
        try {
            mButtonGpio.close();
            mButtonGpio = null;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

代码的注释写的已经很详细了,就不过多解释了。
这里简要介绍下步骤

  1. 通过InputDriver创建驱动基本信息对象
  2. 通过UserDriverManager注册驱动
  3. PeripheralManager处理具体外设硬件的电信号
  4. 通过InputDriver的emit方法将InputDriverEvent事件发射出去,这样系统各个组件就能相应这个事件了
  5. 别忘了不再使用时解除注册和关闭端口

用户驱动类型

主要分为四类:

  1. Location 位置驱动
  2. Input 用户输入事件驱动
  3. Sensor 传感器驱动
  4. LoWPAN

对用户驱动的进一步说明

ats的很多场景我们可以像开发app一样,对于做过android开发的同学们来说这很easy,但是用户驱动这个概念我们可能第一次听说。ats的设计是模块化的,一个ats硬件板只会包含基础的硬件模块如:网络模块,cpu,内存等。我们拿到这个运行ats系统的基础板后,如果要开发成具体的物联网产品,可能需要接外设传感器去实现具体功能:比如温度传感器,烟雾报警器等。
市面上传感器门类复杂,如果我们开发时将业务逻辑与硬件传感器的操作杂糅在一起,很显然这样的话我们的代码很脆弱并且不具备可移植性,换个同类别的其他型号传感器就无法使用了。因此用户驱动的出现很好的解决了这个问题,不管外设硬件同类别的型号有多少种,我们只需要写相应的用户驱动将其注册成framework已经实现的传感器事件,这样业务逻辑只需要跟标准的framework api打交道,而不用管具体用了哪一种传感器。

附上一个开源项目,这里面实现了很多市面上普遍使用的硬件的用户驱动
https://github.com/androidthings/contrib-drivers
有兴趣的同学可以去研究下不同类型的用户驱动是如何编写

ps:本文很多内容和案例来自于官网,更多案例请查看
https://developer.android.com/samples/?technology=iot&language=java

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,717评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,501评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,311评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,417评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,500评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,538评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,557评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,310评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,759评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,065评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,233评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,909评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,548评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,172评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,420评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,103评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,098评论 2 352

推荐阅读更多精彩内容