This post is Private. Only a writer or those who know its URL can access this post.

Article information
Show article in Markdown
Report article
Help us understand the problem. What is going on with this article?

プリンをもっと見守る技術をトレースして勉強した。途中でミクミンP氏のBrownieも。

ano研の「プリンをもっと見守る技術」の本をはじめからトレースして勉強しました。TensorFlow/Ketrasによるモデル作成部分はまだやっていない。V-Trainingは実施済。

第3章部分は、エラーが出るものと、動くものが、半々くらいあった。
第5章のQRコードを読み取る部分はできた。第6章のM5StackとUARTでつなぐのとM5StickCとUARTでつなぐのは行ってみたが無反応で動かなかった(残念)。

MaixPyIDEの準備

MaixPyIDEのダウンロード
MaixPyIDEv0.2.4からM5StickVに公式サポートされている。これまで、MaixPyIDEv0.2.3を使っていたので
新たにMaixPyIDEv0.2.4をダウンロードする。
MaixPyIDEv0.2.4の置き場が非常にわかりづらい。置いているのはここ。これはなかなかわからない。

http://dl.sipeed.com/MAIX/MaixPy/ide

20191022_11-11-18.JPG

MaixPyIDEv0.2.4をインストールします。

20191022_11-13-14.JPG

ツール>Select boardにM5stickVがあります。MaixPyIDEv0.2.3ではM5stickと表示されていて、Vの文字がありませんでした。これで公式サポートになったという意味なのでしょう。。。

M5StickVの動作確認の準備体操

ano研のgithubサイトから有用なプログラムをダウンロードして準備体操する
https://github.com/anoken/purin_wo_motto_mimamoru_gijutsu

準備体操

M5StickVの前のLEDを点灯させる

https://github.com/anoken/purin_wo_motto_mimamoru_gijutsu/tree/master/03_maixpy_example
の中の002_led_light.pyをMaixPyIDEに新しいファイルを作ってコピー&ペースト、接続、実行
StickVのAボタンを押すと前にあるLEDが点灯する。よし。ディスプレイは消えたまま。

M5StickVの中のIMUを調べる。SH200QとMPU6886のどちらが入っているか調べます。

004_imu_check.pyをコピペするとターミナルに
20191022_11-45-00.JPG
と表示されました。MPU6886では104, SH200Qでは108が戻ります。私の持っているM5StickVはSH200Qですね。52は電源管理ICのAXP192の戻り値です。
2台目購入は104が戻り値でMPU6886が入っていた。

加速度センサーを試す。

005_imu_SH200Q.pyを実行してみたら、ターミナルに非常に早く数値が流れ、M5StickVのディスプレイも数値が表示されています。でも数値が早く変化しすぎて数値は読めない状態です。

バッテリー容量を確認する。

007_AXP192_battery.pyを実行すると5秒ほどM5StickVのディスプレイに赤色の8行の電圧っぽいAXP192 の情報が表示されますがMaixPy側でErrorが出て止まりますね。よくわかりません。止まらず次に行きましょう。

カメラの画像をLCDに表示する。

009_camera_capture.pyを実行します。
このコードは基本ですね。

009_camera_capture.py
import sensor,image,lcd
lcd.init()
lcd.rotation(2)
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.run(1)
while True:
    img=sensor.snapshot()
    lcd.display(img)

ちなみに参考としてMaixPyの

Helloworld.pyはこれ

Helloworld.py
# Hello World Example
#
# Welcome to the MaixPy IDE!
# 1. Conenct board to computer
# 2. Select board at the top of MaixPy IDE: `tools->Select Board`
# 3. Click the connect buttion below to connect board
# 4. Click on the green run arrow button below to run the script!

import sensor, image, time, lcd

lcd.init(freq=15000000)
sensor.reset()                      # Reset and initialize the sensor. It will
                                    # 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 = 2000)     # Wait for settings take effect.
clock = time.clock()                # Create a clock object to track the FPS.

while(True):
    clock.tick()                    # Update the FPS clock.
    img = sensor.snapshot()         # Take a picture and return the image.
    lcd.display(img)                # Display on LCD
    print(clock.fps())              # Note: MaixPy's Cam runs about half as fast when connected
                                    # to the IDE. The FPS should increase once disconnected.

カメラ画像をSDファイルに記録する

010_camera_save_sdcard.pyを実行しようとしたら、MaixPyIDE上で'board_info' isn't definedとメッセージが出て
したのコードがあやしそうなんですがよくわかりません。止まっている時間はないので次に進めます。

20191022_12-14-16.JPG

また、今後このあたりが原因になって苦しみそうな予感が少ししますが。。。。

fm.register(board_info.BUTTON_A, fm.fpioa.GPIO1)

画像にフィルタをかける

011_image_filter.pyを実行。動いていますね。buttonAを押すといろいろなフィルターがかかることがわかります。

画像にカスタムフィルタをかける

012_image_custom_filter.pyを実行。うーん、またしても同じようなエラーメッセージが出た。止まりません。次に進めます。
20191022_12-27-30.JPG

KPUでニューラルネットワークを使う

kendryte K210はニューラルネットワークプロセッサKPUを搭載しています。
以下の特徴があります。
固定小数点モデルをサポートしています。ネットワーク層の数に制限はない。
1x1と3x3のサイズの畳み込みカーネルをサポートしています。複数の活性化のための機能をサポートしている。
パラメターサイズは5.5MiB~5.9MiBです。

学習データをM5StickVに入れる

http://dl.sipeed.com/MAIX/MaixPy/release/maixpy_v0.3.0/
のMaixPy 0.3 demo firmware.zipをダウンロードする。

SDカード内のファイルのリストを見る
013_filelist.pyで実行
20191022_12-55-51.JPG

2台目購入したM5StickVのflashのversionがわかった。
1代目もMicroPython v0.4.0-39-g083e0cca5-dirty on 2019-08-13に戻せば、V-Trainingが動くようになるかも。翌日、実際にkflashでmaixpy_v0.4.0_39_g083e0cc_m5stickv.binのみを入れて、MicroSDにV-Traningファイルを入れると動き出した。

20191022_23-51-18.JPG

014_kpu_camera_mnist.pyを実行
数字の認識率悪いがとりあえず認識する。

015_kpu_camera_face_detect.pyを実行
faceを認識したら四角で囲う。認識時に前のLEDライトが赤くつく。

016_kpu_camera_20class.py
しっかり動きますね。

017_kpu_camera_1000class.py
これは初め残念ながらエラーになってしまいます。
でも、コードにtypoを発見しました。

20191023_00-19-57.JPG

20191023_00-20-11.JPG
に変更したら動きます。(mbnet751.kmodelでなくてmbnet75.kemodelです)

よかった。

ano研の方が、Qiitaにデモデータを全部入れる方法を書いてくれている
これ
M5StickVのMaixPyにdemoデータを全部入れる

018_play_wav.py
スピーカーから音声ファイルを再生する。
ボタンAを押したらエラー画面がでて音はならない。
20191022_13-36-40.JPG

019_LCD_draw_face.pyを実行
うまく顔の絵が動く。

020_LCD_acc_rot_face.pyを実行
顔の図を傾きに合わせて回転させる。うまく動いている。

QRコードを読んで電気錠を開けるコードを試す。

purin_wo_motto_mimamoru_gijutsu/05_pudding_rock_app/pudding_rock_app.py
https://github.com/anoken/purin_wo_motto_mimamoru_gijutsu/blob/master/05_pudding_rock_app/pudding_rock_app.py

pudding_rock_app.pyを試してみる。
LINEの自分のQRコードを読むと、ターミナルでhttp://line.naver.jp/ti/p/XXXXXXXXXXが読まれていることは分かった。電気錠はつないでいないのでよくわからない。

Brownieを試す

ミクミンP氏が考案した転移学習をM5StickVで計算するアルゴリズムがある。Brownieに使われている。M5StickVのKPUで演算する。
https://github.com/ksasao/brownie
ダウンロードファイルはこれ
https://github.com/ksasao/brownie/releases/download/1.0.1/brownie_v1.0.1.zip

Brownieはエラーも出ずしっかり動く。

boot.py
import audio
import gc
import image
import lcd
import sensor
import sys
import time
import uos
import KPU as kpu
from fpioa_manager import *
from machine import I2C
from Maix import I2S, GPIO

#
# initialize
#
lcd.init()
lcd.rotation(2)
i2c = I2C(I2C.I2C0, freq=400000, scl=28, sda=29)

fm.register(board_info.SPK_SD, fm.fpioa.GPIO0)
spk_sd=GPIO(GPIO.GPIO0, GPIO.OUT)
spk_sd.value(1) #Enable the SPK output

fm.register(board_info.SPK_DIN,fm.fpioa.I2S0_OUT_D1)
fm.register(board_info.SPK_BCLK,fm.fpioa.I2S0_SCLK)
fm.register(board_info.SPK_LRCLK,fm.fpioa.I2S0_WS)

wav_dev = I2S(I2S.DEVICE_0)

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(board_info.BUTTON_B, fm.fpioa.GPIO2)
but_b = GPIO(GPIO.GPIO2, GPIO.IN, GPIO.PULL_UP) #PULL_UP is required here!

fm.register(board_info.LED_W, fm.fpioa.GPIO3)
led_w = GPIO(GPIO.GPIO3, GPIO.OUT)
led_w.value(1) #RGBW LEDs are Active Low

fm.register(board_info.LED_R, fm.fpioa.GPIO4)
led_r = GPIO(GPIO.GPIO4, GPIO.OUT)
led_r.value(1) #RGBW LEDs are Active Low

fm.register(board_info.LED_G, fm.fpioa.GPIO5)
led_g = GPIO(GPIO.GPIO5, GPIO.OUT)
led_g.value(1) #RGBW LEDs are Active Low

fm.register(board_info.LED_B, fm.fpioa.GPIO6)
led_b = GPIO(GPIO.GPIO6, GPIO.OUT)
led_b.value(1) #RGBW LEDs are Active Low


def play_sound(filename):
    try:
        player = audio.Audio(path = filename)
        player.volume(100)
        wav_info = player.play_process(wav_dev)
        wav_dev.channel_config(wav_dev.CHANNEL_1, I2S.TRANSMITTER,resolution = I2S.RESOLUTION_16_BIT, align_mode = I2S.STANDARD_MODE)
        wav_dev.set_sample_rate(wav_info[1])
        while True:
            ret = player.play()
            if ret == None:
                break
            elif ret==0:
                break
        player.finish()
    except:
        pass

def set_backlight(level):
    if level > 8:
        level = 8
    if level < 0:
        level = 0
    val = (level+7) << 4
    i2c.writeto_mem(0x34, 0x91,int(val))

def show_logo():
    try:
        img = image.Image("/sd/logo.jpg")
        set_backlight(0)
        lcd.display(img)
        for i in range(9):
            set_backlight(i)
            time.sleep(0.1)
        play_sound("/sd/logo.wav")

    except:
        lcd.draw_string(lcd.width()//2-100,lcd.height()//2-4, "Error: Cannot find logo.jpg", lcd.WHITE, lcd.RED)

def initialize_camera():
    err_counter = 0
    while 1:
        try:
            sensor.reset() #Reset sensor may failed, let's try some times
            break
        except:
            err_counter = err_counter + 1
            if err_counter == 20:
                lcd.draw_string(lcd.width()//2-100,lcd.height()//2-4, "Error: Sensor Init Failed", lcd.WHITE, lcd.RED)
            time.sleep(0.1)
            continue

    sensor.set_pixformat(sensor.RGB565)
    sensor.set_framesize(sensor.QVGA) #QVGA=320x240
    sensor.run(1)

#
# main
#
show_logo()
if but_a.value() == 0: #If dont want to run the demo
    set_backlight(0)
    print('[info]: Exit by user operation')
    sys.exit()
initialize_camera()

classes = ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']
task = kpu.load("/sd/model/20class.kmodel")
task_face = kpu.load(0x300000) # default face detection model on flash memory
# task_face = kpu.load("/sd/model/facedetect.kmodel") # you can extract the model from default .kfpkg

anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025)
# Anchor data is for bbox, extracted from the training sets.
kpu.init_yolo2(task, 0.5, 0.3, 5, anchor)
kpu.init_yolo2(task_face, 0.5, 0.3, 5, anchor)

print('[info]: Started.')
but_stu = 1

try:
    while(True):
        #gc.collect()
        img = sensor.snapshot()
        code_obj = kpu.run_yolo2(task, img)
        code_face = kpu.run_yolo2(task_face, img)

        if code_obj: # object detected
            max_id = 0
            max_rect = 0
            for i in code_obj:
                img.draw_rectangle(i.rect())
                text = ' ' + classes[i.classid()] + ' (' + str(int(i.value()*100)) + '%) '
                for x in range(-1,2):
                    for y in range(-1,2):
                        img.draw_string(x+i.x(), y+i.y()+(i.h()>>1), text, color=(250,205,137), scale=2,mono_space=False)
                img.draw_string(i.x(), i.y()+(i.h()>>1), text, color=(119,48,48), scale=2,mono_space=False)
                id = i.classid()
                rect_size = i.w() * i.h()
                if rect_size > max_rect:
                    max_rect = rect_size
                    max_id = id
            if but_a.value() == 0:
                play_sound("/sd/voice/ja/"+str(max_id)+".wav")

        if code_face: # face detected
            max_id = 0
            max_rect = 0
            for i in code_face:
                img.draw_rectangle(i.rect(),color=31)

        lcd.display(img)
except KeyboardInterrupt:
    kpu.deinit(task)
    sys.exit()

ニューラルネットワークの途中の層を取り出す。
purin_wo_motto_mimamoru_gijutsu/06_pudding_alert_v_app/

001_kpu_fmap_view.pyを実行
002_purin_learning.pyを実行
どちらもエラー画面が出る。きついなこれ。

image.png

003_purin_learning_improve_filter.pyもエラーがでる。このプログラムで動くのだったら、すごいプログラムだと思う。重みづけ更新フィルタを入れているらしい。
image.png

M5StickVとM5StackをUARTでつなぐ

MaixPyはFPIOAという機能でGPIOに任意の機能を割り付けることができる。
M5StickVはGPIO34とGPIO35に別のモジュールと接続するためのGroveコネクターがあるので、GPIO34とGPIO35にUART機能を割り付ける。
005_uart_image_send_m5stickv.pyをStickVにインストール
005_uart_image_receive_and_send_line_m5stickc_arduino.inoをインストール
しても、動かなかった。
MaixPyのターミナルはボタンをAを押したら数字が動くが、LINE Notifyに画像が送られることはなかった。

M5StickC側に入れるコードは以下の通り。ssid,passwd,tokenは自分のものに書き換えた。

005_uart_image_receive_and_send_line_m5stickc_arduino.ino
// Copyright (c) 2019 aNoken 
// https://anoken.jimdo.com/
// https://github.com/anoken/purin_wo_motto_mimamoru_gijutsu
// Arduino IDE compile code

#include <M5StickC.h>
#include <WiFi.h>
#include <ssl_client.h>
#include <WiFiClientSecure.h>
const char* ssid = "your_ssid";
const char* passwd = "your_passwd";

const char* host = "notify-api.line.me";
const char* token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; //トークンを入れる場所2か所ある。これは一か所目。

HardwareSerial serial_ext(2);

typedef struct {
  uint32_t length;
  uint8_t *buf;
} jpeg_data_t;

jpeg_data_t jpeg_data;
static const int RX_BUF_SIZE = 30000;
static const uint8_t packet_begin[3] = { 0xFF, 0xD8, 0xEA };

//https://github.com/anoken/purin_wo_mimamoru_gijutsu/blob/master/2_6_M5Camera_Send_LineNotify/2_6_M5Camera_Send_LineNotify.ino
void sendLineNotify(uint8_t* image_data, size_t image_sz);
void setup_wifi() ;
void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.setCursor(0, 30, 4);
  M5.Lcd.println("m5stick_uart_wifi_converter");

  setup_wifi();

  jpeg_data.buf = (uint8_t *) malloc(sizeof(uint8_t) * RX_BUF_SIZE);
  jpeg_data.length = 0;
  if (jpeg_data.buf == NULL) {
    Serial.println("malloc jpeg buffer 1 error");
  }

  serial_ext.begin(115200, SERIAL_8N1, 32, 33);
}

void loop() {
  M5.update();

  if (serial_ext.available()) {
    uint8_t rx_buffer[10];
    int rx_size = serial_ext.readBytes(rx_buffer, 10);
    if (rx_size == 10) {   //packet receive of packet_begin
      if ((rx_buffer[0] == packet_begin[0]) && (rx_buffer[1] == packet_begin[1]) && (rx_buffer[2] == packet_begin[2])) {
        //image size receive of packet_begin
        jpeg_data.length = (uint32_t)(rx_buffer[4] << 16) | (rx_buffer[5] << 8) | rx_buffer[6];
        int rx_size = serial_ext.readBytes(jpeg_data.buf, jpeg_data.length);

        //image processing, for example, line notify send image
        sendLineNotify(jpeg_data.buf, jpeg_data.length);
        //image processing end
      }
    }
  }
  vTaskDelay(10 / portTICK_RATE_MS);
}

void setup_wifi() {
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, passwd);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}


//Line通知
void sendLineNotify(uint8_t* image_data, size_t image_sz) {
  const char* host = "notify-api.line.me";
  const char* token = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; //トークンを入れる場所2か所ある。これは2か所目。

  WiFiClientSecure client;
  if (!client.connect(host, 443))   return;
  int httpCode = 404;
  size_t image_size = image_sz;
  String boundary = "----purin_alert--";
  String body = "--" + boundary + "\r\n";
  String message = "m5stickVで撮影!!!";
  body += "Content-Disposition: form-data; name=\"message\"\r\n\r\n" + message + " \r\n";
  if (image_data != NULL && image_sz > 0 ) {
    image_size = image_sz;
    body += "--" + boundary + "\r\n";
    body += "Content-Disposition: form-data; name=\"imageFile\"; filename=\"image.jpg\"\r\n";
    body += "Content-Type: image/jpeg\r\n\r\n";
  }
  String body_end = "--" + boundary + "--\r\n";
  size_t body_length = body.length() + image_size + body_end.length();
  String header = "POST /api/notify HTTP/1.1\r\n";
  header += "Host: notify-api.line.me\r\n";
  header += "Authorization: Bearer " + String(token) + "\r\n";
  header += "User-Agent: " + String("M5Stack") + "\r\n";
  header += "Connection: close\r\n";
  header += "Cache-Control: no-cache\r\n";
  header += "Content-Length: " + String(body_length) + "\r\n";
  header += "Content-Type: multipart/form-data; boundary=" + boundary + "\r\n\r\n";
  client.print( header + body);
  Serial.print(header + body);

  bool Success_h = false;
  uint8_t line_try = 3;
  while (!Success_h && line_try-- > 0) {
    if (image_size > 0) {
      size_t BUF_SIZE = 1024;
      if ( image_data != NULL) {
        uint8_t *p = image_data;
        size_t sz = image_size;
        while ( p != NULL && sz) {
          if ( sz >= BUF_SIZE) {
            client.write( p, BUF_SIZE);
            p += BUF_SIZE; sz -= BUF_SIZE;
          } else {
            client.write( p, sz);
            p += sz; sz = 0;
          }
        }
      }
      client.print("\r\n" + body_end);
      Serial.print("\r\n" + body_end);

      while ( client.connected() && !client.available()) delay(10);
      if ( client.connected() && client.available() ) {
        String resp = client.readStringUntil('\n');
        httpCode    = resp.substring(resp.indexOf(" ") + 1, resp.indexOf(" ", resp.indexOf(" ") + 1)).toInt();
        Success_h   = (httpCode == 200);
        Serial.println(resp);
      }
      delay(10);
    }
  }
  client.stop();
}
005_uart_image_send_m5stickv.py
## Copyright (c) 2019 aNoken 
## https://anoken.jimdo.com/
## https://github.com/anoken/purin_wo_motto_mimamoru_gijutsu

import network, socket, sensor, image, lcd
from Maix import GPIO
from fpioa_manager import fm, board_info
from machine import UART

lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.run(1)
fm.register(35, fm.fpioa.UART2_TX, force=True)
fm.register(34, fm.fpioa.UART2_RX, force=True)
uart_Port = UART(UART.UART2, 115200,8,0,0, timeout=1000, read_buf_len= 4096)
but_a=GPIO(GPIO.GPIO1, GPIO.IN, GPIO.PULL_UP)

fm.register(board_info.BUTTON_A, fm.fpioa.GPIO1)
but_a=GPIO(GPIO.GPIO1, GPIO.IN, GPIO.PULL_UP)

but_a_pressed = 0


while True:
    img = sensor.snapshot()
    lcd.display(img)
    if but_a.value() == 0 and but_a_pressed == 0:
        img_buf = img.compress(quality=70)
        img_size1 = (img.size()& 0xFF0000)>>16
        img_size2 = (img.size()& 0x00FF00)>>8
        img_size3 = (img.size()& 0x0000FF)>>0
        data_packet = bytearray([0xFF,0xD8,0xEA,0x01,
        img_size1,img_size2,img_size3,0x00,0x00,0x00])
        uart_Port.write(data_packet)
        uart_Port.write(img_buf)
        time.sleep(1.0)
        but_a_pressed=1
    if but_a.value() == 1 and but_a_pressed == 1:
        but_a_pressed=0

uart_Port.deinit()
del uart_Port

Grove端子のケーブルを普通につないで動作を確認できた。

参考
Wi-FiがないM5StickVを、M5StickCと繋ぎLINEに投稿してみるまでの手順
https://qiita.com/nnn112358/items/5efd926fea20cd6c2c43

ミクミンP/Kazuhiro Sasaoさんのプログラムを動かした

Maker Faire Taipei 2019 Kitをダウンロードしてプログラムを動かした
https://github.com/ksasao/brownie/releases

20191031_07-48-55.JPG

QRコードで学習スタート
学習用画像は1枚のみ
検出したら、音楽が鳴ったり、slackにお知らせが届いたりする。素晴らしすぎる。
20191031_07-39-08.JPG

20191031_07-39-47.JPG

実際に需要のある実験室の画像で試した。奥のPCの画面内にエラー画面が出ると、Slackにメッセージが飛んでくることを試した結果、成功した。つまり、QRコードで学習開始、1枚のみの学習で学習完了、異常を検出したらSlackにお知らせ。これで、異常が出たら、すぐに知ることができる。
実験室でテストしている風景はこれ
20191031_18-51-36.JPG

LINE Notifyに送るには以下のSend2LineNotify.pyを作成してpython Send2LineNotify.py
で送ることができる。
参考サイトは超便利&お手軽】Python + LINE NotifyでLINEメッセージ送信
https://blue-black.ink/?p=3935

Send2LineNotify.py
# Send2LineNotify.py
#coding: UTF-8

import requests

token = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'     # Your_Line_Tokenを入力する

payload = {'message': 'M5StickVが物体04を検出した!'}  # 送信メッセージを右側に入力する
url = 'https://notify-api.line.me/api/notify'
headers = {'Authorization': 'Bearer ' + token}

res = requests.post(url, data=payload, headers=headers)  # LINE NotifyへPOST
print(res)

LINE Notifyに送った画面はこれ
20191101_02-51-42.jpg

Slackに送るには以下のSend2Slack.pyを作成してpython Send2Slack.py
で送ることができる。

Send2Slack.py
#coding: UTF-8

import slackweb

slack = slackweb.Slack(url="https://hooks.slack.com/services/XXXXXXXXX/ZZZZZZZZZ/xxxxxxxxxxxxxxxxxxxxxxx")
slack.notify(text="M5StickVがObject03を検出した")

ミクミンPさんのBrownieMonitorを新たなPCで動かす(2019/11/07)

ミクミンPさんのBrownieMonitorを新たなWindows7のノートPCで動かすための必要手順は
python公式サイトでpythonのインストール(ver3.7.5をインストールした)ファイルは、Windows x86 executable installerをダウンロードしてインストールした。
https://www.python.org/
から入ってダウンロードサイトはここ
https://www.python.org/downloads/windows/
その後、コマンドプロンプトで
pip install requests
でrequestsのHTTP 通信ライブラリをインストールする
以上で動く

CAMPFIREにプロジェクトを作った。(2019/11/10)

CAMPFIREにプロジェクトを作った。
限定公開URLはこちら
https://camp-fire.jp/projects/211754/preview?token=1fi4q7fr

現在の自分で気づいた課題は
-画像が良くない。
-文章が簡潔でない。

ミクミンPさんのBwownieMoniterをM5StickCで実現させる準備(2019/11/10)

M5StickV側のBrownieのQRコードを Object01 ではなく 数字の1に変更した。
その後、m5StickCにarduinoで以下のコードを入れた。M5StickVのBrownieで数字の1と2の物体を認識させたところ、
シリアルモニターに数字が飛んでくる(VとCをgroveケーブルで接続した(UART接続)。そして、PCとstickCをつないでいる。)

このサイトを参考にした
https://lang-ship.com/reference/unofficial/M5StickC/Peripherals/UART/
Grove側の32と33を使って接続しています。 M5StickVから送信されたデータをSerial2(Grove)で受信して、Serial(USB)に送信しています。 また、Serial(USB)から送信されたデータをSerial2(Grove)に送信しています。

ConnectForstickC001.c
#include <M5StickC.h>

void setup() {
  M5.begin();

  Serial2.begin(115200, SERIAL_8N1, 32, 33);
}

void loop() {
  if (Serial2.available()) {
    int inByte = Serial2.read();
    Serial.write(inByte);
  }

  if (Serial.available()) {
    int inByte = Serial.read();
    Serial2.write(inByte);
  }
}

image.png

LINE notifyに条件なしで1回メッセージを送るプログラムに、上のプログラムを加え、シリアルモニターでStickVから学習させた数字が送られてくることを確認した。書き込んだ時にLINE notifyにも送られてくる。

M5stickC_LINENotify_Serial_number.c
#include <M5StickC.h>
#include <WiFi.h>
#include <ssl_client.h>
#include <WiFiClientSecure.h>

/* LINENofifyの設定 */
const char* host = "notify-api.line.me";
const char* token = "UG6PDgyBgTf1JAMI5A3LrObojzMZh7EibvbIKQ5U2Om";

HardwareSerial serial_ext(2);

void setup() {
  M5.begin();    //M5Stackを起動する
  wifi_connect();   //Wifiに接続する
  send_line_alert();  //LINEへの送信
  M5.Lcd.setRotation(1);
  M5.Lcd.setCursor(2, 30, 2);
  M5.Lcd.println("StickC_Wifi_Connected");
  Serial2.begin(115200, SERIAL_8N1, 32, 33); 
}

void loop() {
  M5.update();    //M5Stackの内部処理を更新
  delay(500);

  //田中さんと調べた部分。シリアルモニターでStickVから送られた数字が表示される。
  //https://lang-ship.com/reference/unofficial/M5StickC/Peripherals/UART/
  if (Serial2.available()) {
    int inByte = Serial2.read();   //Serial2(Grove)で受信したデータをSerial(USB)に送信というサンプル  
    Serial.write(inByte);  
    if (inByte == 1){
    send_line_alert();
    }
    }
  }



 /* Wifiに接続する */
void wifi_connect() { 
  const char* ssid = "village";
  const char* password = "hrsmk2525";
  //WiFi接続開始
  WiFi.begin(ssid, password);
  //接続状態になるまで待つ
  while (WiFi.status() != WL_CONNECTED)  delay(500);
  Serial.println(WiFi.localIP());
}

 /* LINEへの送信 */
void send_line_alert() {
  const char* message1 = "LabCamと接続できた。";
  WiFiClientSecure client;
  //LineのAPIサーバに接続
  if (!client.connect(host, 443)) {
    return;
  }
  /* LINE NotifyのサーバへHTTPS通信でメッセージをPOSTする リクエストを送信 */
  String query = "message=" + String(message1);

  String request = String("") +
                   "POST /api/notify HTTP/1.1\r\n" +
                   "Host: " + host + "\r\n" +
                   "Authorization: Bearer " + token + "\r\n" +
                   "Content-Length: " + String(query.length()) +  "\r\n" +
                   "Content-Type: application/x-www-form-urlencoded\r\n\r\n" +
                   query + "\r\n";

  client.print(request);

   //受信終了まで待つ 
  while (client.connected()) {
    String line_str = client.readStringUntil('\n');
    if (line_str == "\r")   break;
  }
}



もう一度ゼロから作る意味で、別のQiitaを見て書いてみた。
ESP32とLINE Notifyを使ってナースコール的なのを作る
https://qiita.com/From_F/items/6fc59c50f139f40e52dc
を参考に、書いてみた。

M5StickVから送られてくる数字が3種類であると仮定して、書いてみた。ArduinoIDEでソースを書き込んだ時は、LINENotifyに送られてくるが、M5StickVで画像認識させて数字をM5StickCに送っても、シリアルモニターには数字が送られてきているが、LINE Notifyには送られてこない。何かが間違っている。

V_to_C_3number_LineNotify.c
#include <M5StickC.h>
#include <WiFi.h>
#include <ssl_client.h>
#include <WiFiClientSecure.h>


HardwareSerial serial2(2);

void setup() {
  M5.begin();    //M5Stackを起動する
  wifi_connect();   //Wifiに接続する
  send("LabCam was connected"); //LINEへ引数を含めて送信
  M5.Lcd.setRotation(1);
  M5.Lcd.setCursor(2, 30, 2);
  M5.Lcd.println("StickC_Wifi_Connected");
  Serial2.begin(115200, SERIAL_8N1, 32, 33); 
}

void loop() {
  M5.update();
  delay(500);
  if (Serial2.available()) {
  int inByte = Serial2.read(); 
  Serial.write(inByte);
    if (inByte == 1) {
    M5.Lcd.print('1 was detected');
    send("1 was detected");
  } else if (inByte == 2) {
    M5.Lcd.print('2 was detected');
    send("2 was detected");
  } else if (inByte == 3) {
    M5.Lcd.print('3 was detected');
    send("3 was detected");
    }
  }
}


 /* Wifiに接続する */
void wifi_connect() { 
  const char* ssid = "YOUR_SSID";
  const char* password = "YOUR_PASSWORD";
  //WiFi接続開始
  WiFi.begin(ssid, password);
  //接続状態になるまで待つ
  while (WiFi.status() != WL_CONNECTED)  delay(500);
  Serial.println(WiFi.localIP());
}


void send(String message) {
  const char* host = "notify-api.line.me";
  const char* token = "XXXXXXXXXXXXXXXX_YOUR_TOKEN_XXXXXXXXXXXXXXXXXXXX";
  WiFiClientSecure client;
  Serial.println("Try");
  //LineのAPIサーバに接続
  if (!client.connect(host, 443)) {
    Serial.println("Connection failed");
    return;
  }
  Serial.println("Connected");
  //リクエストを送信
  String query = String("message=") + message;
  String request = String("") +
               "POST /api/notify HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "Authorization: Bearer " + token + "\r\n" +
               "Content-Length: " + String(query.length()) +  "\r\n" + 
               "Content-Type: application/x-www-form-urlencoded\r\n\r\n" +
                query + "\r\n";
  client.print(request);

  //受信終了まで待つ 
  while (client.connected()) {
    String line = client.readStringUntil('\n');
    Serial.println(line);
    if (line == "\r") {
      break;
    }
  }

  String line = client.readStringUntil('\n');
  Serial.println(line);
}







image.png

MikH
ProtoOut Studio 1期生,  Call for Code 2019 Regional Finalist(2019年10月),  IBM Chamipon,  医学博士  
protoout-studio
ProtoOut Studioは日本初のプロトタイピング専門スクールです。プログラミングとプランニング(企画)の両方のスキルを兼ね備えた人材輩出を行います。作って発信して、がんがんプロトアウトしていきましょう。
https://protoout.studio
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした