ArduinoとPythonで複数センサーを同時リアルタイム可視化する方法|CSV送信+matplotlibサブプロット完全ガイド
「温度センサーだけじゃなくて、照度センサーも一緒にグラフで見たい…」
そう思ったことはありませんか?センサーが1つのときはシンプルに動かせても、複数センサーを同時にリアルタイム表示しようとすると途端に難しくなるんですよね。
今回は、ArduinoにLM35(温度)とCdS照度センサーの2つをA0・A1で同時接続し、CSV形式でシリアル送信→Pythonがパースしてmatplotlibのサブプロットにリアルタイム同時描画するシステムを一緒に作っていきます。単一センサーの基礎がまだの方は先に Python × Arduino シリアル通信入門!センサーデータをリアルタイム可視化する方法 をご覧ください。
この記事固有のポイントは「複数系列を1フレームで同期描画する設計」です。ぜひ最後まで読んでみてください! 🚀
この記事で作るもの・対象読者


作るもの:ArduinoのA0にLM35(温度)、A1にCdSセル(照度)を接続し、temperature,light のようなCSV形式でシリアル送信。Python側でパースして、matplotlibのサブプロット2段にそれぞれリアルタイム同時描画するシステムです。
対象読者:
- ✅ Arduinoで単一センサーは動かせたことがある
- ✅ Pythonの基礎(リスト・関数)を少し知っている
- ✅ 複数センサーを同時に可視化したい初〜中級者
必要なもの:
- Arduino Uno(互換機でもOK)
- LM35温度センサー(A0接続)
- CdSセル(照度センサー)+10kΩ抵抗(A1接続)
- USBケーブル、ジャンパワイヤ、ブレッドボード
- Python 3.x・pyserial・matplotlib がインストール済みのPC
全体の仕組みをざっくり理解しよう
単一センサーとの最大の違いは「シリアルで送るデータの形式」です。
複数センサー版のデータフロー:
センサー×2 → Arduino(A0/A1同時読み取り) → CSV形式でシリアル送信 → Python(カンマでパース) → matplotlibサブプロット同時更新
たとえばArduinoが送る1行はこんな形です:
24.8,512
左が温度(℃)、右が照度(アナログ生値0〜1023)です。Python側はこの行をカンマで分割するだけで2つの値を取り出せます。シンプルな設計ですが、センサーを3つ・4つに増やしたいときも同じパターンで拡張できます 😊
なおシリアル通信の基本(COMポート確認・pyserialの導入)は PythonとArduinoをシリアル通信で連携させる方法【pyserial入門・サンプルコード付き】 にまとめているので、ここでは複数センサー固有の設計に集中します。
回路の組み方
LM35(温度センサー)― A0へ
- VCC(左ピン) → Arduino 5V
- OUT(中央ピン) → Arduino A0
- GND(右ピン) → Arduino GND
CdSセル(照度センサー)― A1へ
CdSセルは抵抗値が変化する素子なので、10kΩ抵抗と組み合わせた電圧分圧回路でアナログ電圧に変換します。
- 5V → CdSセル → A1(分圧点) → 10kΩ抵抗 → GND
つまり「5V─CdS─●─10kΩ─GND」の直列回路で、●の点をA1につなぎます。明るいほどCdSの抵抗が下がり、A1の電圧(=読み取り値)が上がります。
STEP 1:Arduino側のスケッチ(CSV形式で2センサー同時送信)

ポイントをまとめるとこんな感じです:
- A0(LM35)とA1(CdS)を同じループで連続読み取りすることで、ほぼ同時刻のサンプルになる
Serial.print()でカンマをはさみ、最後だけSerial.println()で改行を付ける- 1行 = 1タイムスタンプ分のデータとして扱えるのがCSV形式の利点
- 300msごとに送信することでPython側の描画処理が追いつきやすくなる
// 複数センサー(LM35 + CdS)をCSV形式でシリアル送信するスケッチ
const int TEMP_PIN = A0; // LM35
const int LIGHT_PIN = A1; // CdSセル
void setup() {
Serial.begin(9600);
}
void loop() {
// --- LM35:温度計算 ---
int rawTemp = analogRead(TEMP_PIN);
float voltage = rawTemp * (5000.0 / 1023.0); // mV
float tempC = voltage / 10.0; // ℃
// --- CdS:照度(アナログ生値をそのまま送る)---
int lightRaw = analogRead(LIGHT_PIN); // 0〜1023
// --- CSV形式で1行送信: "温度,照度\n" ---
Serial.print(tempC);
Serial.print(','); // カンマ区切り
Serial.println(lightRaw); // 改行付き
delay(300); // 300ms待機
}
書き込み後にシリアルモニターを開いて、24.80,612 のような行が流れてくれば成功です ✅
STEP 2:Pythonのライブラリを確認する
必要なライブラリは3つです。未インストールなら以下を実行してください。
pip install pyserial matplotlib japanize-matplotlib
- pyserial:Arduinoからのシリアルデータを受信する
- matplotlib:サブプロットで複数系列を同時描画する
- japanize-matplotlib:グラフの日本語ラベルが豆腐(□)表示になるのを防ぐ
pyserialの詳細な使い方は PythonとArduinoをシリアル通信で連携させる方法【pyserial入門・サンプルコード付き】 を参考にしてください。
STEP 3:Python側のメインコード(サブプロット+CSV パース)
ここが今回の核心部分です。コードの設計上の工夫を先に整理しておきます:
- CSV パース:
raw.split(',')でカンマ区切りを分解。値が2つ揃っていることを確認してから追加することで、欠損行によるクラッシュを防ぐ - サブプロット:
plt.subplots(2, 1)で縦に2段のグラフ領域を作成し、上段に温度・下段に照度を描画 - 共有X軸:
sharex=Trueを指定すると、両グラフのX軸が連動してスクロールするため見やすくなる - deque: 両系列ともに最新100件のみ保持し、古いデータを自動削除
import serial
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import japanize_matplotlib # 日本語ラベルの文字化け(豆腐)対策
from collections import deque
import time
# ---- 設定 ----
PORT = 'COM3' # Windowsの例。Mac: '/dev/tty.usbmodemXXXX'
BAUD_RATE = 9600
MAX_POINTS = 100 # 表示するデータ点数
# シリアルポート接続
ser = serial.Serial(PORT, BAUD_RATE, timeout=1)
time.sleep(2) # Arduino起動待ち
# データ格納用 deque(2系列)
temperatures = deque(maxlen=MAX_POINTS)
lights = deque(maxlen=MAX_POINTS)
# ---- グラフ初期設定 ----
# sharex=True で両サブプロットのX軸を連動させる
fig, (ax_temp, ax_light) = plt.subplots(
2, 1, figsize=(10, 7), sharex=True
)
# 上段:温度グラフ
line_temp, = ax_temp.plot([], [], 'r-', linewidth=2, label='温度 (℃)')
ax_temp.set_ylim(0, 50)
ax_temp.set_ylabel('温度 (℃)', fontsize=11)
ax_temp.set_title('リアルタイム複数センサーモニター', fontsize=13)
ax_temp.legend(loc='upper left')
ax_temp.grid(True, alpha=0.3)
# 下段:照度グラフ
line_light, = ax_light.plot([], [], 'b-', linewidth=2, label='照度 (raw)')
ax_light.set_ylim(0, 1023)
ax_light.set_ylabel('照度 (0〜1023)', fontsize=11)
ax_light.set_xlabel('サンプル数', fontsize=11)
ax_light.legend(loc='upper left')
ax_light.grid(True, alpha=0.3)
def update(frame):
"""FuncAnimation から繰り返し呼ばれる更新関数"""
if ser.in_waiting > 0:
try:
raw = ser.readline().decode('utf-8').strip()
parts = raw.split(',') # CSV パース
# 値が2つ揃っているときだけ追加(欠損行を無視)
if len(parts) == 2:
temp = float(parts[0])
light = int(parts[1])
temperatures.append(temp)
lights.append(light)
print(f'温度: {temp:.1f}℃ 照度: {light}')
except (ValueError, UnicodeDecodeError):
pass # 変換失敗は無視
xs = range(len(temperatures))
# 両グラフのデータを同時更新
line_temp.set_data(xs, list(temperatures))
line_light.set_data(range(len(lights)), list(lights))
# X軸の表示範囲を現在のデータ数に合わせて動的更新
ax_temp.set_xlim(0, max(MAX_POINTS, len(temperatures)))
return line_temp, line_light
# 300msごとに update を呼び出す
ani = animation.FuncAnimation(
fig, update, interval=300, blit=True
)
plt.tight_layout()
plt.show()
ser.close() # ウィンドウを閉じたらポートを解放
COMポートの確認方法
- Windows:デバイスマネージャー →「ポート(COMとLPT)」を確認
- Mac:ターミナルで
ls /dev/tty.*を実行 - Linux:ターミナルで
ls /dev/ttyUSB* /dev/ttyACM*を実行
STEP 4:実行してみよう
Arduinoにスケッチを書き込んでUSB接続した状態で、Pythonスクリプトを実行します。
python multi_sensor_plot.py
うまく動くと、こんな挙動になります:
- ウィンドウが開き、上段に赤い温度グラフ・下段に青い照度グラフがリアルタイムで伸びていく
- コンソールに
温度: 24.8℃ 照度: 612が流れ続ける - センサーに手を近づけると温度が上昇、センサーに影を作ると照度が下降するのを両グラフで同時確認できる
ウィンドウを閉じると ser.close() が呼ばれてシリアルポートが解放されます ✅
よくあるトラブルと対処法
グラフが片方しか更新されない
Arduino側で Serial.print() と Serial.println() の区別が正しいか確認してください。両値ともに Serial.println() にするとカンマではなく改行が入ってしまい、Python側のパースが崩れます。
ValueError で止まってしまう
Arduinoリセット直後は不完全な行が流れることがあります。len(parts) == 2 のガードがあれば弾けますが、それでも止まる場合は time.sleep(2) を time.sleep(3) に延ばして起動待ちを長くしてみてください。
照度グラフの値が常に0や1023に張り付く
分圧回路の配線を確認してください。CdSとGNDの間に10kΩ抵抗が入っていないと、電圧がGNDまたは5Vに固定されます。
SerialException(Access is denied / Permission denied)
ポートを開けないときは serial.serialutil.SerialException(メッセージに Access is denied / Permission denied 等を含む)が発生します。Arduino IDEのシリアルモニターが開いたままだとポートが占有されます。シリアルモニターを閉じてから再実行してください。詳しい原因と対処は PythonとArduinoをシリアル通信で連携させる方法【pyserial入門・サンプルコード付き】 にまとめています。
発展:センサーを3つ以上に増やすには
今回の設計はセンサー追加がとても簡単です。たとえば湿度センサーをA2に追加するなら、以下の変更だけで対応できます。
Arduino側
// A2に追加センサー(例:湿度に見立てたポテンショメーター)
int humidRaw = analogRead(A2);
// CSV を3列に拡張
Serial.print(tempC);
Serial.print(',');
Serial.print(lightRaw);
Serial.print(',');
Serial.println(humidRaw);
Python側
# deque を1つ追加
humidities = deque(maxlen=MAX_POINTS)
# subplots を3段に変更
fig, (ax_temp, ax_light, ax_humid) = plt.subplots(3, 1, figsize=(10, 9), sharex=True)
# パース部分
if len(parts) == 3:
temp = float(parts[0])
light = int(parts[1])
humid = int(parts[2])
temperatures.append(temp)
lights.append(light)
humidities.append(humid)
このように「CSV列の追加」「dequeの追加」「subplotsの段数変更」の3点セットで、センサーをどんどん増やしていけます。
IoTシステムをさらに発展させて温湿度をクラウドに送りたい場合は、ArduinoとPythonで作るIoT温湿度モニタリングシステム【ゼロから動かす入門ガイド】 も参考にしてみてください。
まとめ
今回作ったシステムのポイントを整理します。
- 🔌 Arduino側:A0(LM35)とA1(CdS)を同一ループで読み取り、
値,値のCSV形式で送信
- 📡 通信形式:カンマ区切りにすることでPython側のパースが1行で済む
- 🐍 Python側:
split(',')でパース → 2つの deque に分けて格納 →FuncAnimationで300msごとに両グラフを同時更新 - 📊 描画:
plt.subplots(2, 1, sharex=True)でX軸を共有した2段サブプロット - 🔧 拡張性:CSV列・deque・subplotsの段数を増やすだけで3センサー以上にも対応
「数字の羅列」だったセンサーデータが、複数の系列グラフとして同時に動く様子は眺めていて楽しいですよ。ぜひ手持ちのセンサーでいろいろ試してみてください! 🎉
こちらも読まれています
📡 Arduinoをもっと深く学ぼう!
Arduino・ラズパイ・ロボットプログラミングを体系的に学びたい方へ。おすすめのUdemyコースや電子部品もまとめています。
📚 関連商品・おすすめ書籍
※本記事にはアフィリエイトリンクが含まれます。





