モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

目次目次を開く/閉じる

Android Things による LED 点灯 (Raspberry Pi 3)

モーダルを閉じる

ステッカーを選択してください

お支払い手続きへ
モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2017/08/18
最終更新最終更新
2024/12/27
記事区分記事区分
一般公開

電子工作や製品のプロトタイピング (例『地球規模で遠隔操作できるブルドーザー』) で利用される Raspberry Pi 3 について、 Android Things アプリケーションを開発できます。

本ページでは、簡単な例として LED を点灯させるアプリケーションを扱います。より実用的なアプリケーションを開発する際には GitHub (Android Things) のサンプルコードを参考にします。

関連する公式ドキュメント

Raspberry Pi 3 で Android を動かして Wi-Fi 接続

Raspberry Pi 3 に Android Things イメージを書き込み、Wi-Fi 設定を行う方法は環境によって異なります。公式ドキュメントにすべての場合について記載がありますが、特にここでは以下の場合を想定した例を記載します。

  • macOS から書き込む。
  • モバイル Wi-Fi ルータのためイーサネットケーブルが利用できない。
  • HDMI ディスプレイが手元にない。

必要なものは以下のとおりです。

  • 本体
    • Raspberry Pi 3
    • Raspberry Pi 3 電源用 USB ケーブル
  • 書き込み先
    • microSD カード (8 GB 以上)
    • microSD カードリーダー/ライター
  • 通信ケーブル
    • USB to TTL Serial Cable (3.3v、イーサネットケーブルが利用できる場合は不要です)

Android Things イメージのダウンロード

Android Things Console に Google アカウントでログインして「CREATE A PRODUCT」ボタンをクリックします。

情報を入力します。SOM (System on Module) type は Raspberry Pi 3 を選択します。また、OEM パーティションには Bundle とよばれるアプリケーション関連ファイル一式が格納されます。

登録した Product ページ内の「CREATE BUILD CONFIGURATION」をクリックすると、ページ内下部の Build configuration list に一行追加されます。

追加された行内の Download build をクリックすると zip ファイルのダウンロードが開始されます。少々時間がかかるため、待ちます。

SD カードへの書き込み

解凍

ダウンロードした zip ファイルを解凍します。unzip コマンドではエラーが出るため、The Unarchiver (Mac OS) を利用します。約 250 MB の zip ファイル myproduct_Raspberry Pi 3_0_OIR1.170720.015_userdebug_build.zip が解凍されて 4 GB 程の iot_rpi3.img になります。

dd コマンド

8 GB 以上の microSD カードを Mac に認識させた後、デバイスの識別番号を確認します。以下の例では disk3 が microSD カードです。

$ diskutil list
/dev/disk0
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *121.3 GB   disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:          Apple_CoreStorage                         120.5 GB   disk0s2
   3:                 Apple_Boot Recovery HD             650.0 MB   disk0s3
/dev/disk1
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:                  Apple_HFS Macintosh HD           *120.1 GB   disk1
                                 Logical Volume on disk0s2
                                 XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
                                 Unencrypted
/dev/disk2
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     Apple_partition_scheme                        *20.0 MB    disk2
   1:        Apple_partition_map                         32.3 KB    disk2s1
   2:                  Apple_HFS Flash Player            20.0 MB    disk2s2
/dev/disk3
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *7.9 GB     disk3
   1:             Windows_FAT_16 RECOVERY                2.2 GB     disk3s1
   2:                      Linux                         33.6 MB    disk3s5
   3:             Windows_FAT_32 boot                    66.1 MB    disk3s6
   4:                      Linux                         5.6 GB     disk3s7

アンマウントします。

$ diskutil unmountDisk /dev/disk3
Unmount of all volumes on disk3 was successful

以下のコマンドで img を書き込みます。時間がかかるため気長に待ちます。

$ sudo dd bs=1m if=iot_rpi3.img of=/dev/rdisk3 conv=sync
4352+0 records in
4352+0 records out
4563402752 bytes transferred in 452.560177 secs (10083527 bytes/sec)

書き込みが終わると Mac からは認識できないためポップアップが表示されますが、そのまま取り出して Raspberry Pi にセットします。

シリアルデバッグコンソールによる Raspberry Pi への接続

今回、モバイル Wi-Fi ルータを利用しており、有線 LAN で Raspberry Pi に接続できない場合を想定しているため、初期の Wi-Fi パスワード設定等を別の方法で行う必要があります。ここでは、公式ドキュメントにも記載のあるシリアルデバッグコンソールを利用します。接続のためのケーブルは Amazon 等で安価に入手できます。電気街が近場にある方は実際の店舗で購入するのもよさそうです。その際、TTL 電圧レベルは 5V ではなく 3.3V のものを選択することに注意します。

デバイスドライバのインストール

OS によって USB to TTL Serial Cable のデバイスドライバをインストールする必要があります。上記 Amazon リンクのケーブルは PL2303 です。Adafruit の商品ページにドライバのインストール方法が記載されています。例えば、macOS について以下のように記載されています。

  • こちらのページ にアクセスしてドライバをダウンロードする。
  • ドライバには Prolific ChipsetSiLabs CP210X Drivers の二種類あり、どちらか分からない場合は両方インストールしておけば問題ない。
  • Prolific Chipset については macOS のバージョンによってダウンロードすべきドライバのバージョンが異なるため注意する。

ただし、これらのドライバは OS のバージョンによってはシステムのクラッシュにつながります。特に Prolific Chipset のドライバは不具合報告がなされており、以下のコマンドでドライバを削除できます。

保存場所の確認

$ kextfind -b com.prolific.driver.PL2303
/Library/Extensions/ProlificUsbSerial.kext

適当なディレクトリに移動

$ sudo mv /Library/Extensions/ProlificUsbSerial.kext ~/Desktop/

PC 再起動

$ sudo reboot

Raspberry Pi と接続するピン

以下のページの画像と見比べて作業するなどし、接続するピンを間違えて Raspberry Pi を壊さないように注意します。

黒 → GND ピン、白 → TXD ピン、緑 → RXD ピンにそれぞれ接続します。赤 (5V) は接続しません

シリアル通信

デバイスドライバのインストールに成功していれば、USB ケーブルを PC に接続すると以下のコマンドで識別子を確認できます。以下の例では /dev/tty.usbserial と表示されています。

$ ls -l /dev/tty.*
crw-rw-rw-  1 root  wheel   18,   0  8 24 02:17 /dev/tty.Bluetooth-Incoming-Port
crw-rw-rw-  1 root  wheel   18,   2  8 24 02:17 /dev/tty.Bluetooth-Modem
crw-rw-rw-  1 root  wheel   18,   4  8 24 02:31 /dev/tty.usbserial

macOS の場合、screen を利用して以下のコマンドで接続できます。何も表示されない場合はエンターキーを押してみます。

screen /dev/tty.usbserial 115200

以下のように表示されれば接続成功です。

rpi3:/ $

別ターミナルから以下のコマンドで pid を確認して終了できます。環境によってはドライバが合わず、ここで正常にデバイスを解放できない可能性があります。別のドライバをインストールするか、後述の Wi-Fi 設定を行ってしまい、シリアル通信は以降利用しないようにして回避します。

screen -ls
screen -S 1983 -X quit

Wi-Fi 認証情報の設定

以下のコマンドで Wi-Fi 認証情報を設定します。特殊な記号がパスワードに含まれる場合は passphrase64 を利用します

rpi3:/ $ am startservice -n com.google.wifisetup/.WifiSetupService -a WifiSetupService.Connect -e ssid 利用するSSID名 -e passphrase パスワード
Starting service: Intent { act=WifiSetupService.Connect cmp=com.google.wifisetup/.WifiSetupService (has extras) }

ログに Successfully connected to と記載されていることを確認します。途中で NTP に接続できたため時刻が現在時刻に変更されていることが確認できます。

rpi3:/ $ logcat -d | grep Wifi | tail
01-01 00:43:52.083   876   876 V WifiWatcher: SSID changed: "SSID_NAME"
01-01 00:43:52.083   876   893 I WifiConfigurator: Successfully connected to SSID_NAME
01-01 00:43:52.089   309   378 E WifiStateMachine: Did not find remoteAddress {192.168.179.1} in /proc/net/arp
01-01 00:43:52.112   309   378 E WifiVendorHal: getSupportedFeatureSet(l.856) failed {.code = ERROR_NOT_AVAILABLE, .description = }
01-01 00:43:52.122   309   378 D WifiNetworkAgent: NetworkAgent: Received signal strength thresholds: []
01-01 00:43:52.125   309   378 E WifiVendorHal: stopRssiMonitoring(l.2115) failed {.code = ERROR_NOT_AVAILABLE, .description = }
01-01 00:43:52.924   309   378 D WifiStateMachine: NETWORK_STATUS_UNWANTED_VALIDATION_FAILED
08-23 17:47:13.903   309   378 W AlarmManager: Unrecognized alarm listener com.android.server.wifi.WifiConfigStore$1@ad923b1
08-23 17:47:13.965   309   378 D WifiConfigStore: Writing to stores completed in 61 ms.
08-23 17:47:14.647   309   540 D WificondControl: Scan result ready event

時刻が同期されていることを確認します。

rpi3:/ $ date
Wed Aug 23 17:49:07 GMT 2017

シリアル通信中は ping コマンドを実行するために root 権限が必要です。8.8.8.8 は Google Public DNS です。

rpi3:/ $ su
rpi3:/ # ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=55 time=197 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=55 time=121 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=55 time=120 ms

ip コマンド等で IP アドレスを確認しておきます。以下の例では 192.168.179.7 がポケット Wi-Fi ネットワーク内の IP です。

rpi3:/ $ ip a s
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: sit0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1
    link/sit 0.0.0.0 brd 0.0.0.0
3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b8:27:eb:79:1e:23 brd ff:ff:ff:ff:ff:ff
    inet 192.168.179.7/24 brd 192.168.179.255 scope global wlan0
       valid_lft forever preferred_lft forever
    inet6 fe80::ba27:ebff:fe79:1e23/64 scope link 
       valid_lft forever preferred_lft forever
4: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
    link/ether b8:27:eb:2c:4b:76 brd ff:ff:ff:ff:ff:ff

Wi-Fi 設定をリセットするためには以下のコマンドを実行します。

am startservice -n com.google.wifisetup/.WifiSetupService -a WifiSetupService.Reset

adb コマンドによる接続

Wi-Fi で無線接続できるようになれば、以降はシリアルデバイスコンソールを利用せずに adb コマンドを利用して Raspberry Pi に接続できます。

Android Studio で SDK と同封されてインストールされる adb (Android Debug Bridge) コマンドを利用すると Android 端末に shell で接続できます。「Preferences → Appearance & Behavior → System Settings → Android SDK → Android SDK Location」で SDK の場所を確認して PATH を通しておきます。

$ /Users/username/Library/Android/sdk/platform-tools/adb connect 192.168.179.7
connected to 192.168.179.7:5555

$ /Users/username/Library/Android/sdk/platform-tools/adb devices
List of devices attached
192.168.179.7:5555      device

$ /Users/username/Library/Android/sdk/platform-tools/adb shell

Android Studio で LED 点灯アプリケーションを開発

SDK tools および SDK のアップデート

Android Studio をインストールします。その後、インストールされている「SDK tools」と「SDK Platforms」を SDK Manager でアップデートします

空プロジェクトを作成

新規プロジェクトを作成します。

アプリケーション名を入力します。

2017/08/19 現在のところ Android Things 専用の項目はなく、Phone and Tablet を選択します。

Empty Activity を選択します。

Activity Name は MainActivity のままでも問題ありませんが、ここでは Android Things のドキュメントで散見される HomeActivity に変更しています。また、UI を持たないアプリケーション開発を想定しているため Layout File 生成のチェックは外します。更に、モバイルアプリケーション開発で必要になる後方互換性は不要であり Homeactivity は AppCompatActivity ではなく Activity を直接継承すればよいため二つ目のチェックも外しておきます。

Android Things アプリ化するための設定を追加

2017/08/19 現在のところ Android Things 専用の項目はなく、Phone and Tablet で生成された内容を流用しているため、Android Things アプリ化するために以下の箇所を手動で設定する必要があります。

app/build.gradle

アプリケーションのルートディレクトリに存在する build.gradle ではなく app ディレクトリ直下の build.gradle です。Bintray / androidthings-supportlibrary で確認できる最新のバージョンを指定して追記します。外部 JAR に依存しているだけでありコンパイル時に APK ファイルに含める必要はないため compile ではなく provided で設定します。

apply plugin: 'com.android.application'

android {
    ...
}

dependencies {
    ....

    provided 'com.google.android.things:androidthings:0.5-devpreview'  ←追記
}

app/src/main/AndroidManifest.xml

build.gradle で provided 設定した外部 JAR を実行時に参照するための classpath 設定を uses-library で行います。また、Android Things デバイスブート時に起動される Activity であることをインテントフィルタで設定しています。

...
<manifest ...>
    <application ...>

        <uses-library android:name="com.google.android.things" />  ←追記

        <activity android:name=".HomeActivity">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter>  ←↓追記
              <action android:name="android.intent.action.MAIN" />
              <category android:name="android.intent.category.IOT_LAUNCHER" />
              <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

        </activity>
    </application>
</manifest>

GPIO 制御処理の記述

汎用の入出力ピンである GPIO ピンを制御して LED を一定間隔で点灯させます

app/src/main/java/com/example/mycompany/myapp/HomeActivity.java

package com.example.mycompany.myapp;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;

import com.google.android.things.pio.Gpio;
import com.google.android.things.pio.PeripheralManagerService;

import java.io.IOException;

public class HomeActivity extends Activity {

    // ログ出力で使用するタグ名
    private static final String TAG = "HomeActivity";

    // LED の点滅間隔
    private static final int INTERVAL_BETWEEN_BLINKS_MS = 1000;

    // LED 用の出力ピン識別子
    // https://developer.android.com/things/hardware/raspberrypi-io.html
    private static final String LED_PIN_NAME = "BCM6";

    // main スレッドとは別のスレッド、およびそのスレッドで順番に実行するためのキューを有します。
    // https://developer.android.com/reference/android/os/Handler.html
    private Handler mHandler = new Handler();

    // GPIO を表現するオブジェクト
    private Gpio mLedGpio;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 周辺機器との接続を管理するオブジェクト
        PeripheralManagerService service = new PeripheralManagerService();
        try {

            // LED 点灯用の GPIO ピンをオープン
            mLedGpio = service.openGpio(LED_PIN_NAME);

            // 出力ピンとして設定、電圧の初期状態は 0V
            mLedGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);

            // LED 点灯処理を別スレッド実行用のキューに積みます。
            mHandler.post(mBlinkRunnable);
        } catch (IOException e) {
            Log.e(TAG, "Error on PeripheralIO API", e);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        // 終了時は別スレッド実行用のキューを空にします。
        mHandler.removeCallbacks(mBlinkRunnable);

        // GPIO ピンを閉じます。
        if (mLedGpio != null) {
            try {
                mLedGpio.close();
            } catch (IOException e) {
                Log.e(TAG, "Error on PeripheralIO API", e);
            }
        }
    }

    // 別スレッドで実行する LED 点灯処理です。
    private Runnable mBlinkRunnable = new Runnable() {
        @Override
        public void run() {

            // 何らかの原因で GPIO が閉じられている場合はそのまま処理を終えます。
            if (mLedGpio == null) {
                return;
            }

            try {
                // 「点灯」と「消灯」をトグルします。
                mLedGpio.setValue(!mLedGpio.getValue());
                Log.d(TAG, mLedGpio.getValue() ? "ON" : "OFF");

                // 一定時間経過してから実行する設定で再びキューに積みます。
                mHandler.postDelayed(mBlinkRunnable, INTERVAL_BETWEEN_BLINKS_MS);
            } catch (IOException e) {
                Log.e(TAG, "Error on PeripheralIO API", e);
            }
        }
    };
}

アプリケーションの配信 (OTA アップデート)

Wi-Fi 接続の設定を行う際に Raspberry Pi 3 に書き込んだイメージは Factory Image とよばれます。Factory Image は Bundle と Android Things OS をそれぞれコンソール上で選択して「CREATE BUILD CONFIGURATION」することで設定が生成されます。先程は空の Bundle を利用したことになります。

Android Things におけるアプリケーションは Bundle ファイルとしてまとめられます。新規 Bundle の配信は OTA (over-the-air) にインターネット経由で行うことができます。LED 点滅アプリケーションを Bundle 化してコンソールにアップロードして配信方法を設定できます。

ただし、Android Things 内の update_engine が更新を確認する周期が 2017/08/20 現在のところ 5 時間とされており時間がかかるため、本ページではアップロードした Bundle と Android Things OS で新規に Factory Image を生成して、再度 SD カードに書き込むことで動作確認することにします。

Bundle ファイルについて

Bundle 内に最低限必要なファイルは IOT_LAUNCHERAndroidManifest.xml で設定された Activity を含んだ APK ファイルのみです。これを zip 化すれば動作確認に必要な Bundle ファイルが得られます。

APK ファイルの作成

APK ファイルのビルド種別について、既定ではデバッグビルドとリリースビルドの二つがあります。また、ビルド方法には Android Studio で行う方法とコマンドで行う方法があります。ここでは簡単のため、以下のコマンドでデバッグビルドを行います。

cd ~/AndroidStudioProjects/MyApp/
./gradlew assembleDebug

生成された apk ファイルを確認します。

$ find . -name *.apk
./app/build/outputs/apk/app-debug.apk

適当なディレクトリにコピーして zip 化します。

mkdir ~/Desktop/myapp-20170820
cp app/build/outputs/apk/app-debug.apk  ~/Desktop/myapp-20170820/
cd ~/Desktop/
zip -r myapp-20170820 myapp-20170820

これをコンソールからアップロードして、再度 Factory Image を作成して SD カードに書き込みます。ちなみに、2017/08/20 現在コンソールが対応しておらず、作業で使用していた Firefox ではアップロードできなかったため Google Chrome でアップロードしました。

Raspberry Pi をブレッドボードで LED と接続して動作確認

ソースコードで LED 用の GPIO を LED_PIN_NAME = "BCM6" と設定したため、以下のようにブレッドボード上で適当な抵抗と LED を直列につなぎます。抵抗や LED に限らず、電子工作でよく使用するパーツや工具は手元に揃えておくと便利です。

Ground ピン --- 180 Ω 抵抗 --- LED --- BCM6 ピン

接続するピンを間違えて Raspberry Pi を壊さないように注意します。以下のページの画像と見比べて作業するとよさそうです。

電源を入れてしばらく待つとアプリが起動して LED が点滅し始めます。

Android Studio サンプルプロジェクトの導入 (補足)

Google Developers Japan / Android Things Developer Preview 5 に記載のとおり、Android Studio の File → New → Import Samples から "Things" で検索することで、サンプルプロジェクトをダウンロードして試すことができます。

Likeボタン(off)0
詳細設定を開く/閉じる
アカウント プロフィール画像

Android Developer

記事の執筆者にステッカーを贈る

有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

>>さらに詳しくステッカーを贈る
ステッカーを贈る コンセプト画像

Feedbacks

Feedbacks コンセプト画像

    ログインするとコメントを投稿できます。

    ログインする

    関連記事

    • Spring Security フォームログインのサンプルコード
      Spring フレームワークによる Web アプリケーション開発で、ログイン処理を実装する際は Spring Security が便利です。ここでは特に Spring Boot で Web アプリケーションを開発する場合を対象とし、フォームによる ID/Password ログインを行うためのサンプルコードをまとめます。 公式ドキュメント [Spring Security チュートリアル](http...
      えびちゃんえびちゃん11/4/2019に更新
      いいねアイコン画像0
    • Java配列の宣言方法 (C/C++との違い)
      Javaの配列 Javaの配列宣言方法はC/C++と似ているようで若干異なる。 初期化しない場合 C/C++の int array[10]; はJavaでは int array[] = new int[10]; となる。同様にC/C++の int array[3][3]; はJavaでは int array[][] = new int[3][3]; となる。 初期化
      てんとうむしてんとうむし4/13/2018に更新
      いいねアイコン画像0
    • PlantUML による UML 図の描き方
      サムネイル画像-c788fffde5
      PlantUML はテキスト形式で表現されたシーケンス図やクラス図といった UML (Unified Modeling Language) 図の情報から画像を生成するためのツールです。簡単な使い方をまとめます。 インストール方法の選択 Atom や Eclipse のプラグインをインストールしてエディタから利用する方法、JAR をダウンロードして Java コマンドで実行する方法、Redmine ...
      kentakenta12/21/2019に更新
      いいねアイコン画像0
    • Akka HTTP サンプルコード (Scala)
      サムネイル画像-a98142497c
      Akka アクターを用いて実装された汎用 HTTP フレームワークです。Spray の後継です。コアモジュールである akka-http-core は 2016/2/17 に experimental が外れました。akka-http などのいくつかのサブモジュールは 2016/3/1 現在 experimental のままですが、基本的な
      雄太雄太9/7/2021に更新
      いいねアイコン画像0
    • Kestrel の使用例
      Kestrel は Message Queue (MQ) の実装のひとつです。一般に MQ はアプリケーション間やプロセス間、スレッド間で非同期に通信するために用いられます。メッセージの送信側は MQ に書き込めば受信側の応答を待たずに次の処理に非同期に進むことができます。Kestrel はわずか 2500 行程の Scala で実装されており JVM で動作します。MQ 自体はメモリ上に存在する...
      したくんしたくん9/12/2017に更新
      いいねアイコン画像0