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

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

新規登録して質問してみよう
ただいま回答率
85.49%
シリアルポート

シリアルポートは一度に一ビットごと移行される物理的なインターフェイスです。一般的には、9ピンのd-subコネクタであるRS-232を指します。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

Python

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

Arduino

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

Q&A

解決済

4回答

5249閲覧

Python>Arduino>Pythonの相互シリアル通信

退会済みユーザー

退会済みユーザー

総合スコア0

シリアルポート

シリアルポートは一度に一ビットごと移行される物理的なインターフェイスです。一般的には、9ピンのd-subコネクタであるRS-232を指します。

文字コード

文字コードとは、文字や記号をコンピュータ上で使用するために用いられるバイト表現を指します。

Python

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

Arduino

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

0グッド

0クリップ

投稿2019/08/27 16:29

編集2019/08/28 15:15

やりたいこと

Python>Arduino>Pythonの相互に文字列のやり取りがしたいです。
試しにPythonで作ったランダムな数字をArduinoで2分の1して、結果をPythonに返すプログラムを書いていますがうまくいきません。

送信する文字列は、
Python:"Pyランダム数字" > Arduino:"Ardランダム数字/2" > Python
です。

※このあと複雑なやり取りに応用したいので、どうしても"Py ** "、 "Ard ** "の文字列で送受信したいです。

訳あってtkinterに結果を出力しています。
宜しくお願いします。

追記

追記:かなり編集したので最初にupしてたプログラムを削除しました。

簡易的なものを作ってみましたがうまくいきませんでした。
Python>Arduino>Pythonで文字列をシリアル通信でオウム返しするプログラムです。

受信側では1文字ずつ受け取るように変更し、
終端文字を改行コードにしたり、 . にしたりいろいろ試しました。

実行はできますが、ずっとループしているようで先に進めません。
Arduino側で  if (i > 10 || input[i] == '.') {   に引っかからない、
またはPython側で   if (line[-1] == '.') : break   に引っかからないのがネックなようです。

これでもダメなら何か他の方法を使ってみようと思います。

Python3

1import serial 2import time 3 4i = 1 5 6ser = serial.Serial('COMポート',9600,timeout=None) 7 8while True: 9 #送信 10 data = str(i) + '.' 11 flag=bytes(data,'utf-8') 12 ser.write(flag) #シリアル通信:送信 13 14 time.sleep(0.3) #必要か? 15 line = 'null' #whileとifで判定するための初期化 16 17 #受信 18 while line is 'null' : 19 if (line[-1] == '.') : break 20 line += ser.read() 21 print(line) 22 line = line.decode('utf-8') 23 line = line.replace('null', '') 24 line = line.replace('\r\n', '') 25 print(line) 26 i += 1 27ser.close()

Arduino

1#include <stdio.h> 2 3char input[10]; // 文字列格納用 4int i = 0; // 文字数のカウンタ 5 6void setup() { 7 Serial.begin(9600); 8} 9 10void loop() { 11 // データ受信したとき 12 if (Serial.available()) { 13 input[i] = Serial.read(); 14 // 文字数が10以上 or 末尾文字'.' 15 if (i > 10 || input[i] == '.') { 16 // 末尾に終端文字の挿入 17 input[i] = '\0'; 18 Serial.write(input); // 受信文字列を送信 19 // カウンタの初期化 20 i = 0; 21 } else { i++; } 22 }

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

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

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

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

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

t_obara

2019/08/28 01:36

そもそもPythonとArduinoは同一に語るべきレイヤのものではないので意味不明です。 AuduinoとはPCやラズパイ、IoTデバイスなどですよね。PythonとはC/C++などとなります。 さて、今回のような課題に対して、一番やらなくてはいけないことは、どこに問題があることを切り分けることです。そのために、問題があると想定される部分を最小限にして確認していくことが重要となります。 今回、送受信をそれぞれで確認していますが、まずは一般的なソフトを利用して送信されたデータが受信側で正常に受信されているかを確認するといったことが考えられます。
guest

回答4

0

本当は自己解決のプログラムについてのコメントなんですが、コードを含むので回答として書きます。

Arduino側

C++

1char input[30]; // 受信文字列格納 2<> 3void loop() { 4 if (Serial.available()) { 5 input[i] = Serial.read(); 6 // 文字数が10以上 or 末尾文字'.' 7 if (i > 30 || input[i] == '.') { 8 // 末尾に終端文字の挿入 9 input[i+1] = '\0'; 10 String tmp = input; //replaceするために1度str型に 11 tmp.replace("Py" , "Ard"); 12 tmp.toCharArray( sendata , tmp.length() ) ; 13 Serial.write(sendata); //送信 14 Serial.write(".\n"); //何故か受信した.が消える謎 15 // カウンタの初期化 16 i = 0; 17 } else { i++; } 18 // 受信文字列を送信 19 }

このプログラムでは、i++でi==30またi==31になった後、次回のloop()の実行でi[30]およびi[31]に対して代入が行われます。また、i==31でif文の条件に入った時、input[i+1]つまりinput[32]に書き込みします。いわゆるバッファオーバーフローで、致命的なエラーと言えます。もちろん、'.'の受信がエラーになったときにしかそのモードにはならないので、なかなか発現しないとは思いますが、コードに書いてある以上はプログラマの責任としてちゃんと動くようにしましょう。配列のサイズと、制限する受信文字数の整合をとるべきです。

それと、何故か受信した.が消える謎なんていうのを放置すると、あとでしっぺ返しを喰らうことがあります。
まず、その時点で'.'がいないことについて
「受信した.が消えた」
「.が送信されていなかった」
「送信された.が受信されなかった」
「PC側に送り返した'.'が受信されていなかった」
等のモードが考えられますが、「受信した.が消えた」であることは確認されているのでしょうか?
少なくとも質問のプログラムでは

C++

1 if (i > 10 || input[i] == '.') { 2 // 末尾に終端文字の挿入 3 input[i] = '\0';

としていますから、'.'が入っていたinput[i]を'\0'で「消して」います。自己解決のプログラムでは対策されているのですが、この辺で打った手は整理されていますか?

t_obaraさんがコメントされているように、シリアルモニタやteratermなどを使用して、少なくともArduino側の通信動作は確認出来るはずです。これは是非やるべき。

投稿2019/08/31 03:55

thkana

総合スコア7629

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

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

退会済みユーザー

退会済みユーザー

2019/08/31 11:15

ご指摘ありがとうございます!自分でも甘かったように思ってます。 やっぱり実行できるだけではだめですよね。 さらに改良しようと思います。
guest

0

ベストアンサー

皆さんの意見を参考にしながら細かいところまでいじくってたらできました。
Python側でシリアルポートを開いた後、**time.sleep(3)**するのもミソだったようです。

しかし空の文字列が帰ってきているのか、受信漏れがあり、さらに改善していこうと思います。
ありがとうございました!

以下プログラムと実行結果

追記
<改良版(受信漏れなし)>
(Python) "Py(数字)" > (Arduino) "Ard(数字)" > (Python) 表示

Python

1import serial 2import time 3 4i = 1 #送信する文字 5ser = serial.Serial('COMポート',9600,timeout=None) 6time.sleep(3) 7while True: 8 #送信 9 data = 'Py' + str(i) + '.' #終端文字 10 flag=bytes(data,'utf-8') 11 ser.write(flag) 12 print(data , flag) #確認用 13 14 time.sleep(1) #必要か? 15 line = 'null' 16 17 #受信 18 while not ('.\n' in line): 19 temp = ser.readline() 20 temp = temp.decode('utf-8') 21 line = line + temp 22 line = line.replace('null', '') 23 line = line.rstrip('\n') #余分な改行は取り除く 24 print(line) #確認用 25 26 i += 1 27 28ser.close()

Arduino

1#include <stdio.h> 2 3char input[30]; // 受信文字列格納 4char sendata[30]; // 送信文字列格納 5int i = 0; // 文字数のカウンタ 6 7void setup() { 8 Serial.begin(9600); 9} 10 11void loop() { 12 if (Serial.available()) { 13 input[i] = Serial.read(); 14 // 文字数が10以上 or 末尾文字'.' 15 if (i > 30 || input[i] == '.') { 16 // 末尾に終端文字の挿入 17 input[i+1] = '\0'; 18 String tmp = input; //replaceするために1度str型に 19 tmp.replace("Py" , "Ard"); 20 tmp.toCharArray( sendata , tmp.length() ) ; 21 Serial.write(sendata); //送信 22 Serial.write(".\n"); //何故か受信した.が消える謎 23 // カウンタの初期化 24 i = 0; 25 } else { i++; } 26 // 受信文字列を送信 27 } 28}

jikkoukekka

1Py1. b'Py1.' 2Ard1. 3Py2. b'Py2.' 4Ard2. 5Py3. b'Py3.' 6Ard3. 7Py4. b'Py4.' 8Ard4. 9Py5. b'Py5.' 10Ard5.

投稿2019/08/29 13:09

編集2019/08/29 15:33
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

送信データに終端記号をつけましょう
テキストデータなら、改行(\n)ですね。

メッセージの終端がわからないため、やみくもに30文字受信しても、送信途中から受信してしまうとワケワカランデータとなってしまって破綻します。
受信側では、改行が来るまでデータを貯めていき、改行が来たら次の処理に回すようにします

投稿2019/08/28 02:19

y_waiwai

総合スコア87747

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

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

0

Arduino側で
serialReadが3重ループになってますけど、抜けてなくないですか?

またpython側でも
self.ser.write(flag) #生成した数字を送信

この部分って30文字以上か終端文字送ってますか?
戻り値で何バイト送ったかわかるようなのでチェックしてみてください。

投稿2019/08/28 02:08

nullbot

総合スコア910

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問