UnitV で金魚ステータス判別テスト ーエッジAI活用への道 15ー
金魚水槽監視システムがだいぶ形になってきまして、いよいよ本題のエッジAIの活用です。
ここではUnitVで金魚を認識してその座標から金魚のステータスを判別できるかの検証です。
金魚は寝るとプカ~っと水中で浮いているので、就寝中は座標が変化しないはずです。
それでは実験スターティン
目次
構成
UnitVとM5StickCを4ピンケーブルで接続して、UnitVで金魚を認識して 座標をUARTでM5StickCに送ります。
M5StickCは受け取った金魚座標をWiFiでUDPブロードキャストします。
オリジナル金魚モデルで画像認識
金魚の認識モデルは以前に作ったお手製のものを使用します。
ファームウェアは M5StickV_Firmware_1022_beta.kfpkg を使用し、 Kflash_GUIで書き込みました。
金魚モデル(kmodelファイル)はアドレス0x600000に書き込みました。
UnitVコード(MaixPy IDE)
コードはYolo-digit-detector/micropython_code/racoon_detector.py を参考にして作成し、MaixPy IDEで書き込みました。
金魚を認識して その中心座標(x, y)をUART送信します。
画角は224×224。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
from machine import UART from board import board_info from fpioa_manager import fm from Maix import GPIO import sensor,image,lcd import KPU as kpu lcd.init() sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.set_windowing((224, 224)) sensor.set_vflip(1) sensor.set_hmirror(1) sensor.run(1) fm.register(35, fm.fpioa.UART1_TX, force=True) fm.register(34, fm.fpioa.UART1_RX, force=True) uart = UART(UART.UART1, 115200,8,0,0, timeout=1000, read_buf_len=4096) classes = ["goldfish"] task = kpu.load(0x600000) #task = kpu.load("/sd/model246pic.kmodel") anchor = (0.57273, 0.677385, 1.87446, 2.06253, 3.33843, 5.47434, 7.88282, 3.52778, 9.77052, 9.16828) a = kpu.init_yolo2(task, 0.3, 0.3, 5, anchor) while(True): img = sensor.snapshot() code = kpu.run_yolo2(task, img) if code: for i in code: a = img.draw_cross(i.x()+int(i.w()/2),i.y()+int(i.h()/2),color = (0, 255, 0),size=5,thickness=4) data_packet = bytearray([0xFF,0xD8,0xEA,0x01,i.index(),i.x()+int(i.w()/2),i.y()+int(i.h()/2),0x00,0x00,0x00]) uart.write(data_packet) a = lcd.display(img) else: a = lcd.display(img) a = kpu.deinit(task) |
この投稿をInstagramで見る
M5StickCコード(Arduino IDE)
UnitVからの金魚座標をM5StickCで受けてUDPで送信しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
#include <WiFi.h> #include <WiFiUDP.h> #include <M5StickC.h> static WiFiUDP wifiUdp; static const char *kRemoteIpadr = "192.168.0.255"; static const int kRmoteUdpPort = 9000; //送信先のポート const char* ssid = "WiFiのSSID"; const char* password = "パスワード"; static const uint8_t packet_begin[3] = { 0xFF, 0xD8, 0xEA }; void setup() { M5.begin(); M5.Axp.ScreenBreath(0); Serial.begin(115200); Serial2.begin(115200, SERIAL_8N1, 32, 33); static const int kLocalPort = 7000; //自身のポート WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); Serial.println(""); // Wait for connection while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } wifiUdp.begin(kLocalPort); Serial.println(""); Serial.print("Connected to "); Serial.println(ssid); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } void loop() { if (Serial2.available()) { uint8_t rx_buffer[10]; int rx_size = Serial2.readBytes(rx_buffer, 10); if (rx_size == 10) { if ((rx_buffer[0] == packet_begin[0]) && (rx_buffer[1] == packet_begin[1]) && (rx_buffer[2] == packet_begin[2])) { Serial.print(rx_buffer[4]); Serial.print(":"); Serial.print(rx_buffer[5]); Serial.print(","); Serial.println(rx_buffer[6]); wifiUdp.beginPacket(kRemoteIpadr, kRmoteUdpPort); wifiUdp.print(rx_buffer[4]); wifiUdp.print(":"); wifiUdp.print(rx_buffer[5]); wifiUdp.write(','); wifiUdp.print(rx_buffer[6]); wifiUdp.endPacket(); } } } } |
実験の様子
UnitVで水槽を監視して金魚ちゃんの位置を認識します。
UnitVで金魚ちゃんの座標ログとってみる。
目的:金魚ちゃんのステータスの識別
就寝中とか草食べ中とか
ゴール:就寝中の様子を自動録画#UnitV #金魚 pic.twitter.com/r70LucncYY— HomeMadeGarbage (@H0meMadeGarbage) February 11, 2020
水槽の横にUnitVを配置してデータをとってみました。
仰々しい金魚システム pic.twitter.com/Oxc7bBLlim
— HomeMadeGarbage (@H0meMadeGarbage) February 11, 2020
座標プロット
M5StickCからUDP送信される座標(x:横、y:縦)をPCで受けてプロットいたしました。
以下、縦軸が$\sqrt{x^2+y^2}$ 横軸が時刻のグラフです。
グラフより1時~5時の間で明らかに移動量が減っており就寝していることが見て取れます。
意外とガッツリ休んでるんですねww
なんだか可愛い 😀
おわりに
AIカメラで金魚を認識し、その座標から移動量の推移を監視して金魚の就寝が判別できそうだという結論に至りました。
次はこの移動量から就寝を検知して自動動画撮影を目指したいと思います。
ではまた!
参考
- UnitV – M5StickC 間 UART送信手法
https://gist.github.com/anoken/8b0ce255e9aef9d1a7f4d46272cedcaa