Progress Log: ArduinoJsonの使い方ガイド¶
Task Description¶
ArduinoJson(Arduino/ESP32向けのJSONライブラリ)の使い方をKurikintonsプロジェクトの文脈で整理しました。
以下の観点から調査・整理しました。
- ArduinoJsonの概要と特徴
- インストール方法
- 基本的な使い方(オブジェクト作成、シリアル化、デシリアル化)
- JSON配列の操作
- JSONL形式での実装例
- ESP32での実装上の注意点
- メモリ効率の考慮
Outcome¶
ArduinoJsonの包括的な使用ガイドを作成しました。
ArduinoJsonについて¶
ArduinoJson は、Arduino、ESP32などのマイコンボード向けに最適化されたC++のJSONライブラリです。
主な特徴:
- メモリ効率が高い(スタック/静的メモリ使用)
- コンパイル時のメモリ量決定(動的メモリアロケーション最小化)
- シンプルで直感的なAPI
- Arduino IDEおよびPlatformIOで標準サポート
- ドキュメントが豊富
バージョン情報:
- 現在の最新バージョン: v7.x
- Kurikintonsで使用可能: v6.x~v7.x
インストール方法¶
PlatformIOでのインストール¶
platformio.iniに以下を追加:
[env:esp32dev]
lib_deps =
ArduinoJson @ ^7.0.0
または、以下のコマンドで自動追加:
pio lib install "ArduinoJson"
Arduino IDEでのインストール¶
- スケッチ → ライブラリをインクルード → ライブラリを管理
- 「ArduinoJson」を検索
- インストール
基本的な使い方¶
- 初期化(静的メモリ確保)
- 初期化(動的メモリ確保)
- JSON値の代入
-
JSON値の出力(JSONL形式)
-
イベントごとにデータを逐次送信する
- JSON構造はフラットにする。ネストや配列は使わない
1. 初期化(静的メモリ確保)¶
#include <ArduinoJson.h>
void setup() {
// 256バイトのスタックメモリでKurikintons検出データドキュメントを作成
StaticJsonDocument<256> doc;
// 検出データ用のフィールドを確保
doc["signal1"] = 0; // チャネル1信号値
doc["signal2"] = 0; // チャネル2信号値
doc["signal3"] = 0; // チャネル3信号値
doc["adc"] = 0; // ADC値
doc["temp"] = 0.0; // 温度
doc["pressure"] = 0.0; // 気圧
doc["humidity"] = 0.0; // 湿度
doc["uptime_ms"] = 0; // アップタイム(ミリ秒)
doc["duration_us"] = 0; // イベント間隔(マイクロ秒)
Serial.println(F("Detection document created successfully"));
}
2. 初期化(動的メモリ確保)¶
大規模なJSONが必要な場合は動的なヒープを確保する
// 256バイトのヒープメモリでKurikintons検出データドキュメントを作成
DynamicJsonDocument doc(256);
// 検出データを設定
doc["signal1"] = 95;
doc["signal2"] = 87;
doc["signal3"] = 92;
doc["adc"] = 2048;
doc["temp"] = 25.35;
doc["pressure"] = 1013.25;
doc["humidity"] = 45.67;
doc["uptime_ms"] = 123456;
doc["duration_us"] = 1234567890;
ESP32での推奨:
StaticJsonDocumentを使用(スタックは十分にある)- 小~中規模データは256~512バイト
- 大規模データは1024~2048バイト
3. JSON値の代入¶
// setupで初期化済み
StaticJsonDocument<256> doc;
// 検出データを設定
doc["signal1"] = 95; // チャネル1信号値(整数)
doc["signal2"] = 87; // チャネル2信号値(整数)
doc["signal3"] = 92; // チャネル3信号値(整数)
doc["adc"] = 2048; // ADC値(整数)
doc["temp"] = 25.35; // 温度(浮動小数点数)
doc["pressure"] = 1013.25; // 気圧(浮動小数点数)
doc["humidity"] = 45.67; // 湿度(浮動小数点数)
doc["uptime_ms"] = 123456; // アップタイム(ミリ秒)
doc["duration_us"] = 1234567890; // イベント間隔(マイクロ秒)
4. JSON形式の出力(シリアル化)(JSONL形式)¶
StaticJsonDocument<256> doc;
// Kurikintonsの検出データを設定
doc["signal1"] = 95;
doc["signal2"] = 87;
doc["signal3"] = 92;
doc["adc"] = 2048;
doc["temp"] = 25.35;
doc["pressure"] = 1013.25;
doc["humidity"] = 45.67;
doc["uptime_ms"] = 123456;
doc["duration_us"] = 1234567890;
// コンパクト形式でシリアル出力(JSONL:1行JSON)
serializeJson(doc, Serial);
Serial.println(); // 改行で1行を完成
シリアル出力:
{"signal1":95,"signal2":87,"signal3":92,"adc":2048,"temp":25.35,"pressure":1013.25,"humidity":45.67,"uptime_ms":123456,"duration_us":1234567890}
2. 可視形式(デバッグ用)¶
StaticJsonDocument<256> doc;
doc["signal1"] = 95;
doc["signal2"] = 87;
doc["signal3"] = 92;
doc["adc"] = 2048;
doc["temp"] = 25.35;
// 見やすい形式で出力(デバッグ時のみ使用)
serializeJsonPretty(doc, Serial);
シリアル出力:
{
"signal1": 95,
"signal2": 87,
"signal3": 92,
"adc": 2048,
"temp": 25.35
}
JSONL形式での実装例¶
ESP32側:検出データをJSONL形式で出力¶
#include <ArduinoJson.h>
#include "cosmic_detector.h"
// グローバル変数
uint64_t last_event_time_us = 0;
void setup() {
Serial.begin(115200);
delay(3000); // デバイス安定化待機
cosmic_detector_init();
last_event_time_us = micros();
}
void loop() {
cosmic_detection_t detection = cosmic_detector_read();
if (detection.detected) {
// JSON形式で検出データを記録
StaticJsonDocument<256> doc;
// タイムスタンプ
uint64_t current_time = micros();
doc["timestamp_us"] = (uint32_t)(current_time / 1000); // ミリ秒単位
// 検出データ
doc["signal1"] = detection.signal1;
doc["signal2"] = detection.signal2;
doc["signal3"] = detection.signal3;
// センサー値
doc["adc"] = analogRead(ADC_PIN);
doc["temp"] = bme280_read_temperature();
doc["pressure"] = bme280_read_pressure();
doc["humidity"] = bme280_read_humidity();
// イベント間隔(マイクロ秒)
uint64_t duration_us = current_time - last_event_time_us;
doc["duration_us"] = duration_us;
// JSONL形式で出力(1行)
serializeJson(doc, Serial);
Serial.println(); // 改行で1行を終了
// 時刻を更新
last_event_time_us = current_time;
// LED点灯など
digitalWrite(LED_PIN, HIGH);
delay(50);
digitalWrite(LED_PIN, LOW);
}
delay(10); // 検出サイクル
}
メモリ使用量の計算¶
ドキュメントサイズの決定方法¶
メモリ使用量(バイト)= キー + 値 + JSON構造オーバーヘッド
サンプル計算(検出データ):
{
"signal1": 100, // キー8 + 値3 + 構造3
"signal2": 85, // キー8 + 値2 + 構造3
"signal3": 92, // キー8 + 値2 + 構造3
"adc": 2048, // キー3 + 値4 + 構造3
"temp": 25.35, // キー4 + 値5 + 構造3
"pressure": 1013.25, // キー8 + 値7 + 構造3
"humidity": 45.67, // キー8 + 値5 + 構造3
"duration_us": 1234567890 // キー11 + 値10 + 構造3
}
推定メモリ: 150~200バイト
推奨サイズ:
- 単純な検出データ: 256バイト
- 複雑なセンサー設定: 512バイト
- 配列を含むデータ: 1024バイト以上
ESP32でのメモリ確認¶
void print_heap_info() {
Serial.print(F("Free heap: "));
Serial.print(ESP.getFreeHeap());
Serial.println(F(" bytes"));
Serial.print(F("Largest free block: "));
Serial.print(ESP.getMaxAllocHeap());
Serial.println(F(" bytes"));
}
デバッグとトラブルシューティング¶
デシリアル化エラーの確認¶
const char* json = "{invalid json}";
StaticJsonDocument<256> doc;
DeserializationError error = deserializeJson(doc, json);
if (error) {
Serial.print(F("Parse error: "));
Serial.println(error.f_str()); // 詳細エラーメッセージ
}
一般的なエラー:
NotDeserialized: JSON解析なしInvalidInput: 入力が無効NoMemory: メモリ不足IncompleteInput: 入力が不完全
ドキュメントサイズが足りない場合¶
// 警告を確認
bool overflowed = doc.overflowed();
if (overflowed) {
Serial.println(F("Document overflowed!"));
// サイズを増やす
}
Kurikintonsでの推奨設定¶
platformio.iniの設定¶
[env:esp32dev]
lib_deps =
ArduinoJson @ ^7.0.0
インクルードと初期化¶
#include <ArduinoJson.h>
// グローバルドキュメント(再利用)
StaticJsonDocument<256> detection_doc;
StaticJsonDocument<512> config_doc;
void setup() {
Serial.begin(115200);
// ArduinoJsonは追加初期化不要
}
パフォーマンスのベストプラクティス¶
- ドキュメントをグローバルで作成(毎回の割り当て回避)
- StaticJsonDocumentを使用(スタック使用でヒープフラグメント防止)
- 不要になったドキュメントは
clear()で再利用 - シリアル出力時は改行後にフラッシュ(
Serial.flush())
Learnings¶
- ArduinoJsonはESP32向けに最適化: 固定サイズメモリ確保でヒープフラグメント回避
- StaticJsonDocumentが基本: 開発時のシンプルさと実運用の信頼性を両立
- JSONL形式出力は簡単:
serializeJson()とSerial.println()で1行JSON - メモリサイズの事前計算が重要: オーバーフロー防止と効率化のため
- デシリアル化時のエラー処理: 外部入力を扱う場合は必須
Next Steps¶
- Kurikintonsへの統合:
- ArduinoJsonをpluginio.iniに追加
- 検出データのJSONL形式化
-
シリアル出力を新形式に変更
-
検出ログ機能の実装:
- SDカードへのJSONL保存(オプション)
-
ホスト側でのログ解析Python スクリプト
-
テストと検証:
- JSON形式での動作確認
- メモリ使用量の測定
- パフォーマンステスト(シリアル出力速度)