Android
Kotlin
IoT
AndroidThings

Android Thingsの概要とKotlinでのLチカ

はじめに

Android Thingsの登場により、AndroidでもGPIOやI2C、SPI、PWMを通してセンサーやインプットをいじることができるようになりました。既存のAndroidの知識を活かしつつIoTデバイスの開発が行うことができてますし、さらにはAndroid Things Consoleを使うことでOTA(Over-The-Air)からソフトウェアのアップデートすることが可能です。Google社によるAndroidのサポートとConsoleの存在は、クラウドインフラを持たないIoTスタートアップにとっては大きなメリットになるのではないでしょうか。

今回はそんなAndroid Thingsのユースケースを調べたり、KotlinでのLチカをトライしてみたので紹介します。

Android Thingsの特徴

既存のAndroidと比べて、Android Thingsでは何が新しいでのしょうか。FaBo,incの佐々木さんのスライド "はじめてのAndroid Things"によれば、Android Thingsの特徴として以下のようなものが挙げられています。

  • Peripheral I/O APIの追加
  • User Driver APIの追加
  • Board Support Package(BSP)をGoogleが管理
  • Android Things Console

公式ページに掲載されている以下の図から分かるように、Android Thingsアプリケーションは既存のJava APIやGoogleサービスを活用しつつGPIOやI2C、SPIなどを使うことができるようになっています。

platform-architecture.png
Android Thingsの構造 - Overviewより

Realm社のページにGoogle社のDave Smithさんの分かりやすいスライドがまとめられているので、いくつか引用させていただきます。雰囲気だけでも掴んでいただけるのではないでしょうか。

04.jpg
Android Thingsのメリット

01.jpg
ユーザドライバとアプリケーションの開発はデベロッパーが行う

02.jpg
既存のAndroidがカバーするAPI

03.jpg
Android ThingsがカバーするAPI

05.jpg
Android ThingsのPeripheral I/O

Dave Smith, "Just Android Things"より引用

ユースケース

ロンドンで行われたdroidcon London 2017では、Android Thingsを使ったデバイスとして、ドローンやdrawBotと呼ばれるお絵かきロボット(デモ動画を要参考)が展示されたようです。

google-demonstrates-android-things-in-action-at-droidcon-uk-electronics-weekly-maxresdefault.jpg
"Drones, Things and Android galore at droidcon London 2017" より

他にもHacksterというIoTのレシピサイトで検索すると面白そうなものが出てきます。いくつか取り上げてみますと、

img_20171009_125629_qpzUZCMYEc.jpg
"Android Things Word Clock"より引用

1-r0lzm9zq58j5fiaax5owkw_Hbnx9AyoMZ.jpeg
"BrailleBox - Braille News Reader"より引用

日本国内の動向としては、富士通とNXPが共同でAndroid Thingsを使ったIoT開発ソリューリョンの提供を2018年から開始するというものがあるようです。

参考:

使用したハードウェア

Android Thingsを動かすことができるハードウェアはこちらから確認することができます。お馴染みのRaspberry Pi 3も使うことができますが、今回は開発用ボードPICO-PI-IMX7-STARTKIT
NXP Pico i.MX7Dを使用しました。


PICO-PI-IMX7-STARTKIT-RAINBOW-HAT - Tech Nexionより引用

PICO-PI-IMX7-STARTKIT
NXP Pico i.MX7D


題材

Android Thingsの公式チュートリアルBuilding Your First Deviceの内容を総合して、ボタンが押されたらLEDの点灯または消灯を行うアプリケーションを実装してみます。

デモ

demo2-compressor.gif

Android Studio 3

Android Studio 2.xではAndroid Thingsのウィザード画面がないので、Android Studio 3をインストールしましょう。

https://developer.android.com/studio/index.html?hl=ja

プロジェクトの準備

通常のAndroidアプリのプロジェクトと同様に、ウィザード画面に進みます。

今回はせっかくAndroid Studio 3.0からウィザード画面からオプションとしてKotlinを選択できるようになったので使ってみましょう。アプリ名を入れて"Include Kotlin Support"にチェックを入れます。

ttt01.jpg

次に"Android Things"にチェックを入れます。APIレベルは26にしました。

ttt02.jpg

"Android Things Empty Activity"を選択します。

ttt03.jpg

"Finish"をクリックします。

ttt04.jpg

Hello, World!

はじめに以下のようなプログラムを動かしてみます。

  • ハードウェアやボードの情報などを出力する
  • GPIO/SPI/PWMなどのピン名を出力する(ここで表示された文字列を使って、ピンを扱います)
import android.app.Activity
import android.os.Build
import android.os.Bundle
import android.util.Log
import com.google.android.things.pio.PeripheralManagerService

class MainActivity : Activity() {
    private val TAG = "MainActivity"
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d(TAG, "BOARD:" + Build.BOARD)
        Log.d(TAG, "DEVICE:" + Build.DEVICE)
        Log.d(TAG, "BRAND:" + Build.BRAND)
        Log.d(TAG, "PRODUCT:" + Build.PRODUCT)
        Log.d(TAG, "CPU_ABI2:" + Build.CPU_ABI2)
        Log.d(TAG, "HARDWARE:" + Build.HARDWARE)
        val manager = PeripheralManagerService()
        Log.d(TAG, "GPIO:" + manager.gpioList.toString())
        Log.d(TAG, "PWM:" + manager.pwmList.toString())
        Log.d(TAG, "I2C:" + manager.i2cBusList.toString())
        Log.d(TAG, "SPI:" + manager.spiBusList.toString())
        Log.d(TAG, "UART:" + manager.uartDeviceList.toString())
        Log.d(TAG, "I2S:" + manager.i2sDeviceList.toString())
    }
}

実行結果 :

D/MainActivity: BOARD:imx7d
D/MainActivity: DEVICE:imx7d_pico
D/MainActivity: BRAND:Things
D/MainActivity: PRODUCT:iot_imx7d_pico
D/MainActivity: CPU_ABI2:armeabi
D/MainActivity: HARDWARE:imx7d
D/MainActivity: GPIO:[GPIO_10, GPIO_128, GPIO_172, GPIO_173, GPIO_174, GPIO_175, GPIO_32, GPIO_33, GPIO_34, GPIO_35, GPIO_37, GPIO_39]
D/MainActivity: PWM:[PWM1, PWM2]
D/MainActivity: I2C:[I2C1]
D/MainActivity: SPI:[SPI3.0, SPI3.1]
D/MainActivity: UART:[UART6]
D/MainActivity: I2S:[I2S3]

ピン配置

ではさっそくLチカのプログラムを作っていきます。まずはボードにピンを配置していきましょう。

以下の図では、RaspberryPi 3のものですが、NXP Pico i.MX7Dに置き換えてください。

ボード側のピン番号 Android Things側のピン名
01(3.3V)
06(GND)
31(GPIO06) GPIO_34
40(GPIO21) GPIO_174

LED_Button.png

Lチカのソースコード

import android.app.Activity
import android.os.Bundle
import android.os.Handler
import android.util.Log
import com.google.android.things.pio.PeripheralManagerService
import com.google.android.things.pio.Gpio
import java.io.IOException
import com.google.android.things.pio.GpioCallback

class MainActivity : Activity() {
    private val TAG = "MainActivity"
    private val LED_PIN_NAME = "GPIO_34"
    private val BUTTON_PIN_NAME = "GPIO_174"
    private lateinit var mLedGpio: Gpio
    private lateinit var mButtonGpio: Gpio

    // Callback for button
    private val mCallback = object : GpioCallback() {
        override fun onGpioEdge(gpio: Gpio?): Boolean {
            Log.i(TAG, "GPIO changed, button pressed")
            val mLedGpio = mLedGpio ?: return false
            try {
                mLedGpio.value = !mLedGpio.value
            } catch (e: IOException) {
                Log.e(TAG, "Error on PeripheralIO API", e)
            }

            return true
        }
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val service = PeripheralManagerService()
        Log.d(TAG, "Available GPIO: " + service.gpioList)
        try {
            // Setup LED
            mLedGpio = service.openGpio(LED_PIN_NAME)
            mLedGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW)
            mLedGpio.value = false
            Log.i(TAG, "Setup LED pin")
            // Setup Button
            mButtonGpio = service.openGpio(BUTTON_PIN_NAME)
            mButtonGpio.setDirection(Gpio.DIRECTION_IN)
            mButtonGpio.setEdgeTriggerType(Gpio.EDGE_FALLING)
            mButtonGpio.registerGpioCallback(mCallback)
            Log.i(TAG, "Setup Button pin")
        } catch (e: IOException) {
            Log.e(TAG, "Error on PeripheralIO API", e)
        }
    }
    override fun onDestroy() {
        super.onDestroy()
        mButtonGpio.unregisterGpioCallback(mCallback)
        try {
            mLedGpio.close()
            mButtonGpio.close()
        } catch (e: IOException) {
            Log.e(TAG, "Error on PeripheralIO API", e)
        }
    }
}

実行すると、上のほうであげたデモのように動くと思います。

参考資料

おわりに

Androidの延長としてIoTにチャレンジできるのはとても魅力的ではないでしょうか。Android Oreo(v8.1)ではAndroid NN APIも控えています。機械学習や深層学習も巻き込んでIoTデバイスの開発はますます面白くなってくると思われます。

次はOTA(Over-The-Air)やFireBaseとの連携にトライしてみたいです。