TWELITE CUEとM5Atomで玄関のカギの開閉状態監視システムを作った
初めに
外出先で「玄関のカギかけたっけ?」となる心配性な私。鍵の状態をスマホでチェックすることができたら超便利だと思う。
Qrio みたいなスマートロックを付けるという方法もあるが、開け閉めまでできなくてもいい(なんか不安だし。そんな私は心配性)
単純にカギかかっているかだけを確認できる仕組みが欲しい。
今年のゴールデンウィークもどこにも行けそうになくてヒマそうなので、自作してみた。
設計図
うちの玄関ドアのカギは2か所についているので2つモニターする必要あり。
開発環境、アプリバージョン
windows10
ArduinoIDE v1.8
TWE Programmer v3.7.5
App_Wings_MONOSTICK_BLUE_L1304_V1-1-4.bin
TWELITEについて
モノをつなぐ無線マイコンモジュール TWELITE-トワイライト - MONO-WIRELESS.COM
TWELITEはIEEE802.15.4(2.4GHz)規格の無線マイコンで、手軽に複数の子機の無線網を構築できるのが特徴です。
自分的には5年ほど前、まだモノワイヤレス株式会社に分社化される前の東京コスモス電機の時代にTWELITEをいくつか使用したことがありました。その時はTWELITE 2525(ニコニコ)という、コイン電池で動いて加速度が取れるモジュールを3Dプリンタのフィラメントロールにつけて、3Dプリンタが途中で止まっていないかをロールの回転による加速度変化でモニターして、止まったらアラームを出すといったことをしたりしてました。
今回、鍵のモニターも2525に磁気センサつければできるなと漠然と考えていて、久しぶりにTWELITEのホームページを見たところ、すごく進化していて、新製品がいっぱいでした。
そして2525はすでに新規採用非推奨品となっていたのですが、なんと後継機TWELITE CUEは磁気センサを搭載しているではないですか。モノワイヤレスさん素晴らしいです。
加速度、磁石センサータグ TWELITE CUE-トワイライトキュー | MONO-WIRELESS.COM
材料
製品名 | 価格 | 用途 |
---|---|---|
M5Atom Lite | 1287円 | Wi-Fiでインターネット接続 |
TWELITE CUE(Blue) | 2481円 x2台 | 無線子機(磁気センサ) |
TWELITE DIP(Blue) | 1980円 | 無線親機 |
TWELITE R2 | 1500円 | TWELITEの設定、アプリ変更に必要 |
価格は2021/5/5現在のものです。
TWELITEには標準出力のBLUEと高出力タイプのREDがあります。値段的にREDのほうが1.5倍くらい高いです。
自分はTWELITE DIP(旧製品の基板アンテナ型)とTWELITE R(2でなく旧型)とM5Atomを持っていたので、今回購入したのはTWELITE CUE2台だけです。
その他必要なもの
- コイン型電池(CR2032) 2個:TWELITE CUE用
- ブレッドボード:TWELITE DIPとM5Atom の接続用
- マジックテープ:TWELITE CUEをドアに貼り付ける用
作り方
TWELITE CUEの設定
設定変更はインタラクティブモードで行います。
TWELITE CUEにTWELITE R2を接続し、TWELITE STAGE APPを使えばできるようです。その辺はホームページに詳しく記載されているので省略します。
自分の場合は旧製品であるTWELITE Rを使ったために、すんなりはいきませんでしたが、ちゃんと旧製品も使えるように詳細情報が記載されていました。モノワイヤレスさんのこういうところは信頼できてよいです。
USBアダプター TWELITE R-トワイライター - MONO-WIRELESS.COM
TWELITEプログラマというソフトを使うことで、TWELITE RでもCUEとの接続ができました。
肝心の設定内容ですが、変更するのは少なくとも4か所です。
これが初期設定値ですが、変更するのは
a アプリケーションID
このIDが同じ端末同士で通信を行います。
初期値のままでもいいですが、もしもご近所でTWELITEを使っている人がいた場合、お互いに迷惑かけることになるので違う番号に変更
したほうがいいでしょう。(もし近所で使っている人がいればお友達になりたいですが)
使える番号には制約があります。詳細はこちら
TWELITE APPS - インタラクティブモード - MONO-WIRELESS.COM
i 論理デバイスID
子機につけるナンバーです。同じセンサーの子機が複数あってもこの番号で個体識別できます。
今回は2台の子機を使うので、1
と2
に設定しておきます。
t 送信間隔の設定
定期送信の送信間隔を秒単位で設定します。1〜4095の値で指定可能。
初期値は5なので5秒おきに通信されます。これはあくまで定期送信の話で、開閉センサーパルモードの場合、磁気センサの値に変化があった場合にも送信してくれます。なので定期送信は別になくてもよく、最大の4095秒(68分)でもいいのですが、 送信受信で取りこぼしが出る可能性を考えると60
秒くらいが適当かと思います。(心配性アゲイン)
p センサ固有パラメータの設定
これは今回、開閉センサーパルモードを使うので、04000000
を設定します。
設定変更後はコマンド S
で忘れずに保存しましょう。
TWELITE CUEの設置
TWELITE DIPの設定
TWELITE DIPはまず親機用のアプリを書き込む必要があります。
書き込むのは親機・中継機アプリ(App_Wings)
です。ホームページではMONOSTICK 用とありますが、TWELITE DIPに書き込んでも特に問題なく動きました。
TWELITE R2とTWELITE STAGE APPを使えば多分簡単にできることでしょう。
アプリを書き込んだらインタラクティブモードで設定変更をします
これが初期設定値です。
変更するのは a アプリケーションID
だけです。CUEに設定した番号と同じものに変更します。
TWELITE DIPとM5AtomLiteの配線
Groveコネクタ使って配線できればよいのですが、TWELITEの電源は3.3VなのでGroveの5V電源は使えません。
M5Atomの背面のソケットピンを使うことになりますが、ブレッドボードを使うのが簡単です。(ワイヤーで結線してももちろんかまいません)
接続はわずか3ピンでOK。電源(3.3V)とGNDとTWELITEのUART TX→M5AtomのUART RXです。
M5AtomLiteのプログラム
電文のデコード
まず受信電文を確認するために、単純に受信した値をそのままprintさせてみます。
#include "M5Atom.h" void setup() { M5.begin(true, false, true); Serial.begin(115200); Serial2.begin(115200, SERIAL_8N1, 21, 25);// RX=21 TX=25(TXは使わないので適当) } void loop() { char c; if (Serial2.available() > 0 ) { c = Serial2.read(); Serial.print(c); } }
CUEに磁石をつけたり離したりして通信が来るのを確認します。
こんな電文が確認できました。
:800000004E0006810BFF090180810311300802099C1130010204A900000001026D42 :80000000480007810BFF090180810311300802099C1130010204A900000001005D59 :800000006C000B810BFF090180810311300802099C1130010204F70000000101B08F :800000006F000C810BFF090180810311300802099C1130010204BA00000001818078
バイナリをアスキーにした電文が来ます。
電文の詳細はホームページに記載されています。パルアプリ - WINGS
必要な情報は3つ
番号5 送信元の論理デバイスID
番号d データ(子機の電池電圧(mV))
番号n データ(磁気センサの状態 )
0x00=近くに磁石がない
0x01=N極が近い
0x02=S極が近い
0x80= 定期送信
今回は磁気センサしか使っていないので、単純に:から始まる電文の文字数で必要なデータを取り出すことができます。
余裕があれば拡張性がある作りにしたいところでしたが、今回はとりあえず決め打ちでプログラムしました。(とりあえずで作ったプログラムが直されることはほぼないが)
IoTサービスへの考慮
センサーからデータ受信するたびにIoTサービスへインターネット通信するのが最も簡単ですが、フリーで使えるIoTサービスはデータの更新間隔や一日のデータ数などに制約があることがほとんどです。
とあるフリーのIoTサービスは1日3,000件(約30秒間隔)、データの送信は最低5秒あける必要があるとの条件でした。それを考えると単純に受信したら投げるという作りにはできません。その条件を満たす実装を考えます。
基本的には1分程度に1回、定期的にその時の状態を送るでいいと思いますが、問題はカギが開き閉めされた時です。
1分に1回だとその間の開き閉めを見逃す可能性があります。それは避けたい。 特にドアの上側のカギはメインで使われるので、ここが閉→開の動きをした場合は確実にデータアップしたい。
そういった考えを盛り込んで最終的なプログラムをしました。コード
Wi-Fi接続およびIoTサービスへのデータ送信に関してはあえて省いています。(あまりにプライベートなものなので) ここまで出来る人であればこの先のIoT化はできるでしょう。
#include "M5Atom.h" #define SENSOR_NUM 2 #define OPEN 1 #define CLOSE 0 uint8_t door_lock[ SENSOR_NUM ] = {0}; uint16_t batt_vol[ SENSOR_NUM ] = {0}; unsigned long send_time = 0; uint8_t door1_before = CLOSE; void setup() { M5.begin(true, false, true); Serial.begin(115200); Serial2.begin(115200, SERIAL_8N1, 21, 25);// RX=21 TX=25 send_time = millis(); } void loop() { char str[70]; //受信用配列 int str_len; unsigned long now_time; if (Serial2.available() > 0 ) { str_len = Serial2RecvStr(str); if (str_len != 69) { return; } //Serial.println(str); char id[] = {str[23], str[24], '\0'}; char bat[] = {str[39], str[40], str[41], str[42], '\0'}; char door[] = {str[64], '\0'}; int id_num = atoi(id); int bat_mv = strtol(bat, 0, 16); int d_num = atoi(door); switch (id_num) { case 1: if (d_num == 0 ) { door_lock[0] = 0; //door close door1_before = CLOSE; M5.dis.drawpix(0, 0x000000); } else { door_lock[0] = 1; //door open M5.dis.drawpix(0, 0x00f000);//開いている場合赤LED点灯 if (door1_before == CLOSE) { while (1) { now_time = millis(); if (send_time > now_time) { //飽和対策 send_time = 5000; } if (now_time - send_time > 5000) { send_mes(); break; } } } door1_before = OPEN; } batt_vol[0] = bat_mv; break; case 2: if (d_num == 0 ) { door_lock[1] = 0; //door close } else { door_lock[1] = 1; //door open } batt_vol[1] = bat_mv; break; } } now_time = millis(); if (send_time > now_time) { //飽和対策 send_time = 60000; } if (now_time - send_time > 60000) { send_mes(); } } void send_mes(void) { Serial.print("door1 = "); Serial.println(door_lock[0]); Serial.print("bat1 = "); Serial.println(batt_vol[0]); Serial.print("door2 = "); Serial.println(door_lock[1]); Serial.print("bat2 = "); Serial.println(batt_vol[1]); /* ここにIoTサービスへのデータ送信を記述すればよい */ send_time = millis(); } int Serial2RecvStr(char *buf) { int i = 0; char c; if (Serial2.available() > 0 ) { c = Serial2.read(); if (i == 0 ) { if (c == ':') { buf[i] = c; i++; } else return 0; } while (1) { if (Serial2.available() > 0 ) { c = Serial2.read(); if ( (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ) { buf[i] = c; i++; } else { return 0; // ERROR } if (i == 69) { buf[i] = '\0'; return i; } } } } }
動作の様子
カギの開閉状態を無線で取得する事が出来た。
— PikaPikaらいと (@KPmilk3) 2021年5月4日
ここまで出来ればあとはWi-FiでIoTサービスにデータ送れば、カギ監視システムの完成だ。#TWELITE #M5Atom pic.twitter.com/cSZu0mjiuR
TWELITE DIPとM5AtomLiteの設置
電源はM5AtomのUSB端子で給電しますのでUSB電源ポートが必要です。
自分は最初、ドアから距離5mほど高さ2mほどにあるWi-Fiルータ(通称:カニルータ)のそばに置いてみたのですが、下側のカギにつけたセンサからの無線が不安定でした。上側のカギは問題なし。無線機の特性として地面に近いところに設置したものは通信距離が悪くなるので、多分そのせいだと思います。設置場所を変えてドアの近くに設置したら両方とも問題なく受信できました。Wi-Fiはカニルータのおかげもあって余裕でつながりました。
ブレッドボードに挿してあるだけなので、テープで固定してタッパ的なケースに入れて完成としました。
最後に
今回はカギの状態だけを見ていますが、M5AtomのGroveコネクタも空いていることなので、何か他のセンサを追加して本格的なIoTをしてみるのも面白いと思っています。
今回のプログラミングはいわゆるゲートウェイを作るもので普段なじみがなく、我ながら不細工なコードだと思いますが、目標の期間で動くものができたのでよしとします。
TWELITE CUEの電池寿命はホームページページによると「1日に200回の開閉を行なった場合、約4年です。」とありますが、実際にどのくらい持つのか楽しみです。
稼働日:2021/5/4
立方体万華鏡をLEDテープを使ってピカピカさせてみた
立方体万華鏡 CUMOS
ヤマザキミノリ氏
が発明された立方体万華鏡 CUMOS という、鏡を6面組み合わせて作る、とても幻想的な万華鏡があります。
立方体万華鏡CUMOSから光のオブジェ、空間演出デザイン、光のインスタレーションまで一貫して展開。海外国内でふしぎなのぞき箱ワークショップ開催、アートアクティビティも多数。 pic.twitter.com/4ztAdAG5ZH
— ヤマザキミノリ Minori Yamazaki (@MinorinY) 2018年10月21日
私がCUMOSを最初に知ったのはこのツイートです。作り方の動画もありました。
こちらでは色を付けるのにマジックを使っていますが、これをカラーLEDでやったらキレイなんじゃないかと思って実際に作ってみました。先日バズった「立方体万華鏡」ですが、ヤマザキミノリ名誉教授に確認を取り、当館公式YouTubeに作り方を公開させていただけることとなりました!
— 佐賀県立宇宙科学館 (@saga_space) 2020年8月2日
この動画を見て、ぜひおうちでもチャレンジしてみてください!(自分の目で見ると本当に感動します✨)https://t.co/u4jHGonBY1 pic.twitter.com/GXgxnt6END
材料
- 正方形のアクリル鏡 6個
自分は100円ショップ(キャン★ドゥ)で購入しました。 WS2812B LEDテープ
LEDの間隔が狭いもののほうがいいと思います。 自分が使ったのはこちらArduinoマイコンボード
自分が使用したのは M5Atom Lite です。 www.switch-science.com M5Atom Lite との接続にはGroveケーブルを使用しました。
作り方
まずはCUMOSを作成します。
CUMOSの作り方を紹介しているページがありますので、そちらを参考にして作成しました。
おうちで自由研究道場【立方体万華鏡】
国立大学56工学系学部ホームページ
こちらではマジックやセロハンで色を付けていますが、その代わりにLEDテープを使用します。
鏡に線傷をつけたところにWS2812B LEDテープ を貼ります。
WS2812B LEDテープ はハサミで好きなところをカットして分割できるようになっていますので、鏡の大きさに合わせてカットし、ワイヤーをはんだ付けして配線します。 こんな感じです。(雑な工作ですいません)
M5Atom Lite への接続はGroveケーブルの片方を直接LEDテープ にはんだ付けしました。
これでハードは完成です。
コード
ArduinoでプログラムしてLEDテープを点灯させるわけですが、
Adafruit_NeoPixelライブラリのサンプルプログラムをそのまま使うのが簡単です。
ただし、M5Atomに使われているESP32マイコンだとAdafruit_NeoPixelライブラリは完璧には動作しません。LEDの数が多いと誤点灯します。今回は誤点灯してもそれほど影響ないので、このライブラリを使いました。
github.com
githubからライブラリのZIPをダウンロードし、ArduinoIDEにてライブラリインクルードをします。
サンプルプログラムのstrandtestがいい感じの点灯パターンです。
修正するのは2か所だけ。LED制御信号のピン番号とLEDの数の設定だけ直せばOKです。
LED_PIN はM5AtomのGroveポートの26番ピンを使っているので26に、
LED_COUNT は今回72個使っているので、そのように修正します。
// Which pin on the Arduino is connected to the NeoPixels? // On a Trinket or Gemma we suggest changing this to 1: //#define LED_PIN 6 #define LED_PIN 26 // How many NeoPixels are attached to the Arduino? //#define LED_COUNT 60 #define LED_COUNT 72
プログラムを書きこめば完成です。
strandtestによる点灯パターンの様子はこちら
裏側がどうなっているかお見せします。作り方のブログ記事も作成中です。 pic.twitter.com/cnebAc9xuf
— PikaPikaらいと (@KPmilk3) 2021年5月2日
消費電流確認
WS2812B LEDテープを使用するときは消費電流に気を付ける必要があります。
strandtestプログラムで72個使った場合の消費電流を簡易的にUSB電流計で測ってみました。
M5Atomの分も含めて最大320mA@5V でした。結構大きいですが普通のモバイルバッテリーで給電可能な値でした。
これ以上だとちょっと気にしないといけないと思うので、プログラム改造するときはこれ以上明るくしないよう注意必要と思います。
ツイッターにあげた動画
#MFKyoto2021 #作品発表
— PikaPikaらいと (@KPmilk3) 2021年5月1日
立方体万華鏡CUMOS をLEDテープでピカピカさせたものです。
アートという事で。 pic.twitter.com/Hzqrl7YFA1
#立体万華鏡 #cumos はヤマザキミノリ名誉教授の考案だそうです。素晴らしいアイデアに敬服します。
— PikaPikaらいと (@KPmilk3) 2021年2月8日
自分はこちらの動画の作り方を見て、カラーペンの代わりにカラーLEDテープを貼ってプログラムでチカチカできるようにしました https://t.co/n5sWyPivqu pic.twitter.com/lNiy9Gt5WH
こちらの #立体万華鏡 をLEDテープ使って作ってみました。
— PikaPikaらいと (@KPmilk3) 2021年2月5日
点灯パターン変えても面白そう。 https://t.co/07MKSZ71Wc pic.twitter.com/FyeP4kq56B
#立体万華鏡 #万華鏡
— PikaPikaらいと (@KPmilk3) 2021年2月9日
外と内の世界はこんなにも違う pic.twitter.com/1HD0D2qi9W
#万華鏡 #立体万華鏡
— PikaPikaらいと (@KPmilk3) 2021年2月8日
ランダム点灯にしてみた。 https://t.co/i0oAhP1uPX pic.twitter.com/UDl4EVUmPo
#立体万華鏡
— PikaPikaらいと (@KPmilk3) 2021年2月9日
全体が徐々に変化するパターン
これもなかなかいい感じ😃 pic.twitter.com/bdzBZb7Anb
UNIT-VでopenMV使ってIMEモード判別してみた
初めに
ブラインドタッチができない人間(私)が日々悩まされている、「日本語モードだと思って打っていたら英数モードだった(その逆もしかり)問題」の対策として「あ」or「A」を判別させるAIカメラの作成に取り掛かった。
ファーストステップとしてM5StickVのV-Trainingで狙いの動作をさせることができた。詳細は以下の記事にて。
pikapikalight.hatenadiary.com
M5StickVにはLCDとバッテリーがついていて便利なのだが、今回やりたいことに対してはこの機能は不要、むしろいらない機能といえる。 今回の目的に対してはUNIT-Vを使うのが最適なので、セカンドステップとしてUNIT-Vで同じものを作ることにした。
エッジAIの挫折
M5StickVでは割とすんなりできたので、UNIT-Vでも簡単にできると思って始めたのだが、これが予想外の苦戦を強いられる。
V-Trainingは学習曲線を見るかぎり問題なく学習できていそうなのだが、そのKモデルをUNIT-Vにいれて動かすと正答率がすこぶる悪い。カメラの位置、角度をシビアに調整してやっと正解が出るといった具合で、使い物にならないレベル。
写真の撮り方、写真サイズ、ブライトネス、コントラスト、色々変えてみたりしたが、うまくいかず。果てはV-Trainingを使わず、自力で学習してモデル作成するということもやってみたが、それでもやっぱり実機動作で正答率悪し。
そのあたりのいきさつはこちら。
V-TrainingでのUNIT-Vの画像判別がうまくいかないので、自力で学習させる方法ないかと検索したら、からあげ先生の記事に行きつく。
— PikaPikaらいと (@KPmilk3) 2021年4月13日
困った時はだいたいたどり着くからあげ先生。ありがたや。https://t.co/MxS8OZnid1
結局はAIによる判別はあきらめたのですが、Google Colaboratoryを使っての自力学習の方法など非常に得たものは大きかったので、詳細は別の記事にしたいと思います。V-Trainingを使わない、M5UNIT-V用のモデルの自力作成。
— PikaPikaらいと (@KPmilk3) 2021年4月14日
からあげ先生の記事にリンクされていたNabeshinさん作の修正版コードを使わせていただき、なんとか学習とモデル変換できました😁
ただ、学習結果がダメダメ😓これは写真の撮り方が悪いのだと思うのでやり直す。https://t.co/xdN5j6jrvu
openMVに挑戦
色々と試している過程で必然的にMaixPyの機能について調べることとなったのだが、思っていた以上にいろいろな機能があることが分かった。openMVとやらの機能が使えて、フィルターをかけたり、特定の色の領域を判別させたりと、AI使わなくてもひょっとしてできるかもと思い始めた。
さらに調べるとこのような記事を発見
マーカーシールを使ってメーターの針の位置を読み取るというもの。このマーカーシールを使う方法で今回やりたいことを実現することができた。
概要
- マーカーシールを「あ」の真下に貼る
- sensor.set_auto_gain(False) でオートゲインを無効にする
- MaixPyのしきい値エディタでマーカーのしきい値と「あ」「A」のしきい値を確認
- .find_blobsでマーカーシールの領域を特定
- マーカーシールの領域情報から「あ」の領域を特定し、その領域を切り出す
- 切り出した領域に対して.find_blobsで「あ」「A」の領域サイズを判定
- マーカーシールのサイズと「あ」「A」の領域サイズの比から「あ」を判別(「あ」のほうが明らかにサイズが大きいので区別ができる)
しきい値エディタ
MaixPyでフレームバッファにカメラの絵が出ている状態で メニューの「ツール」→「マシンビジョン」→「しきい値エディタ」→ソースイメージの場所 フレームバッファ でしきい値エディタを起動する。 スライドバーを適当に動かして、マーカーシールのみが表示されるしきい値を確認する。 同じように「あ」「A」のしきい値も確認する
コード
import sensor, image, time #import gc, math from board import board_info from Maix import GPIO from fpioa_manager import fm import sys while 1: try: sensor.reset() #Reset sensor may failed, let's try some times break except: time.sleep(0.1) continue sensor.set_hmirror(1) sensor.set_vflip(1) # run automatically, call sensor.run(0) to stop sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE) sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240) sensor.skip_frames(time = 1000) # Wait for settings take effect. #sensor.set_brightness(-2) #sensor.set_contrast(-2) sensor.set_auto_gain(False) #これ重要。無効にしないと周りの明るさで大きく変化してしまう。 #clock = time.clock() # Create a clock object to track the FPS. #LED点灯用 fm.register(35, fm.fpioa.GPIOHS0, force=True) pinout35 = GPIO(GPIO.GPIOHS0, GPIO.OUT) pinout35.value(0) mark_threshold = (0, 100, -128, -28, -128, 127) #マークシールのしきい値 text_threshold = (100, 34, -128, 127, 127, -128) #「あ」のしきい値 while True: img=sensor.snapshot() blobs = img.find_blobs([mark_threshold]) if blobs: for b in blobs: if b.area() > 1000: #ゴミとりのため、小さい領域は無視する。 #print(b) tmp = img.draw_rectangle(b[0:4],color=(0,255,0)) tmp = img.draw_cross(b[5], b[6],color=(0,255,0)) mark_x = b[0] mark_y = b[1] mark_w = b[2] mark_area = b.area() try: tmp = img.draw_rectangle(mark_x,mark_y - int(mark_w*1.5),mark_w,mark_w,color=(0,0,255)) #シールの位置から文字の位置を特定 img2 = img.copy((mark_x,mark_y - int(mark_w*1.5),mark_w,mark_w)) #文字の領域を切り出す blobs2 = img2.find_blobs([text_threshold]) #切り出した領域に対してしきい値判定 if blobs2: for b in blobs2: #print(b.area()) if b.area() > 200: #小さい領域は無視する。 img.draw_rectangle(mark_x+b[0],mark_y - int(mark_w*1.5) + b[1],b[2],b[3],color=(255,255,255)) text_area = b.area()/mark_area #比を計算 print(text_area) if text_area > 0.2: #「あ」の判定基準。実機確認の結果より。 pinout35.value(1) else: pinout35.value(0) except: pass
サードステップ
今回の実施条件は照明がほとんど一定の環境下のもの。照明条件が大きく変わるような条件、例えば直射日光が当たるような場所では正しく動かないはずである。
ホワイトバランスをとるような仕組みがあればより安定した動作ができると思う。今後の検討課題である。
また、「あ」と「A」の区別を領域のサイズ比で行ったが、この判定部分をAIにさせることでより精度の高い判定ができそうな気がする。 マシンビジョンとAIの組み合わせ、なんかカッコいいのでトライしてみたい。
【作品まとめ】M5Stackで霹靂一閃
Twitterにあげていた作品のまとめ
ハーフミラーを使って面白もの作れないかと考えていて思いつきました。M5Stackでホログラム その8
— PikaPikaらいと (@KPmilk3) 2021年3月12日
霹靂一閃#M5Stack #ホログラム #LovyanGFX pic.twitter.com/PluWAKEUue
Yin and Yangの絵はM5Stackライブラリの中のサンプルコードより。 M5Stack\examples\Advanced\Display\Sprite\one_bit_Yin_Yang
これをベースにLovyanGFXを使って上側の絵と下側の絵を別のspriteで作成し、パカッという動きを実現させています。
クモの絵はパワーポイントに入っていた素材を使用。M5Stackで 霹靂一閃 六連
— PikaPikaらいと (@KPmilk3) 2021年3月17日
縦撮りバージョン
クリックすれば全面見れるはず https://t.co/gmfCdPFWS6 pic.twitter.com/ozvvp3zvSV
WS2812を144個使用。M5Stackでは144個の制御ができなかったので、WS2812の制御とM5Stack2台へのタイミング信号の送り出しは別のマイコンで実現。
クモの絵のパカッという動きのプログラムはspriteを理解することで実現。 もしリクエストあればコード公開します。(現状、全然整理してないコードなのでとてもお見せできない)
光モノの工作を色々してきたが、ここにきて影の面白さに目覚めた。M5Stackで 霹靂一閃
— PikaPikaらいと (@KPmilk3) 2021年3月24日
影絵バージョン
RGB LEDテープを使った影絵、楽しい。色々な可能性ありそう😊#M5Stack pic.twitter.com/isG1cRRPaM
舞台裏編
M5Stackでホログラム その8
— PikaPikaらいと (@KPmilk3) 2021年3月12日
霹靂一閃の舞台裏
陰陽は上下で2つのspriteを使って表示。それでパカッとする動きを実現。ミラーフィルム使った瞬間移動は想像よりそれっぽくできた😆
思い付いたら作らずにはいられない。PoCを超えたいとは思うのだが🤔#M5Stack #ホログラム #LovyanGFX https://t.co/fgbYAHmnfB pic.twitter.com/WI5NBRGUBL
M5Stackで 霹靂一閃 六連の舞台裏
— PikaPikaらいと (@KPmilk3) 2021年3月16日
WS2812 144個使用
M5Stackは磁石追加で隙間あけてホワイトボードに貼付
クモのspriteを2つのspriteに座標ずらしてpushする事で分断
こそこそ噂話
M5StackでWS2812を144個制御出来なかったので、別のマイコンも使ったらしいですよ#M5Stack #LovyanGFX https://t.co/gmfCdPFWS6 pic.twitter.com/jhH5NWsCP1
M5Stackで 霹靂一閃
— PikaPikaらいと (@KPmilk3) 2021年3月24日
影絵バージョンの舞台裏
ハード、ソフトは前回の構成をほぼ使い回し。ダンボールステージはこれからも活躍予定 https://t.co/HxQtFN7l6i pic.twitter.com/b8xp5HO3ML
【作品まとめ】M5Stackでホログラム
Twitterにあげていた作品のまとめ
www.hitachi.co.jp
こちらの記事を見て、M5Stackなら自分でプログラム作れば好きな絵を浮かばせられるじゃん、と思って始めました。
実際にはこれは「ホログラム」とは違うものとは承知していますが、他に呼びようないのでホログラムと言っちゃってます。
LovyanGFXの描画速度の速さが体感できます。一番早いのは30回転首振りしているはずですが全然見えません。#M5Stack で #ホログラム#PartyParrot にチャレンジ
— PikaPikaらいと (@KPmilk3) 2021年2月19日
LovyanGFXの描画速度は凄い😲
スマホカメラでは全然追いつけない😓 https://t.co/e9HdtBpFH0 pic.twitter.com/5FbBNDPo2i
Wio Terminalのほうが画面サイズ大きいので向いているかもしれません。#WioTerminal でも #ホログラム
— PikaPikaらいと (@KPmilk3) 2021年2月20日
M5Stackと全く同じコードで動いた。 https://t.co/e9HdtBpFH0 pic.twitter.com/eQ2O721QjO
もともとM5Stack 2台持っていましたが。これやるために2台買い増し。#M5Stack で #ホログラム
— PikaPikaらいと (@KPmilk3) 2021年2月21日
思いついたらどうしてもやりたくなってM5stack買い増ししちゃった😅
楽しくなる予感しかないから悔い無し pic.twitter.com/QLSMm0WyfK
このために電動ターンテーブルも購入M5Stackでホログラム その4
— PikaPikaらいと (@KPmilk3) 2021年2月27日
電動ターンテーブル買っちった😅
4台使っての #PartyParrot
GIFアニメに白線2本使うと飛び出す感出せるとの記事見て、LovyanGFXを駆使して追加してみた😁#M5Stack #ホログラム pic.twitter.com/bqCCuPErPA
M5Stackでホログラム その5#PartyParrot にどうしてもChoo Choo TRAINさせたくなって考えた。
— PikaPikaらいと (@KPmilk3) 2021年3月5日
4台直列は厳しかったので2x2に#M5Stack #ホログラム pic.twitter.com/8wzD75aE2Q
M5Stackでホログラム その6
— PikaPikaらいと (@KPmilk3) 2021年3月7日
すごい動画みて、かめはめ波に挑戦したくなった。
あらゆるレベルの低さを痛感しつつも、最初の一歩として記録。ここからマイコンならではのエフェクトを考えてみようhttps://t.co/nyve34I9Jo @YouTubeより#M5Stack #ホログラム #LovyanGFX pic.twitter.com/SZaAH00HsO
M5Stackでホログラム その7
— PikaPikaらいと (@KPmilk3) 2021年3月10日
かめはめ波のあのシーンに挑戦。
マイコンの基本技、Lチカを活用。
日本語表示、さらに鏡に写すため反転表示という難題もLovyanGFXの力でなんなくクリア。
もう少し時間かけて作品に仕上げたい。#M5Stack #ホログラム #LovyanGFX pic.twitter.com/S1gsviEZFV
M5StickVでIME入力モードを判別してLチカさせてみた
構想
M5StickVでパソコンのモニター画面のIMEのモード表示「あ」or「A」を判別させ、「あ」ならLEDを点灯させ、日本語モードであることがキーボードに目線を置いていても分かるようにする。ブラインドタッチができない人間(私)が日々悩まされている問題に先端技術を持って取り組む。
環境&Version
Windows10
SDカード:SanDisk 32G HC Class10
EasyLoader(V5.1.2)
VTraining-Client-VerA02B01
V-Training実施レポ
M5StickVはV-Trainingという画像判別のための至れり尽くせりなサービスがある。
M5Stack Docs - The reference docs for M5Stack products.
基本的にはこのページに従って進めていけばOK。
EasyLoaderでファームウェアの書き込み
VTraining-Client.zipをダウンロードして中身をSDカードに書き込み。
M5StickVの電源を入れると学習用データ撮影モードのソフトが起動する。
学習には3クラス以上必要で、1クラス35枚以上の写真が必要と書いてあるので、「あ」、「A」、「×」の3種類の写真を35枚ずつ撮影。
trainフォルダとvaildフォルダができるので二つのフォルダを選択した状態で(これ肝心らしい)→送る→圧縮(zip形式)フォルダ でzipファイルを作成。
それをデータアップロードページでアップロード
http://v-training.m5stack.com/
しばらく待つとメールで結果が返ってくる。
が、1回目の結果は
[V-Trainer] *** Online Training Request Failed
Hi! Sorry for that, there is some error happened during the training process. We attached the reason below, if you have any questions, welcome to report to us through Twitter, Facebook, or Forum. Or, check out our docs here: https://docs.m5stack.com/#/en/related_documents/v-training
USERID: *** CONTENT: Lake of Enough Train Dataset, Only 78 pictures found, but you need 90 in total.Notice:
Image 16.jpg was removed for being too close to 82.jpg, hashdiff: 2
Image 93.jpg was removed for being too close to 82.jpg, hashdiff: 2
・・・
自分のつたない英語力でも読み取れます。「90個以上の写真がないとだめだけど君のは78個しかなかったよ。ちなみに似た画像があったから消しちゃったよ。 」
なるほど。似た画像になってしまうのは避けられないので、これはいっぱい写真を撮るしかない、ということで2回目は各100枚の写真を撮って、再チャレンジ。
今度は成功。
[V-Trainer] *** Online Training Request Finished
Model: Classification MobileNetV1 Alpha: 0.7 Depth: 1
学習曲線がついていて、学習がうまくいったのか分かる仕組み。これが無料でつかえるとは有り難い。
メールのURLから結果ファイルをダウンロードして、中身をSDカードに書きこめばOK
SDカード直下のboot.pyが起動時に実行されるようなので、最初の撮影用のファイル一式は別フォルダ作って移動させておいた。
起動して、パソコン画面にカメラを向けると、「おお!判別している」 (文字ちっちゃ ) けど正答率はいまいち。
手持ち撮影による不安定さが原因かもしれないと思い、今度はカメラを台座に固定して、しっかり位置キープした状態で再々チャレンジ。
初めてのPython
M5StickV、ボタン押しにくい。台座に固定した状態ではなおさら。なので1回押したら100回連続で撮影するようにプログラムを修正することにした。
元のコード のこの部分に
try: while(True): img = sensor.snapshot() if but_a.value() == 0 and isButtonPressedA == 0: if currentImage <= 30 or currentImage > 35:
for文を追加
try: while(True): img = sensor.snapshot() if but_a.value() == 0 and isButtonPressedA == 0: for num in range(100): if currentImage <= 30 or currentImage > 35:
生まれて初めてのPythonプログラミング 。コンパイルとかせずに、ただ書いたコードをSDに入れるだけで動くというのも驚きの仕組み。
ドキドキしながらシャッター(Aボタン)オン → 画面固まる → カチャ音100回 → 同じ写真が100枚取れる。
forループの中に img = sensor.snapshot() を入れてなかった。サウンドも消してなかったので延々カチャカチャ。
それでもエラーではなかったので、気を取り直して修正。
validationデータが31-35の5枚だけなのもよくないかと思い、5枚に1枚をvalidationデータにするように修正。
try: while(True): img = sensor.snapshot() if but_a.value() == 0 and isButtonPressedA == 0: for num in range(100): #100回撮影 time.sleep(0.1) #100ms delay入れておく。 img = sensor.snapshot() #if currentImage <= 30 or currentImage > 35: if currentImage % 5 != 0: #5枚に1枚をvalidationデータにする #以下略。play_sound("/sd/kacha.wav")はコメントアウト
再々チャレンジの結果はまずまず。カメラ位置の調整はしないといけないが、ちゃんと3クラスの判別ができている。
こんなに簡単にAIカメラが作れるとは驚き。
試しているとフリーズする現象が発生。調子いい時もあるが、だいたい途中でフリーズする。USBシリアルでログを見てみると pmax=max(plist) のところで型エラーが起きているみたい。 Pythonの型が全く分かっていないのでエラーを読み解けない。とりあえず覚えたての必殺技 try: except: pass でエラー起きても無視させてみる。結果、フリーズすることはなくなった。こんなんでいいのかと思いながらも先に進む。
あとは「あ」の時にLEDを光らせる仕組みを入れる。
M5StickV自身にもLEDはついているがカメラ側についているのでこれは使えない。使えるピンはGroveコネクタのところだけなので、ここを使うしかない。LED光らせるだけなら直接ドライブさせてもいいと思うが、手持ちにLEDドライバの基板があったのでこれを利用。コード的には直接ドライブと一緒。
あとLCDの画面は位置合わせの時には便利だが、常時ついていると気になるので、ボタンを押したら消せるようにしてみた。
最終的なコードがこれ(初めてのPython)
import image import lcd import sensor import sys import time import KPU as kpu from fpioa_manager import * from board import board_info import KPU as kpu from Maix import GPIO fm.register(board_info.BUTTON_A, fm.fpioa.GPIO1) but_a=GPIO(GPIO.GPIO1, GPIO.IN, GPIO.PULL_UP) #PULL_UP is required here! fm.register(35, fm.fpioa.GPIOHS1, force=True) pinout35 = GPIO(GPIO.GPIOHS1, GPIO.OUT) pinout35.value(0) lcd.init() lcd.rotation(2) try: from pmu import axp192 pmu = axp192() pmu.enablePMICSleepMode(True) except: pass try: img = image.Image("/sd/startup.jpg") lcd.display(img) except: lcd.draw_string(lcd.width()//2-100,lcd.height()//2-4, "Error: Cannot find start.jpg", lcd.WHITE, lcd.RED) task = kpu.load("/sd/XXX_mbnet10_quant.kmodel") labels=["1","2","3"] #You can check the numbers here to real names. sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.set_windowing((224, 224)) sensor.run(1) lcd.clear() isButtonPressedA = 0 off_flg = 0 while(True): try: img = sensor.snapshot() fmap = kpu.forward(task, img) plist=fmap[:] pmax=max(plist) max_index=plist.index(pmax) if pmax > 0.95: # lcd.draw_string(40, 60, "Accu:%.2f Type:%s"%(pmax, labels[max_index].strip())) print(labels[max_index]) if max_index == 0: pinout35.value(1) else: pinout35.value(0) if but_a.value() == 0 and isButtonPressedA == 0: isButtonPressedA = 1 if off_flg == 0: lcd.set_backlight(False) lcd.clear() off_flg = 1 else: lcd.set_backlight(True) lcd.clear() off_flg = 0 if but_a.value() == 1: isButtonPressedA = 0 if off_flg == 0: a = lcd.display(img) except: pass a = kpu.deinit(task)
ファーストステップ完成
M5StickVでIMEの入力モード判別ができた🎵#M5Stack pic.twitter.com/enQfF1fcqe
— PikaPikaらいと (@KPmilk3) 2021年4月2日
セカンドステップ
M5StickVにはLCDとバッテリーがついていて便利なのだが、今回やりたいことに対してはこの機能は不要、むしろいらない機能といえる。
今回の目的に対してはUNIT-Vを使うのが最適なので、UNIT-Vで同じものを作ることにする。
2021/4/16現在、取組中。学習はいい結果が出せているが、モデルをUNIT-Vに入れて判別動作をさせると正答率がかなり悪いという問題で苦闘中。
その結果はまた記事にしたいと思います。
【作品まとめ】M5Stackで万華鏡
Twitterにあげていた作品のまとめ
ヤマザキミノリ先生のCUMOSを意識した作品です。 Twitterではガラスブロックと言ってますが多分アクリルの間違いです。キャン★ドゥで購入したものですが現在見かけません。買いだめしておけばよかった。M5Stackで万華鏡 その1
— PikaPikaらいと (@KPmilk3) 2021年2月26日
100均で見つけた直方体のガラスブロックを3個重ねることで広がりを出してます。#CUMOS を再現。と言いたいところですが、立体ではないので見えかたでおよびません😓立体にするには、さてどうするか🤔#M5Stack#万華鏡 pic.twitter.com/Hc0Oz2eA0m
LovyanGFXの描画が凄すぎて、あえてボールの数を減らしてますM5Stackで万華鏡 その2
— PikaPikaらいと (@KPmilk3) 2021年3月1日
ダイソーの万華鏡そのまま使ってます😅
表示プログラムはこれまたLovyanGFXのサンプルをちょっとだけ改造したもの
単純な方法ですがポテンシャルはあると思うので、もっといろいろやってみたいです🪞#M5Stack#万華鏡 pic.twitter.com/MZJo1b1zvF
カラーだとめまいを起こしそうなくらい激しかったので白黒に変換して投稿M5Stackで万華鏡 その3
— PikaPikaらいと (@KPmilk3) 2021年3月1日
つい出来心で
カラーだと点滅激しいのでモノクロにて#M5Stack#万華鏡#PartyParrot pic.twitter.com/oR9FZh753m
キモカワイさがお気に入りで、このシリーズは何種類も作りました。M5Stackで万華鏡 その4
— PikaPikaらいと (@KPmilk3) 2021年3月2日
想像を超えるものが生まれるところが万華鏡の醍醐味
表示プログラムはM5Stackライブラリのサンプルone_bit_Yin_Yangをちょこっと改造したものです#M5Stack#万華鏡 pic.twitter.com/6yM3gNyKeH
M5Stackで万華鏡 その5
— PikaPikaらいと (@KPmilk3) 2021年3月9日
絵柄の方を動かす事で変化させる#M5Stack #万華鏡#どこかの誰かに刺さればそれで良い pic.twitter.com/4UMjKyVsIr
M5Stackで万華鏡 その5の2
— PikaPikaらいと (@KPmilk3) 2021年3月13日
魚眼レンズで怪しさ倍増#M5Stack #万華鏡 pic.twitter.com/3EJgt9aauJ
M5Stackで万華鏡 その6#CUMOS っぽい絵柄
— PikaPikaらいと (@KPmilk3) 2021年3月13日
100均の魚眼レンズを装着
spriteの残像はあえて残して模様に#M5Stack #万華鏡 pic.twitter.com/uVfri9epl6