はじめに
touch-sp.hatenablog.com
前回はiPhoneを使った。アクションカメラの方が軽量なのでそちらでもチャレンジ。
アクションカメラは安さ優先で「APEMAN A79」を選択。
1. まずはサーボの上にカメラを乗せた。(多少の工作が必要)
Arduino用、サーボ用、カメラ用(カメラのバッテリー)の3つの電源を使っている(笑)。PCの電源も含めると4つ。
2. カメラ画像をWi-Fi経由でPCに送信。
3. PC内で画像内の顔を検出し、XBee経由でArduinoにサーボを動かす命令を送信。
4. Arduinoはサーボを動かすだけ。
環境
OpenCVではどうしてもうまくいかなかった。
代わりにVLC media playerを使用したので、あらかじめインストールが必要。
Windows10 Pro NVIDIA GeForce GTX1080 Python 3.7.7 VLC media player 3.0.10 Arduino IDE 1.8.12 Arduino Uno R3
- 2020年6月5日追記
バージョン確認(pip freeze)
Pythonパッケージでインストールが必要なのは「mxnet-cu101]と「gluoncv」と「python-vlc」と「pyserial」のみ。
pip install https://repo.mxnet.io/dist/python/cu101/mxnet_cu101-1.6.0-py2.py3-none-win_amd64.whl pip install gluoncv pip install python-vlc pip install pyserial
その他は勝手についてくる。
certifi==2020.4.5.1 chardet==3.0.4 cycler==0.10.0 gluoncv==0.7.0 graphviz==0.8.4 idna==2.6 kiwisolver==1.2.0 matplotlib==3.2.1 mxnet-cu101 @ https://repo.mxnet.io/dist/python/cu101/mxnet_cu101-1.6.0-py2.py3-none-win_amd64.whl numpy==1.16.6 Pillow==7.1.2 portalocker==1.7.0 pyparsing==2.4.7 pyserial==3.4 python-dateutil==2.8.1 python-vlc==3.0.9113 pywin32==227 requests==2.18.4 scipy==1.4.1 six==1.15.0 tqdm==4.46.0 urllib3==1.22
Pythonコード
import mxnet as mx import gluoncv import serial, time import vlc ctx = mx.gpu() # Load the model classes = ['face'] net = gluoncv.model_zoo.get_model('ssd_512_mobilenet1.0_custom', classes=classes, pretrained=False, root='./model') net.load_parameters('ssd_512_mobilenet1.0_face.params') net.collect_params().reset_ctx(ctx) # Compile the model for faster speed net.hybridize() pl = vlc.MediaPlayer('rtsp://192.72.1.1:554/liveRTSP/av4/track0') pl.play() time.sleep(1) ser =serial.Serial("COM4", 9600) time.sleep(1.5) #初期設定 servo_angle = 90 while(True): try: #bufferがゼロになるまで待つ finished = False while not finished: finished = (ser.out_waiting == 0) pl.video_take_snapshot(0,'.snapshot.tmp.png', 0, 0) # Image pre-processing rgb_nd, frame = gluoncv.data.transforms.presets.ssd.load_test('.snapshot.tmp.png', short=360) # Run frame through network class_IDs, scores, bounding_boxes = net(rgb_nd.as_in_context(ctx)) if scores[0][0] > 0.6: x_min = bounding_boxes[0][0][0] y_min = bounding_boxes[0][0][1] x_max = bounding_boxes[0][0][2] y_max = bounding_boxes[0][0][3] if x_min > 360: if x_min > 480: servo_angle += 15 else: servo_angle += 3 if x_max < 280: if x_max <160: servo_angle -= 15 else: servo_angle -= 3 servo_angle = 160 if servo_angle > 160 else servo_angle servo_angle = 20 if servo_angle < 20 else servo_angle send_data = servo_angle.to_bytes(1, 'big') ser.write(send_data) ser.write((255).to_bytes(1, 'big')) time.sleep(0.8) except KeyboardInterrupt: print("プログラムを終了します") break pl.stop() ser.close()
Arduinoスケッチ
#include <Servo.h> Servo myServo; int var = 90; int dummy; void setup() { myServo.attach(9); myServo.write(var); Serial.begin(9600); } void loop() { if(Serial.available()>1){ var = Serial.read(); myServo.write(var); delay(100); dummy = Serial.read(); } }
dummyデータを読み込むことで命令完了をPC側に知らせている。