Raspberry Pi と Arduino が Python を使ってシリアルポートで通信する
Raspberry Pi と Arduino の間で少量のデータをやり取りする必要がある場合、通常はシリアルポートがもっともシンプルな橋渡しになります。Arduino は USB シリアル経由でバイトを送受信し、Raspberry Pi 側の Python は pyserial を使ってそれらのバイトを読み書きできます。
覚えておくべき重要な点は、シリアル通信はバイトベースだということです。Python の文字列はそのまま送信されるわけではありません。シリアルポートへ書き込む前にバイトへエンコードする必要があり、受信したバイトはテキストとして扱う前にデコードする必要があります。
message = "string"
data = message.encode("utf-8")
text = data.decode("utf-8")
1 バイトの整数値であれば、Python は整数と文字の間の変換もできます。
value = 65
char = chr(value) # 'A'
number = ord(char) # 65
Arduino 側
シリアルから 1 行を読み取り、応答を返す簡単なスケッチをアップロードします。Python 側で使うものと同じボーレートでシリアルポートを開きます。
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) {
String input = Serial.readStringUntil('n');
input.trim();
Serial.print("Arduino received: ");
Serial.println(input);
}
}
このスケッチは、改行で終端されたメッセージを待ちます。受信すると、受け取ったテキストをシリアルポートへ出力し返します。
Raspberry Pi 側
pyserial がまだ利用できない場合はインストールします。
python3 -m pip install pyserial
Arduino を Raspberry Pi に接続したあと、Arduino のシリアルデバイスを探します。
ls /dev/ttyACM* /dev/ttyUSB* 2>/dev/null
一般的なデバイス名は、Arduino Uno なら /dev/ttyACM0、USB シリアルアダプターを使うボードなら /dev/ttyUSB0 です。
次に Python を使ってメッセージを送信し、応答を読み取ります。
import time
import serial
PORT = "/dev/ttyACM0"
BAUD = 9600
with serial.Serial(PORT, BAUD, timeout=2) as ser:
time.sleep(2) # Give the Arduino time to reset after opening serial.
ser.write(b"hello from raspberry pin")
ser.flush()
line = ser.readline()
print(line.decode("utf-8", errors="replace").strip())
ポートが正しく、両側で同じボーレートを使っていれば、Raspberry Pi には次のような内容が表示されるはずです。
Arduino received: hello from raspberry pi
バイト、文字列、Unicode
Python 3 では、シリアルデータを明示的に扱うべきです。
text = "hello"
bytes_to_send = text.encode("utf-8")
received_bytes = b"hellon"
received_text = received_bytes.decode("utf-8").strip()
便利な変換は次のとおりです。
bytes_value = b"string"
text_value = bytes_value.decode("utf-8")
single_char = chr(65)
single_number = ord("A")
変数名に str や bytes を使うのは避けてください。これらの名前は Python の組み込み型を隠してしまうためです。
トラブルシューティング
何も受信できない場合は、まず次の点を確認してください。
- Arduino のスケッチと Python スクリプトが同じボーレートを使っている。
- Python スクリプトが正しいシリアルデバイスを開いている。
- Arduino コードで
readStringUntil('n')を使っている場合、メッセージがnで終わっている。 - Python スクリプトを実行しているユーザーに、シリアルデバイスへアクセスする権限がある。
Raspberry Pi OS では、シリアル権限は通常 dialout グループで管理されます。
sudo usermod -aG dialout "$USER"
グループメンバーシップを変更したあとは、ログアウトしてから再度ログインしてください。
短いコマンドやセンサーメッセージであれば、このパターンで十分です。一方から改行終端の UTF-8 テキストを送信し、もう一方でそれをデコードし、Python ではバイトと文字列の境界を明確に保ちます。
