Arduinoのセンサーデータをリアルタイムでグラフ表示する方法|Python連携

プログラミング・電子工作






Arduinoのセンサーデータをリアルタイムでグラフ表示する方法|Python連携







Python連携 / 初心者

Arduinoのセンサーデータをリアルタイムでグラフ表示する方法|Python連携

シリアルモニタに並ぶ数字の羅列は、値の変化を目で追うにはあまり向いていません。センサーの値を折れ線グラフとして、リアルタイムに動く形で見られたら、変化の傾向や異常値にずっと気づきやすくなります。本記事では、追加インストール不要のArduino純正機能から、Pythonの Matplotlib を使った本格的な可視化、複数センサーの同時表示、CSV記録との組み合わせまで、初心者の方に向けて順を追って解説します。

YOFUKASI LAB編集部
公開日:2026年9月26日
読了目安:15分

執筆・実機検証:YOFUKASI LAB運営者

理学療法士/Arduino・Pythonを使った医療機器制作・学会発表経験あり

Chapter 01 / Basics

01リアルタイムグラフ表示とは|何ができるようになるか

数字の羅列とグラフの決定的な違い

シリアルモニタは、値を確認する手段として手軽で優秀です。ただし、数字がひたすら流れていくだけなので、「値がじわじわ上がっている」「一瞬だけ大きく跳ねた」といった変化のパターンは、読み取りづらいという弱点があります。同じデータでも、折れ線グラフとして時系列に並べるだけで、傾向や異常値に気づく速度は大きく変わります。センサーのチューニングやキャリブレーション、動作確認の効率も、グラフ表示によって格段に上がります。

この記事で扱う2つのアプローチ

センサーデータをリアルタイムでグラフ表示する方法には、大きく分けて2つのアプローチがあります。1つは、Arduino IDEに標準で搭載されている「シリアルプロッタ」を使う方法です。追加のソフトは一切不要で、今すぐ試せます。もう1つは、Pythonの可視化ライブラリ「Matplotlib」を使う方法です。少し準備は必要ですが、複数センサーの自由なレイアウト表示や、画像保存、しきい値による色分けなど、表現の幅が大きく広がります。まずは手軽な方法から見ていきましょう。

編集部想定シナリオ

Arduinoでソイルセンサーの値を記録していたKさんは、シリアルモニタの数字を目で追うだけでは、値がゆっくり下がっているのか、実は上下に揺れているだけなのか、判断がつかなかった。試しにシリアルプロッタを開いてみると、値は緩やかな右肩下がりの直線を描いており、乾燥が着実に進んでいることが一目で分かった。数字の羅列では気づけなかった傾向が、グラフにした瞬間にはっきりと見えるようになった。



Chapter 02 / Serial Plotter

02最も手軽な方法|Arduino純正「シリアルプロッタ」

1行書くだけでグラフが出る

Arduino IDEには、標準で「シリアルプロッタ」という機能が搭載されています。ツールバーのアイコン、または「ツール」メニューから開くことができます。Arduino側のコードは、シリアルモニタで使うのとまったく同じSerial.println()だけで構いません。特別な準備は一切不要です。

// シリアルプロッタで1本の折れ線を表示するコード
void setup() {
  Serial.begin(9600);
}

void loop() {
  int value = analogRead(A0);
  Serial.println(value);  // これだけでグラフになる
  delay(50);
}

複数の値を同時に表示する

複数の値を1つのグラフに重ねて表示したい場合は、カンマまたは空白区切りで、1行にまとめて出力します。さらに「ラベル名:値」という書き方をすると、凡例に名前を表示させることもできます。

// 2つの値を、名前つきで同時にグラフ表示するコード
void setup() {
  Serial.begin(9600);
}

void loop() {
  int sensorA = analogRead(A0);
  int sensorB = analogRead(A1);

  Serial.print("SensorA:");
  Serial.print(sensorA);
  Serial.print(",");
  Serial.print("SensorB:");
  Serial.println(sensorB);

  delay(50);
}

シリアルプロッタの限界

シリアルプロッタは手軽な反面、いくつかの制約もあります。表示できる時間軸は直近の一定区間のみで、グラフを画像として保存する機能はありません。また、ボーレート(通信速度)は、コード内のSerial.begin()とプロッタ側の設定を必ず一致させる必要があります。ここが食い違うと、文字化けした値や、グラフが表示されない状態になります。もっと自由度の高い表示や記録をしたい場合は、次の章から解説するPython側のアプローチに進みましょう。

Chapter 03 / Why Python

03本格的に可視化するなら|Python × Matplotlibを使う理由

シリアルプロッタでは足りなくなる場面

シリアルプロッタは手軽ですが、「グラフを画像として残したい」「しきい値を超えたら色を変えたい」「複数のグラフを自由なレイアウトで並べたい」「表示しながら同時にファイルへ記録したい」といった要望には応えられません。こうした表現をしたくなったら、Pythonの可視化ライブラリ「Matplotlib(マットプロットリブ)」の出番です。

ArduinoとPythonの役割分担

この構成では、Arduinoは「センサーの値を読み取り、シリアル通信で送信する」役割に専念します。グラフの描画や記録といった重い処理は、パソコン側のPythonが担当します。マイコン側の処理を軽く保てるため、より高速なセンサー読み取りにも対応しやすくなるという利点もあります。



Chapter 04 / Setup

04環境構築|必要なライブラリのインストール

必要なライブラリは2つ

Python側で必要になるライブラリは、シリアル通信用の「pyserial」と、グラフ描画用の「matplotlib」の2つです。ターミナル(コマンドプロンプト)で、次のコマンドを実行してインストールします。

pip install pyserial matplotlib
1

Pythonがインストール済みか確認する

ターミナルでpython --version(環境によってはpython3 --version)を実行し、バージョンが表示されることを確認します。表示されない場合は、先にPython本体をインストールしてください。

2

pipでライブラリをインストールする

pip install pyserial matplotlibを実行します。数十秒〜数分でインストールが完了します。

3

インストールを確認する

pip show matplotlibを実行し、バージョン情報が表示されればインストール成功です。

Chapter 05 / Arduino Side

05Arduino側の準備|データを送信するコード

シンプルな1値送信のコード

Python側でグラフ表示をする場合も、Arduino側のコードは驚くほどシンプルです。基本的には、値を一定間隔でSerial.println()するだけで構いません。

// センサー値を一定間隔で送信するコード
const int sensorPin = A0;

void setup() {
  Serial.begin(9600);
}

void loop() {
  int value = analogRead(sensorPin);
  Serial.println(value);
  delay(50);  // 送信間隔(短くするほどグラフが滑らかになる)
}

送信間隔と滑らかさのバランス

delay()の値を短くするほど、送られてくるデータの密度が上がり、グラフは滑らかに動きます。ただし、短くしすぎるとパソコン側の処理が追いつかなくなる場合もあります。まずは50ミリ秒程度から試し、用途に応じて調整するとよいでしょう。



Chapter 06 / Python Basic Code

06Pythonの基本コード|1つのセンサー値をリアルタイム表示

FuncAnimationで定期的にグラフを更新する

Matplotlibには、グラフを一定間隔で自動更新できるFuncAnimationという仕組みがあります。これを使うと、シリアルポートから読み取った値を、そのままリアルタイムに描画し続けることができます。

# Arduinoのセンサー値をリアルタイムでグラフ表示するコード
import serial
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from collections import deque

# ポート名は環境に合わせて変更する(Windowsは"COM3"等、Macは"/dev/cu.usbmodemXXXX"等)
ser = serial.Serial("COM3", 9600, timeout=1)

MAX_LEN = 100  # 画面に表示する点の数
data = deque([0] * MAX_LEN, maxlen=MAX_LEN)

fig, ax = plt.subplots()
line, = ax.plot(data)
ax.set_ylim(0, 1023)  # analogReadの範囲に合わせて調整する
ax.set_xlabel("Time (frames)")
ax.set_ylabel("Sensor Value")
ax.set_title("Arduino Sensor - Realtime Plot")

def update(frame):
    if ser.in_waiting > 0:
        raw = ser.readline().decode("utf-8", errors="ignore").strip()
        if raw.isdigit():
            data.append(int(raw))
            line.set_ydata(data)
            line.set_xdata(range(len(data)))
    return line,

ani = animation.FuncAnimation(fig, update, interval=50, blit=True, cache_frame_data=False)
plt.show()

コードのポイント

deque(maxlen=MAX_LEN)を使うことで、常に直近100個分のデータだけを保持する「流れるグラフ」を簡単に作れます。ser.in_waitingで受信バッファにデータが来ているかを確認してから読み取ることで、データが来ていないときの無駄な待機を減らせます。interval=50は、グラフを更新する間隔(ミリ秒)です。Arduino側の送信間隔とおおよそ揃えておくと、無駄のない滑らかな表示になります。



Chapter 07 / Multiple Sensors

07応用|複数センサーを同時にグラフ表示する

Arduino側:カンマ区切りで複数の値を送る

加速度センサーのようにX・Y・Zの3軸を持つセンサーは、複数の値を同時にグラフ化したい代表例です。Arduino側では、値をカンマ区切りの1行にまとめて送信します。

// 3つの値をカンマ区切りで送信するコード(例:3軸のセンサーを想定)
void setup() {
  Serial.begin(9600);
}

void loop() {
  int x = analogRead(A0);
  int y = analogRead(A1);
  int z = analogRead(A2);

  Serial.print(x);
  Serial.print(",");
  Serial.print(y);
  Serial.print(",");
  Serial.println(z);

  delay(50);
}

Python側:カンマで分割して3本の線を描く

# 3つの値を同時にグラフ表示するコード
import serial
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from collections import deque

ser = serial.Serial("COM3", 9600, timeout=1)

MAX_LEN = 100
data_x = deque([0] * MAX_LEN, maxlen=MAX_LEN)
data_y = deque([0] * MAX_LEN, maxlen=MAX_LEN)
data_z = deque([0] * MAX_LEN, maxlen=MAX_LEN)

fig, ax = plt.subplots()
line_x, = ax.plot(data_x, label="X")
line_y, = ax.plot(data_y, label="Y")
line_z, = ax.plot(data_z, label="Z")
ax.set_ylim(0, 1023)
ax.legend(loc="upper right")

def update(frame):
    if ser.in_waiting > 0:
        raw = ser.readline().decode("utf-8", errors="ignore").strip()
        parts = raw.split(",")
        if len(parts) == 3 and all(p.lstrip("-").isdigit() for p in parts):
            data_x.append(int(parts[0]))
            data_y.append(int(parts[1]))
            data_z.append(int(parts[2]))
            line_x.set_ydata(data_x)
            line_y.set_ydata(data_y)
            line_z.set_ydata(data_z)
    return line_x, line_y, line_z

ani = animation.FuncAnimation(fig, update, interval=50, blit=True, cache_frame_data=False)
plt.show()

データの分割数を必ずチェックする

len(parts) == 3という条件は、意外と重要です。通信の途中でデータが1行分だけ欠けたり、途中で切れたりすると、想定より少ない・多い数の値が届くことがあります。この確認を省略すると、リストの範囲外を参照してプログラムがエラーで止まってしまうことがあるため、必ず件数を確認してから処理するようにしましょう。



Chapter 08 / Logging + Plotting

08実践|グラフ表示しながらCSVにも記録する

「見る」と「残す」を同時に行う

リアルタイムに眺めるだけでなく、あとから分析やレポートに使いたい場合は、受信したデータをCSVファイルに書き込みながら、同時にグラフ表示する構成が便利です。update()関数の中で、グラフの更新とファイルへの書き込みを両方行うだけで実現できます。

# グラフ表示しながらCSVにも記録するコード
import serial
import csv
import time
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from collections import deque

ser = serial.Serial("COM3", 9600, timeout=1)

MAX_LEN = 100
data = deque([0] * MAX_LEN, maxlen=MAX_LEN)

csv_file = open("sensor_log.csv", "w", newline="")
csv_writer = csv.writer(csv_file)
csv_writer.writerow(["timestamp", "value"])  # ヘッダー行

fig, ax = plt.subplots()
line, = ax.plot(data)
ax.set_ylim(0, 1023)

def update(frame):
    if ser.in_waiting > 0:
        raw = ser.readline().decode("utf-8", errors="ignore").strip()
        if raw.isdigit():
            value = int(raw)
            data.append(value)
            line.set_ydata(data)
            line.set_xdata(range(len(data)))

            # グラフ表示と同時にCSVへ1行ずつ追記する
            csv_writer.writerow([time.time(), value])
            csv_file.flush()
    return line,

ani = animation.FuncAnimation(fig, update, interval=50, blit=True, cache_frame_data=False)
plt.show()

csv_file.close()

flush()を入れておく理由

csv_file.flush()を呼ぶと、書き込んだ内容がすぐにディスクへ反映されます。これを省略すると、Pythonの内部バッファに一時的にデータが溜まったままになり、プログラムを異常終了させてしまった際に、直近の記録が失われてしまうことがあります。長時間の記録を行う場合は、この一手間を入れておくと安心です。

Chapter 09 / Troubleshooting

09よくあるトラブルと対処法

症状別の対処早見表

症状 主な原因 対処法
「could not open port」というエラーが出る ポート名の指定違い、またはArduino IDEのシリアルモニタが開いたまま ポート名を確認し、Arduino IDE側のシリアルモニタ・シリアルプロッタを閉じてから実行する
グラフが真っ直ぐなまま動かない ボーレートの不一致、または受信データの形式違い Serial.begin()の数値とser = serial.Serial()の数値を一致させる(5章参照)
途中でエラーが出て止まる(ValueError等) ノイズや欠損で不完全な行を受信し、int()変換に失敗している isdigit()等で数値として妥当かを確認してから変換する(6・7章のコード参照)
3軸のはずが2つしか表示されない データの一部が欠けて届いている len(parts)の件数チェックを入れる(7章参照)
グラフの動きがカクカクする 更新間隔(interval)や送信間隔(delay)が長すぎる 両方の間隔を30〜50ms程度に短くし、blit=Trueを指定する(10章FAQ参照)

原因を素早く切り分けるコツ

編集部想定シナリオ

Mさんは3軸センサーのグラフ化コードを試したが、数分に1回、プログラムがエラーで止まってしまう現象に悩まされていた。原因を調べたところ、USBケーブルの接触が不安定なタイミングで、1行分のデータが「12,34」のように途中で切れて届いていたことが分かった。件数チェックの条件を追加したところ、不完全な行は静かに読み飛ばされるようになり、エラーで止まることがなくなった。

Chapter 10 / FAQ

10よくある質問

基本のQ&A

Q.グラフの動きがカクカクします。滑らかにするにはどうすればいいですか?
A.主な原因は2つあります。1つは更新間隔(interval)が長すぎること、もう1つはArduino側のdelay()が長すぎることです。FuncAnimationのintervalを30〜50ms程度に短くし、Arduino側の送信間隔も20〜50ms程度に合わせてみてください。また、blit=Trueを指定すると、変化した部分だけを再描画するため、体感速度が大きく改善します。

Q.シリアルプロッタとPython・Matplotlib、結局どちらを使えばいいですか?
A.動作確認やちょっとした波形の確認だけなら、追加インストール不要の純正シリアルプロッタで十分です。一方、グラフを画像として保存したい、複数センサーを自由なレイアウトで並べたい、しきい値を超えたら色を変えたい、CSVに記録しながら同時に表示したいといった場合は、Python・Matplotlib側を使うことをおすすめします。目的に応じて使い分けるのが良いでしょう。

応用のQ&A

Q.グラフに表示されるデータが、実際の値より少し遅れて反映される気がします。
A.これは正常な挙動です。シリアル通信にはArduino側のバッファ、USBの転送、Python側の読み取りループなど、複数の段階を経由するための、ごくわずかな遅延が発生します。多くの用途では数十ミリ秒〜数百ミリ秒程度の遅延は問題になりませんが、遅延が気になる場合は、Arduino側の送信間隔を短くし、Python側のバッファに溜まったデータを毎回読み切る処理を入れると改善します。

Q.Pythonの実行を止めても、グラフの画像は残せますか?
A.残せます。Matplotlibのplt.savefig(“graph.png”)を使えば、その時点のグラフを画像ファイルとして保存できます。リアルタイム表示を終了する直前や、一定時間おきに自動保存する処理を追加しておくと、あとから結果を振り返りやすくなります。

関連記事・参考資料

基礎を学べる記事

  1. YOFUKASI LAB「ArduinoとPCのシリアル通信入門|Serial.printで値を可視化する」2026年, https://yofukasi-lab-wp.com/2026/08/18/arduinoとpcのシリアル通信入門――serial-printで値を可視化す/
  2. YOFUKASI LAB「Arduinoのシリアルモニタ活用術」2026年, https://yofukasi-lab-wp.com/2026/08/22/arduino-serial-monitor-debugging/
  3. YOFUKASI LAB「Arduinoで使える定番センサー30選」2026年, https://yofukasi-lab-wp.com/2026/09/11/arduino-30-sensors-guide/
  4. YOFUKASI LAB「Arduinoに必要な工具・部品リスト」2026年, https://yofukasi-lab-wp.com/2026/08/22/arduino-tools-parts/
  5. YOFUKASI LAB「Arduino IDEのダウンロード・インストール方法」2026年, https://yofukasi-lab-wp.com/2026/08/01/arduino-install-download/

応用・関連記事

  1. YOFUKASI LAB「電子工作×プログラミング入門」2026年, https://yofukasi-lab-wp.com/2026/09/12/electronics-programming-getting-started/
  2. YOFUKASI LAB「Arduinoで土壌水分センサーを使う」2026年, https://yofukasi-lab-wp.com/2026/09/03/arduino-soil-moisture-sensor/
  3. YOFUKASI LAB「Arduinoで音センサーを使う方法」2026年, https://yofukasi-lab-wp.com/2026/09/04/arduino-sound-sensor/
  4. YOFUKASI LAB「Arduino×MPU6050で加速度・ジャイロセンサーを使う方法」2026年, https://yofukasi-lab-wp.com/2026/08/31/mpu6050/
  5. YOFUKASI LAB「ArduinoでSDカードにCSV保存する方法」2026年, https://yofukasi-lab-wp.com/2026/08/31/arduino-sd-card-csv-save/
  6. YOFUKASI LAB「Arduinoが「ポートが見つからない」時の原因と解決策」2026年, https://yofukasi-lab-wp.com/2026/08/23/arduino-port-not-found/
  7. YOFUKASI LAB「Arduinoのコンパイルエラー一覧」2026年, https://yofukasi-lab-wp.com/2026/07/30/error/

参考資料(外部・一次情報)

  1. Arduino Documentation「Using the Serial Plotter Tool」, https://docs.arduino.cc/software/ide-v2/tutorials/ide-v2-serial-plotter
  2. Luis Llamas「Easily Create Graphs in Arduino IDE with Serial Plotter」, https://www.luisllamas.es/en/arduino-serial-plotter/
  3. Matplotlib Documentation「matplotlib.animation.FuncAnimation」, https://matplotlib.org/stable/api/_as_gen/matplotlib.animation.FuncAnimation.html
  4. pySerial Documentation, https://pyserial.readthedocs.io/en/latest/pyserial.html

※本記事は個人の学習・電子工作用途を対象にしています。医療機器や製品として実際に運用する場合は、精度検証・電気安全・関連法規について専門家に別途ご相談ください。


関連記事

特集記事

コメント

この記事へのコメントはありません。

TOP
CLOSE