2017年11月18日、19日に実施された「東北Tech道場 郡山道場 第8回」の作業内容をまとめます。
12月2日に東北Tech道場全体の発表会が行われたのですが、その直前の回です。前回までの作業で、5秒おきに写真を撮って、Cloud Vision APIで解析して、解析結果とともにFirebaseにアップロードし、スマホからそれを確認するところまでできました。そろそろハードと合わせないと間に合いません。それと、当初予定していた、
- 画像をAIで判別し、猫が写っていて、設定温度と湿度を超えていれば扇風機のモータを回す。このとき、距離センサで猫との距離を測り、離れすぎている場合には扇風機は回さない。
という仕様ですが、これはもう時間的に全部は完成させられそうにないので、
- 画像をAIで判別し、猫が写っていれば扇風機のモータを回す。
- サーボモータで扇風機そのものを回転させ、猫を探す。
に限定して開発することになりました。なお、下の方の仕様は、距離センサの代替案です。
#1. ハードウェアの状態
この時点でのハードウェアは次のような状態です。市販の扇風機から取り外したファンと別途購入したサーボモータをRaspberry Pi3で制御します。
#2. Lチカを試す
まず、Raspberry Pi3のPIOの使い方を覚えるためにLEDを点灯させるプログラムLチカを作成しました。参考にしたのは、「電子工作、プログラミングのメモ的なブログ」です。
##(1) 配線
サイトに載っている通りにブレッドボードにLEDと抵抗の配線をした。抵抗は1kΩを使用した。
##(2) サンプルプログラムのインポート
サイトに載っている「Simple PIO」をダウロード・解凍し、Android Studioにインポートした。インポートしたとき、バージョンが異なっていたらしく、アップデートを促すポップアップがでたので指示に従いアップデートした。
##(3) 実行
サイトの説明の通り、「RUN」の隣にあるプルダウンから「blink」を選択して実行した。すると、ちゃんと1秒ごとにLEDが点滅した。
#3. CatFansへLチカを移植
CatFansにLチカのプログラムをいれます。画像を解析して、猫がいたらLEDをOn、猫がいなかったらLEDをOffにするプログラムにします。実際にはLEDのOn/OffをファンのOn/Offに使えるようにすることになります。
##(1) mBlinkRunnableメソッドの追加
Lチカのプログラム、BlinkActivityの79行目から97行目にあるLEDの処理、「mBlinkRunnable」メソッドをコピーして、以下のように書き換える。これで、LEDを1秒おきではなく、引数でon/offできるようになる。
//LEDの処理
private void mBlinkRunnable(boolean onoff) {
// Exit Runnable if the GPIO is already closed
if (mLedGpio == null) {
return;
}
try {
mLedGpio.setValue(onoff);
Log.d(TAG, "State set to " + onoff);
} catch (IOException e) {
Log.e(TAG, "Error on PeripheralIO API", e);
}
}
##(2) GPIO()メソッドの追加
CatFansのCatFansActivityに新しいメソッド「GPIO()」を作り、その中にLチカのプログラムのBlinkActivityの49行目から60行目までをコピーする。このとき、ピン名は「String pinName = "BCM6"」の様にCantFansの中で固定する。
import com.google.android.things.pio.PeripheralManagerService;
:
private Gpio mLedGpio; //LED
:
private void GPIO(){
// GPIOの処理
PeripheralManagerService service = new PeripheralManagerService();
try {
String pinName = "BCM6";
mLedGpio = service.openGpio(pinName);
mLedGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
Log.i(TAG, "Start blinking LED GPIO pin");
// Post a Runnable that continuously switch the state of the GPIO, blinking the
// corresponding LED
mBlinkRunnable(false);
} catch (IOException e) {
Log.e(TAG, "Error on PeripheralIO API", e);
}
}
GPIO()の呼び出し部分をonCreateメソッドに追加する。
public void onCreate(Bundle savedInstanceState) {
:
:
GPIO();
}
##(3) onDestroyメソッドの修正
CatFansのonDestroyの中にLチカのプログラムのonDestroyを追記する。Lチカのプログラム、BlinkActivityの66行目から76行目をコピーする。
protected void onDestroy() {
:
:
//LED
// Remove pending blink Runnable from the handler.
mBlinkRunnable(false);
// Close the Gpio pin.
Log.i(TAG, "Closing LED GPIO pin");
try {
mLedGpio.close();
} catch (IOException e) {
Log.e(TAG, "Error on PeripheralIO API", e);
} finally {
mLedGpio = null;
}
}
##(4) onCreateメソッドの修正
OnCreateメソッドの最後に
GPIO();
を追加。
#4. 猫がいたらLEDをOn、猫がいなかったらLEDをOffにする処理
猫がいたらLEDをOnにし、猫がいなかったらLEDをOffにする処理を追加します。
##(1) onPictureTakenメソッドの修正
onPictureTakenメソッドの中に、画像解析の結果、Catが80%以上だったらLEDをつける、そうでなかったのならば、LEDを消す処理を追加する。そして、今まで画像を先にFirebaseに投げてそのあと解析していたが、if文の中でFirebaseに投げるようにする。
String imageStr;
private void onPictureTaken(final byte[] imageBytes) {
if (imageBytes != null) {
final DatabaseReference log = mDatabase.getReference("logs").push();
//画像を画面サイズに合わせて縮小する
Bitmap b = createScaleBitmap(imageBytes, 1.0F, 1.0F);
byte[] temp = bmp2byteArray(b, Bitmap.CompressFormat.JPEG, 100);
final byte[] imageB = temp;
imageStr = Base64.encodeToString(imageB, Base64.NO_WRAP | Base64.URL_SAFE);
mCloudHandler.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, "sending image to cloud vision");
// Cloud Vision APIにアップロードして画像に注釈を付ける
try {
Map<String, Float> annotations = CloudVisionUtils.annotateImage(imageB);
Log.d(TAG, "cloud vision annotations:" + annotations);
if (annotations != null) {
if (annotations.containsKey("cat") == true) {
if (annotations.get("cat") >= 0.8F) {
// イメージをfirebaseにアップロードする
log.child("timestamp").setValue(ServerValue.TIMESTAMP);
log.child("image").setValue(imageStr);
mBlinkRunnable(true);
Log.d(TAG, "LED ON");
log.child("annotations").setValue(annotations);
} else {
mBlinkRunnable(false);
Log.d(TAG, "LED OFF");
}
}
else {
mBlinkRunnable(false);
Log.d(TAG, "LED OFF");
}
}
} catch (IOException e) {
Log.e(TAG, "Cloud Vison API error: ", e);
}
}
});
}
}
##(2) 実行
実行して、猫の画像にカメラを向けるとLEDが点灯し、そうでないときにはLEDが消灯するように動いた。
第8回はまだ続きます。