Python3とArduino間のシリアル通信での正しい型変換
- 評価 0
- クリップ 0
- VIEW 5,151
退会済みユーザー
PythonとArduino間でシリアル通信を行い,PythonでArduinoの制御を行おうとしています。
今はPythonからLチカを行うプログラムを作成しています。
調べながら進めているのですが、つまずいた箇所があるので質問させていただきます。
まず、実行できたコードを以下に示します。
受け側Arduino
#define LED_PIN 13
void setup() {
pinMode(LED_PIN, OUTPUT); //13番ピンを出力に設定
Serial.begin(9600);//シリアル通信のレートを9600に設定
digitalWrite(13, LOW);
}
void loop() {
if (Serial.available() > 0) {
int cmd = Serial.read();
switch (cmd) {
case '0' : digitalWrite(13, HIGH); break;
case '1' : digitalWrite(13, LOW); break;
}
}
}
送信側Python
#coding:utf-8
import serial
from time import sleep
def main():
with serial.Serial("/dev/tty.usbmodem1421",9600,timeout=1) as ser:
sleep(5)
flag=bytes('0','utf-8')
print(type(flag))
ser.write(flag)
if __name__ == "__main__":
main()
次に、失敗したコードを書きます。
Arduino側は同じ。
送信側Python
#coding:utf-8
import serial
from time import sleep
def main():
with serial.Serial("/dev/tty.usbmodem1421",9600,timeout=1) as ser:
sleep(5)
flag = bytes(0)
print(type(flag))
ser.write(flag)
if __name__ == "__main__":
main()
成功時、失敗時ともにflagをbytes型に変換したつもりです。
type(flag)の結果はどちらもbytes型でした。
成功時はstr→bytes型へ、失敗時はint→bytes型への型変換なのですが、なぜ後者ではLチカできなかったのでしょうか。
--追記 2017/10/24 --
回答を参考にint.to_bytesを用いてPython側のプログラムを書き直しました。
#coding:utf-8
import serial
from time import sleep
def main():
with serial.Serial("/dev/tty.usbmodem1421",9600,timeout=1) as ser:
sleep(5)
flag = 1
flag_byte = flag.to_bytes(1,'big')
print(flag_byte)
ser.write(flag_byte)
if __name__ == "__main__":
main()
またこれに応じてArduinoのcase文を書き直しました。
#define LED_PIN 13
void setup() {
pinMode(LED_PIN, OUTPUT); //13番ピンを出力に設定
Serial.begin(9600);//シリアル通信のレートを9600に設定
digitalWrite(13, LOW);
}
void loop() {
if (Serial.available() > 0) {
int cmd = Serial.read();
switch (cmd) {
case 0 : digitalWrite(13, HIGH); break;
case 1 : digitalWrite(13, LOW); break;
}
}
}
このソースで正しく動作しました。感謝します。
-
クリップを取り消します
-
質問の評価を上げたことを取り消します
-
質問の評価を下げたことを取り消します
checkベストアンサー
+1
Pythonのドキュメントのbytesの項目を見てみると、
bytes は bytearray のイミュータブル版です。
とありますので、bytearrayの項目を見てみます。
class bytearray([source[, encoding[, errors]]])
オプションの source 引数は、配列を異なる方法で初期化するのに使われます:文字列 の場合、 encoding (と、オプションの errors) 引数も与えなければなりません。このとき bytearray() は文字列を str.encode() でバイトに変換して返します。
整数 の場合、配列はそのサイズになり、null バイトで初期化されます。
sourceに文字列を指定した場合は、「文字列を str.encode() でバイトに変換して返します」
一方で、整数を指定した場合は、「配列はそのサイズになり、null バイトで初期化されます。」
そのため、bytes(0)
で返ってくるのは要素数0のbytes型の配列ということになります。
後者のソースでLチカができなかったのは、上記の理由が原因です。
int型→bytes型への変換はint.to_bytes(length, byteorder, *, signed=False)
を使います。
(参考)
bytearrayの説明
投稿
score 197
+1
bytes(0)
は、長さ0のbytesオブジェクトを作成するという意味になるので、flag
変数の型はbytes
でも内容はb''
(中身がないbytesオブジェクト)になります。なお、その後write
では0バイトのデータを書き込んでいることになるため、Arduinoでは何も起きません。
投稿
score 964
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.24%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
退会済みユーザー
2017/10/18 01:03
よろしければまたアドバイス、宜しくお願いします。
sa-yu
2017/10/19 00:40
Arduinoのコードの`int cmd = Serial.read();`の直後に`Serial.println(cmd);`とかを入れて、
Python側のコードで`ser.write(flag)`の直後に`ser.readline()`とかを入れて、
Arudino側で何を受け取ったのか確認すれば、何かわかるかもしれません。
退会済みユーザー
2017/10/24 16:24
修正したところ、正しく動作してくました。
感謝します。