質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

0回答

522閲覧

PythonでPCとArduino間でシリアル通信させてモータを振動させたい

milemile

総合スコア0

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2023/01/15 15:23

前提

PC側でキャプチャボードで取得したNintendo Switchの映像を使って、OpenCVのテンプレートマッチングを使用しマッチした場合にシリアル通信をして、Arduinoでモータを振動させたいです。シリアル通信の実装は初めてなので初歩的なことかもしれませんがよろしくお願いします。

実現したいこと

キャプチャボードで取得した映像の中にテンプレート画像に近いものがあると判断した時だけ、モータが回転するようにしたいです。

発生している問題・エラーメッセージ

エラーは出ずテンプレート画像に近いものを認識すると長方形は描くのですが、テンプレート画像に近いものの有無にかかわらずモータが回転してしまいます。

該当のソースコード

PC側

1import cv2 2import numpy as np 3import serial 4import time 5 6#カメラから映像を取得 7capture = cv2.VideoCapture(2) 8 9#カメラから映像を取得できない場合、終了 10if not capture.isOpened(): 11 print('カメラから映像を取得できませんでした') 12 exit() 13 14#テンプレート画像をグレースケールで読み込む 15template = cv2.imread('template_menu.png', 0) 16#テンプレート画像の幅と高さを取得 17w, h = template.shape[::-1] 18 19while True: 20 ret, frame = capture.read() 21 #frameをグレースケールに変換 22 frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 23 if ret: 24 #テンプレートマッチングを実行 25 result = cv2.matchTemplate(frame_gray, template, cv2.TM_CCOEFF_NORMED) 26 #テンプレートマッチングの結果が0.7以上の位置をすべて取得 27 threshold = 0.7 28 locate = np.where(result >= threshold) 29 30 #テンプレート画像がマッチした位置に長方形を描画 31 for point in zip(*locate[::-1]): 32 cv2.rectangle(frame_gray, point, (point[0] + w, point[1] + h), (255, 0, 0), 3) 33 34 cv2.imshow('frame', frame_gray) 35 36 #0.7以上の場所があればArduinoに振動させる命令を送る 37 if locate != []: 38 ser = serial.Serial('COM21', 9600, timeout=0.1) 39 time.sleep(1) 40 ser.write(b'1') 41 ser.close() 42 43 #qを押した際にbreak 44 k = cv2.waitKey(1) & 0xFF 45 if k == ord('q'): 46 break 47 48 else: 49 break 50 51capture.release() 52cv2.destroyAllWindows()

Arduino側

1void setup() { 2 Serial.begin(9600); 3 pinMode(11, OUTPUT); 4 digitalWrite(11, LOW); 5} 6 7void loop() { 8 char data; 9 data = Serial.read(); 10 if(data == '1'){ 11 digitalWrite(11, HIGH); 12 delay(500); 13 digitalWrite(11, LOW); 14 delay(500); 15 } 16}

試したこと

おそらくPC側の37~41行目がおかしいのだろうと思ってソースコードを少しいじってみましたがうまくいきませんでした。

補足情報(FW/ツールのバージョンなど)

OpenCV 4.6.0
Python 3.9.15

シリアル通信の部分は以下のサイトを参考にしました。
https://tomson784.github.io/memo/python/arduino/2021/05/25/pyserial-arduino.html

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dameo

2023/01/15 16:27 編集

無関係なコードを入れるのは止めましょう。 シリアル通信ができないならシリアル通信だけのコードを作成して、確認しましょう。 まずはArduino側だけで動作確認しましょう。PC側はArduino IDEのシリアルモニタとかputty/teraterm(windowsなら)などのシリアル対応した端末ソフトを使えば通信できます。 Arduino単体で確認できたらPC側の開発を進めて、そこで問題が起きたらようやく今回のような質問が出来る状況になります。
退会済みユーザー

退会済みユーザー

2023/01/15 21:50 編集

> おそらくPC側の37~41行目がおかしい 「少なくともOpenCVによる判定」はうまくいっているようですので、私もパッとコードを見た感じだと同じように感じます。ですので、一番怪しいのは「if locate != []:」の部分です。if locate == []: print("Not found")みたいな文をifの前に付ければ確認できますね。 「何も認識していないはずの状態」の時のlocateの中身が何かを確認できますか?このとき、誤ってlocateの中に何かが入っているのか、Noneであればif is not None:に差し替えがいるのかという話になってきます。もし、ifの部分があっていれば、シリアル通信がおかしいのか、Arduino側のコードが怪しいのか、ということになってきます。
thkana

2023/01/16 00:08 編集

多分直接は関係しませんが、 シリアルポートはアプリケーションに入った段階でオープンし、終わるときにクローズするようにするのが普通でしょう。 特にArduino UNO等が相手の場合、COMボートをクローズ->オープンしたときにArduinoにリセットがかかるような仕組みになっていて、データ送信の度にオープン/クローズすると動作に支障を来す場合がありそうです。 で、Pythonよく知りませんが、numpy.where()って、条件を満たさないと空リストを返すんだっけ? てもとでは、 a=numpy.array([1,2,3]) b=numpy.where(a>=10) とすると b==[]はfalseだけれど b[0].sizeが0になるから、そういう判別をするんじゃないかと。
thkana

2023/01/16 00:21

参照先ページ( https://tomson784.github.io/memo/python/arduino/2021/05/25/pyserial-arduino.html )の最後の「注意点」はまさに上記のリセットに引っかかっていて、serial.readline()のタイムアウトまでの時間をとることで、Arduinoがブートを終えて受信できるようになっているということでは。確認/実験してはいないけれど。 (質問のプログラムでも1秒寝かしているのはこの件?) まぁ、そこそこの時間を待つだけでも実用上は十分でしょうけれど、Arduinoの起動時間のスペックとか(多分)ないので、真面目にやるならシリアルオープンしてArduinoが起動したらArduinoから一文字「起きたよ」信号を送信させて、Python側はそれを受けてから以降の動作に進む...とかいうシーケンスが適切な気がします。 (毎回オープン/クローズするのでないなら最初だけの話だし)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問