Mac / PC とArduino Unoを通信させる方法です.たくさんの情報がネット上にはありますが,ここでも紹介しておきます.
Arduino側からPCへ
Serialを使ってArduinoは文字列を出力し,Python側はそれを読み取ります.
Arduino側
void setup() {
Serial.begin(9600);
}
int data = 0;
void loop() {
data++;
Serial.println(data);
delay(1000);
}
コンパイルしてシリアルモニタで表示させると以下のように数字が増えながら表示されます.
1
2
3
4
5
6
PC / Mac
まずpython3の環境にpyserialをインストールします.
$ pip3 install pyserial
Windowsだったら単純に pip install pyyaml
コードは以下の通りです.
import serial
ser = serial.Serial('/dev/cu.usbmodem1101', 9600,timeout=None)
while True:
line = ser.readline() # ここで一行データを取得するがbyte型
stripped_str = str(line, 'ascii').strip() # byte型を文字列に変換して前後の空白改行除去
data = int(stripped_str) # 文字列を数値に解釈し直す
print(data)
/dev/cu.usbmodem1101の部分は自分のarduinoがつながっているポート名にする.WinならCOM1とか.Arduinoのシリアルモニタがつながっているとできません.
これのポイントは,データとしては「文字列」として送られているものを,python側で解釈してデータに変換していることです.文字列のままでは加減乗除のような計算が不能なので数値に解釈することが必要です.
たくさんのデータを送りたい
ADコンバータ等をたくさん使ってデータを送る場合は以下の通り
Arduino側
コンマで区切って一行に送りたいデータをすべて送ります.
void setup() {
Serial.begin(9600);
}
void loop() {
int data1 = analogRead(A1);
int data2 = analogRead(A2);
int data3 = analogRead(A3);
int data4 = analogRead(A4);
Serial.print(data1);
Serial.print(',');
Serial.print(data2);
Serial.print(',');
Serial.print(data3);
Serial.print(',');
Serial.println(data4);
delay(1000);
}
シリアルモニタで確認すると以下のような表示です.
311,301,292,305
364,336,316,315
287,283,278,286
274,274,272,275
Python側
import serial
ser = serial.Serial('/dev/cu.usbmodem1101', 9600,timeout=None)
while True:
line = ser.readline()
stripped_str = str(line, 'ascii').strip()
datas = [int(d) for d in stripped_str.split(',')]
print(datas)
ポイントとしては [int(d) for d in stripped_str.split(',')]
の部分ですね.これはリスト内包表記を使ってstripped_str.split(‘,’)で返ってきたリスト型データに繰り返し処理をしてリストに変換しています.要するにここでは「 ‘,’で区切られている文字列を’,’で分割したのち,それら一つ一つに対してint()関数を使って数値に解釈し,それらの結果をリストとしてdatasに代入します」という処理でした.出力は以下のようになります.
[365, 337, 317, 291]
[270, 272, 271, 267]
[260, 264, 265, 260]
[258, 263, 265, 258]
[257, 262, 264, 257]
[257, 262, 264, 257]
[365, 337, 317, 291]
PCからArduinoへ
ここはあまり難しい処理をしないでONとOFFの文字列をそれぞれ送ります.
Python側
import time
import serial
ser = serial.Serial('/dev/cu.usbmodem1101', 9600,timeout=None)
while True:
ser.write('ON\n'.encode())
time.sleep(1.0)
ser.write('OFF\n'.encode())
time.sleep(1.0)
Arduino側
こちらは文字列がONだったら,OFFだったら・・・という処理を記述します.
void setup() {
// put your setup code here, to run once:
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
Serial.begin(9600);
Serial.setTimeout(3000); /// 3 sec
}
void loop() {
// put your main code here, to run repeatedly:
String message = Serial.readStringUntil('\n');
message.trim();
if (message == "ON") {
digitalWrite(13, HIGH);
} else if (message == "OFF") {
digitalWrite(13, LOW);
}
}
ONの文字列だったらArduino基板上のLED (Pin 13) がひかり,OFFなら消える,という処理です.文字列を増やせばいろんな処理を送れます.
送受信が絡まり合う処理はお勧めしません
おすすめは,PCが送ったらArduinoが返す,という処理を繰り返すことです.こういう処理を「同期処理」と言います.基本的には同期処理でなんとかできるように考えてみてください.
これ以上の処理,たとえばPCが送らなくてもArduinoがデータを送るけど,時々受け取るデータに対してArduinoは処理を行なってほしい,などの要求がある場合は,たとえばSerial.available()関数などを使います.これ以上は詰め込みすぎだと思うのでこの辺で.