前回はこちら
Raspberry Pi はマイコンと同じようにセンサーの電圧値などを簡単に計測できます。
またPCと同じようにファイル操作、グラフの作成などの作業も行うことが出来ます。
今回はそんなRaspberry Piの特性を活かして、電圧情報をファイルとして保存し、またPython言語を使ってグラフ表示を行う方法を学びます。

Pythonでファイルにデータを保存する方法
プログラムでデータを扱うとき、ただ画面に表示するだけでなく「ファイルに保存する」ことがよくあります。
測定データを残したり、実験結果をまとめたり、後からグラフ化したりするのに欠かせません。
ここでは Python でのファイル保存の基本を順を追って学んでいきましょう。
1. そもそもファイルとは
- コンピュータ上の「ノート」のようなものです。
- 中に文字や数字を書き込んだり(保存)、後で読み返したり(読み込み)できます。
- .txt、.exeなどファイル名の最後の文字(拡張子)によってファイルの種類を見分けます。
- 種類によって中身のデータの書き方が変わります。
- Pythonでも「ファイルを開いて → 書く → 閉じる」という流れで操作します。
2.最も基本的な書き込み
# "sample.txt" という名前のファイルを作成して書き込み
f = open("sample.txt", "w") # "w" は write(書き込み)の意味
f.write("こんにちは、ファイル!\n") # 1行書く
f.write("Pythonでファイルに保存できます。\n")
f.close() # 忘れずに閉じる
- これを実行すると、同じフォルダに
sample.txt
ができます。 - 中身をテキストエディタで開くと、書いた文章が入っています。
キーワード:
"w"
… 上書きモード。新しく作る/中身を消して書き直す。"a"
… 追記モード。既存ファイルの最後に追加。"r"
… 読み込みモード。
3.with文を使った保存
Pythonでは with open(...) as f:
と書くのが一般的です。
自動で閉じてくれるので、閉じ忘れの心配がありません。
with open("sample2.txt", "w") as f:
f.write("1行目\n")
f.write("2行目\n")
4.繰り返し保存する場合
例えば、0〜9までの数字をファイルに1行ずつ書く場合:
with open("numbers.txt", "w") as f:
for i in range(10):
f.write(f"{i}\n") # f-stringで整形して書き込み
出力される numbers.txt
はこんな感じです。
0
1
2
3
...
9
5.CSVで保存する
**Comma Separated Values(カンマ区切り値)**の略です。
表のデータを保存することが出来、後からExcel、Googleスプレッドシートなどで開くことが出来ます。
time,value
0.0,10
0.1,12
0.2,15
6.CSVの書き込み
Pythonでは csv
モジュールを使うと便利です。writer.writerow([...])
で1行ずつリストの形でデータを書けます。
import csv
with open("data.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["time", "value"]) # ヘッダー(列名)
writer.writerow([0.0, 10])
writer.writerow([0.1, 12])
writer.writerow([0.2, 15])
実行後に data.csv
を開くと、表のようなデータが入っています。newline=""
を付けるのは、余計な空行が入るのを防ぐためです。
7.繰り返してデータを記録する
測定値を時系列で保存したい場合は、ループで繰り返し書き込めばOKです。
import csv, time
with open("log.csv", "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["time_sec", "value"])
t0 = time.perf_counter() # 実行開始時刻を基準に
for i in range(5): # 5回だけサンプルを保存
t = time.perf_counter() - t0
value = i * 10
writer.writerow([t, value])
time.sleep(0.5)
これを実行すると、0.5秒ごとに測った「時刻」と「値」が5行分記録されます。
後からグラフにすれば「時間に応じて値が変わる様子」が見えるわけです。
問題4
可変抵抗を ADC0834(CH0)で読み取り、0.1秒ごとにCSVファイルへ保存しなさい。
- ファイル名は実行時刻入り(例:
20250922_153045_adc0834.csv
) - 列は
time_sec, raw, voltage_V
- 記録中は画面にも
time, raw, voltage
を表示 - Ctrl+Cで止めたら保存先パスを表示
保存したCSVを Excel などで開き、可変抵抗を回したときに値がどう変わるか確認してみましょう。
解答例はこちら
import spidev
import time
import csv
from pathlib import Path
from datetime import datetime
# === SPI 初期化 ===
spi = spidev.SpiDev()
spi.open(0, 0) # bus=0, CE0
spi.mode = 0 # CPOL=0, CPHA=0
spi.max_speed_hz = 250_000 # 200〜400kHzが安定
spi.bits_per_word = 8
# === ADC0834 設定 ===
VREF = 3.3 # 基準電圧(3.3V)
CMD_BASE = 0x08 # SGL=1(単端子)ビット
def _cmd_for_channel(ch: int) -> int:
"""ADC0834へ送る2バイト目のコマンドを生成(chは0..3)"""
return (CMD_BASE | (ch & 0x03)) << 4
def read_adc0834_once(ch: int = 0) -> int:
"""指定チャネルを1回だけ読み取る(0..255)"""
r = spi.xfer2([0x01, _cmd_for_channel(ch), 0x00])
# ダミー0の後の MSB→LSB 8bit を取り出す(v4式)
return ((r[1] & 0x0F) << 4) | (r[2] >> 4)
# === ログ保存の準備(ホーム直下に adc_logs) ===
home = Path.home() # 例: /home/ando
log_dir = home / "adc_logs"
log_dir.mkdir(exist_ok=True) # 無ければ作成
filename = datetime.now().strftime("%Y%m%d_%H%M%S_adc0834.csv")
filepath = log_dir / filename
interval = 0.1 # 0.1秒ごとに記録
try:
with open(filepath, "w", newline="") as f:
writer = csv.writer(f)
writer.writerow(["time_sec", "raw", "voltage_V"]) # ヘッダー
t0 = time.perf_counter()
print(f"Logging to: {filepath} (Ctrl+C で停止)")
while True:
raw = read_adc0834_once(0) # CH0
voltage = raw * VREF / 255
t = time.perf_counter() - t0
# 画面にも表示(整形)
print(f"{t:8.3f}, raw={raw:3d}, {voltage:6.3f} V")
# CSVに書き込み(文字列/数値どちらでもOK)
writer.writerow([f"{t:.3f}", raw, f"{voltage:.4f}"])
f.flush() # 安全のため都度フラッシュ
time.sleep(interval)
except KeyboardInterrupt:
print("\nStopped by user.")
print(f"Saved file: {filepath}")
finally:
spi.close()
Pythonでグラフ表示
実験や測定では数値を集めるだけでは変化が分かりにくいです。
グラフにすると「どう増えているか」「どこで変化したか」が一目で理解できます。
Pythonには matplotlib という強力なグラフ描画ライブラリがあります。
1.ライブラリのインストール
Raspberry Pi OS では apt を使ってインストールするのが簡単で安全です。
1.ターミナル(黒い画面のアプリ)を開く
2.次のコマンドを入力して Enter キーを押す
sudo apt update
sudo apt install -y python3-matplotlib python3-pandas
2.インストール確認
Thonnyを起動し、シェル(>>>
のところ)で以下を入力してください。
import matplotlib, pandas
print(matplotlib.__version__, pandas.__version__)
3.matplotlibを使ったグラフの基本
import matplotlib.pyplot as plt
x = [0, 1, 2, 3, 4]
y = [0, 1, 4, 9, 16]
plt.plot(x, y) # 折れ線グラフを描画
plt.xlabel("X axis") # x軸ラベル
plt.ylabel("Y axis") # y軸ラベル
plt.title("Sample Graph") # タイトル
plt.grid(True) # 補助線を表示
plt.show() # グラフを表示
実行すると、新しいウィンドウにグラフが表示されます。
※ ラベルはすべて英語で書くと、フォントエラーが出ません。
4.CSVファイルを読み込んでグラフ化
前の課題(問題4)で保存した CSV ファイル(例:adc_logs/20250922_153045_adc0834.csv
)を読み込み、電圧の変化をプロットしてみましょう。
import pandas as pd
import matplotlib.pyplot as plt
# CSVファイルを読み込む(自分のファイル名に置き換える)
df = pd.read_csv("adc_logs/20250922_153045_adc0834.csv")
# 折れ線グラフを描画
plt.plot(df["time_sec"], df["voltage_V"])
# グラフの整形
plt.xlabel("Time [sec]")
plt.ylabel("Voltage [V]")
plt.title("ADC0834 Logging Data")
plt.grid(True)
plt.show()
問題5
CSVファイルをグラフ化する基本コードをベースに、
区間の拡大
線のスタイル変更
移動平均の追加
特徴点の強調表示
など、自分なりに一工夫したグラフを作成しなさい。
回答例はこちら
回答例(区間を絞って表示)
# 0〜5秒のデータだけ抽出して描画
df_zoom = df[df["time_sec"] <= 5]
plt.plot(df_zoom["time_sec"], df_zoom["voltage_V"])
plt.xlabel("Time [sec]")
plt.ylabel("Voltage [V]")
plt.title("Zoomed View (0–5 sec)")
plt.grid(True)
plt.show()
回答例(移動平均をかけて滑らかに)
# 5点移動平均を計算
df["smoothed"] = df["voltage_V"].rolling(window=5).mean()
plt.plot(df["time_sec"], df["voltage_V"], alpha=0.4, label="Raw")
plt.plot(df["time_sec"], df["smoothed"], color="red", label="Smoothed (5-point)")
plt.xlabel("Time [sec]")
plt.ylabel("Voltage [V]")
plt.title("Raw vs Smoothed")
plt.grid(True)
plt.legend()
plt.show()
回答例(発展③:最大値を強調表示)
max_idx = df["voltage_V"].idxmax()
max_time = df["time_sec"][max_idx]
max_val = df["voltage_V"][max_idx]
plt.plot(df["time_sec"], df["voltage_V"])
plt.scatter(max_time, max_val, color="red", label=f"Max: {max_val:.2f} V")
plt.xlabel("Time [sec]")
plt.ylabel("Voltage [V]")
plt.title("Max Value Highlighted")
plt.grid(True)
plt.legend()
plt.show()
次回はこちら