「まただ…また動かない…」
深夜2時。モニターに映し出されたエラーメッセージを前に、僕はPCのキーボードを打つ手を止めた。部屋の片隅に置かれたArduinoには、温度センサーが寂しそうにぶら下がっている。数時間前まで、「これでリビングの温度をリアルタイムでモニタリングできるぞ!」と意気揚々としていた熱意は、冷え切った部屋の空気のように、すっかり萎んでしまっていた。
あれは、僕がIoTの世界に足を踏み入れたばかりの頃の話だ。当時、僕はプログラミング経験はそこそこあったものの、ハードウェアとの連携はまるで素人だった。Arduinoでセンサーデータを読み取るのは簡単だった。でも、そのデータをPythonで受け取り、グラフ化したり、もっと複雑な処理をさせたいと思った瞬間、目の前に分厚い壁が立ちはだかったんだ。
ネット上には「ArduinoとPythonでシリアル通信!」といった記事がたくさんあった。僕はそれらを片っ端から読み漁り、コードをコピペしては実行した。しかし、結果はいつも同じ。Pythonスクリプトはエラーを吐き出し、Arduinoからのデータは一向に届かない。ポートが開けない、ボーレートが合わない、バイト列と文字列の変換で文字化け…。「なぜ、みんなはこんなに簡単にやっているように見えるのに、僕だけがこんなにもつまづくんだ?」
焦燥感が募る。時間だけが過ぎていく。家族が寝静まったリビングで、一人、モニターの光を浴びながら、僕は何度も心の中で叫んだ。「もうダメかもしれない…このままじゃ、僕のIoTの夢は、ただの夢で終わってしまうのか…?」
そんな絶望の淵にいた僕を救ってくれたのは、プログラミングスクールで講師をしている友人だった。彼に現状を話すと、彼は静かに言った。「お前は、ArduinoとPythonが『会話』するための準備をしていないだけだよ」。
「会話?」僕は聞き返した。
「そう。シリアル通信は、例えるなら海外旅行での言葉の壁だ。お互いが違う言語を話しているのに、いきなり複雑な話をしようとしても無理だろう?まずは、お互いが理解できる共通の言葉(データ形式)と、話す速度(ボーレート)を合わせることから始めるんだ。」
友人の言葉は、僕の頭の中でバラバラだった知識の断片を、一本の線で繋いでくれた。僕はハッとさせられた。そうだ、僕はただ闇雲にコードをコピペしていただけで、その裏にある「対話のルール」を全く理解していなかったのだ。
そこから僕は、シリアル通信の基礎を徹底的に学び直した。ArduinoのSerial.begin()で設定するボーレートの意味。Pythonのpyserialライブラリでポートを開く手順。そして最も重要だったのは、Arduinoから送られてくる「バイト列」のデータを、Pythonで「意味のある文字列」や「数値」に変換する方法だった。
1. Arduino側の準備:データの「話し方」を決める
まずはArduinoスケッチで、シンプルにセンサーデータをシリアルポートへ出力する。ポイントは、データを読みやすく、Python側でパースしやすい形式にすることだ。例えば、Serial.println("Temp:25.5");のように、識別子と値をセットで送る。そして、Serial.begin(9600);でボーレート(通信速度)を設定する。この「9600」が、Pythonとの共通言語の速度になる。
“`cpp
void setup() {
Serial.begin(9600); // Pythonとボーレートを合わせる
}
void loop() {
float temperature = 25.5; // 仮のセンサーデータ
Serial.print(“Temp:”);
Serial.println(temperature); // 「Temp:25.5」のように送信
delay(1000);
}
“`
2. Python側の準備:データの「聞き方」を学ぶ
次に、Pythonでpyserialライブラリをインストールする。これは、Arduinoが話す言葉を聞き取るための「翻訳機」のようなものだ。
“`bash
pip install pyserial
“`
そして、Pythonスクリプトでシリアルポートを開き、データを読み取る。最も重要なのは、Arduinoと同じボーレートを設定すること、そして、どのポートにArduinoが接続されているかを正確に指定することだ。WindowsならCOMx、macOSやLinuxなら/dev/tty.usbmodemXXXXのような形式になる。
“`python
import serial
import time
ser = serial.Serial(‘COM3’, 9600, timeout=1) # 環境に合わせてポート名とボーレートを設定
print(f”Connected to {ser.name}”)
try:
while True:
if ser.in_waiting > 0:
line = ser.readline().decode(‘utf-8’).strip() # バイト列を文字列に変換し、改行を除去
print(f”Received: {line}”)
ここでデータパースや処理を行う
if line.startswith(“Temp:”):
try:
temp_str = line.split(“:”)[1]
temperature = float(temp_str)
print(f”Temperature: {temperature}°C”)
except (ValueError, IndexError) as e:
print(f”Error parsing temperature: {e}”)
time.sleep(0.1)
except KeyboardInterrupt:
print(“Exiting…”)
finally:
ser.close() # 忘れずにポートを閉じる
print(“Serial port closed.”)
“`
このコードを実行した瞬間、モニターに次々と表示される「Received: Temp:25.5」。僕は思わず声を上げた。「動いた!本当に動いたんだ!」
あの時の感動は忘れられない。まるで、遠く離れた異国の友人と、初めて言葉が通じ合ったかのような感覚だった。センサーデータがただの数字の羅列ではなく、意味を持った「情報」として、僕のPythonスクリプトの中を駆け巡る。それは、僕のアイデアが形になる瞬間の、確かな手応えだった。
シリアル通信は、決して難しい技術じゃない。大切なのは、ArduinoとPythonがお互いに「何を、どう伝えたいか」を理解し、そのための「共通のルール」を設定することだ。一度この基礎を理解すれば、あなたのIoTプロジェクトは、まるで魔法にかかったかのように動き出すだろう。
もう、あの時の僕のように、エラーメッセージと孤独に戦う必要はない。センサーデータは、あなたの手の中で、無限の可能性を解き放つ準備ができている。さあ、あなたも「会話」の第一歩を踏み出してみないか?このシンプルな一歩が、あなたの未来を大きく変えるきっかけになるはずだ。
