プロンプト一つで、
基板に命を吹き込む。
AIにArduinoのコードを書かせるのは「丸投げ」ではありません。良いプロンプトの設計、生成されたコードの読解、そして実機での検証。
この3つを回せるようになると、AIは最速の電子工作パートナーになります。本記事では実際に生成させたスケッチを題材に、行単位で仕組みを解説します。

なぜAIでArduinoコードを書くのか
Arduinoの文法自体はシンプルですが、pinModeの設定漏れ、割り込みでのvolatile忘れ、センサのデータシート特有の計算式など、
「知らないと詰まる」細部が多いのも事実です。AIはこうした定型知識の補完に強く、アイデアを電気信号に変換するまでの時間を大幅に短縮してくれます。
基本文法や関数の正確な仕様は、最終的にはArduino公式の言語リファレンスで裏取りするのが確実です。
ただし、AIが出力したコードをそのまま書き込むのは推奨しません。目的は「AIに書かせて終わり」ではなく、生成されたコードを読み解き、自分の回路とすり合わせる力を身につけることです。
本記事はその実践トレーニングでもあります。
- 定型処理の高速化 ― センサ初期化、ライブラリの呼び出し方など
- 設計のたたき台作り ― 状態遷移やピン配置の初期案
- デバッグの壁打ち相手 ― エラーメッセージを貼るだけで原因の仮説が返る
良いプロンプトの設計図
AIへの指示が曖昧だと、動作要件が抜けたコードが返ってきます。Arduino向けプロンプトには、最低限次の4要素を含めるのがコツです。
| 要素 | 内容 | 例 |
|---|---|---|
| ボードと制約 | 機種、メモリ制約、電源 | Arduino Uno / SRAM 2KB |
| ハードウェア構成 | センサ・出力デバイスとピン番号 | 超音波センサ HC-SR04(Trig=9, Echo=10) |
| 動作条件 | しきい値、タイミング、状態遷移 | 距離が20cm未満でブザーとLEDを作動 |
| 非機能要件 | ブロッキング禁止、コメント量など | delay()を使わずmillis()で制御 |
実際に使ったプロンプトはこちらです。ピン配置と測定原理はHC-SR04のデータシートを先に読んでから組み立てました。
物体との距離を常時測定するプログラムを書いてください。
条件:
・距離が20cm未満になったらピン8のブザーを鳴らし、ピン7のLEDを点滅させる
・それ以外はブザーとLEDを停止する
・delay()は使わずmillis()でノンブロッキングに実装する
・測定値はシリアルモニタに0.5秒間隔で表示する
・各処理ブロックに日本語でコメントを付ける
「delay()禁止」「millis()で」のように実装方針まで指定すると、後工程の可読性が大きく変わります。曖昧な依頼ほど、AIは無難な(=ブロッキングな)実装を選びがちです。
生成されたスケッチ全文
上のプロンプトに対してAIが返した実際のコードです。次のセクションで、このコードをブロックごとに解説していきます。
// 超音波距離センサによる接近警告システム
// ボード: Arduino Uno / センサ: HC-SR04
const int TRIG_PIN = 9;
const int ECHO_PIN = 10;
const int BUZZER_PIN = 8;
const int LED_PIN = 7;
const int THRESHOLD_CM = 20; // 警告を出す距離のしきい値
const unsigned long BLINK_INTERVAL = 200; // LED点滅の間隔(ms)
const unsigned long PRINT_INTERVAL = 500; // シリアル表示の間隔(ms)
unsigned long lastBlinkTime = 0;
unsigned long lastPrintTime = 0;
bool ledState = false;
void setup() {
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
Serial.begin(9600);
}
float measureDistanceCm() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 30000);
if (duration == 0) return -1; // タイムアウト(未検出)
return duration * 0.0343 / 2.0;
}
void loop() {
unsigned long now = millis();
float distance = measureDistanceCm();
bool isAlert = (distance > 0 && distance < THRESHOLD_CM);
if (isAlert) {
digitalWrite(BUZZER_PIN, HIGH);
if (now - lastBlinkTime >= BLINK_INTERVAL) {
lastBlinkTime = now;
ledState = !ledState;
digitalWrite(LED_PIN, ledState);
}
} else {
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(LED_PIN, LOW);
ledState = false;
}
if (now - lastPrintTime >= PRINT_INTERVAL) {
lastPrintTime = now;
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
}
}
コード解説:ブロック単位で読む
AIが生成したコードは「動く」だけでなく「なぜそう書かれているか」まで理解して初めて自分の資産になります。ブロックごとに見ていきましょう。
① 定数とピン定義
constで宣言しているのは、コード中で誤って書き換えられるのを防ぐためです。また、数値が散らばらず先頭にまとまっているので、しきい値を「20cm→30cm」に変えたい時もここ一箇所を直すだけで済みます。
② millis()による時間管理変数
delay()を使わない代わりに、「前回いつ処理したか」を覚えておく変数です。unsigned longにしているのは、millis()の戻り値が非常に大きな数(約49日で一周)になるため、符号なし32ビットで受ける必要があるからです。詳しい仕様はmillis()の公式リファレンスにまとまっています。
③ measureDistanceCm() ― センサ計測の関数化
pulseIn()の第3引数30000はタイムアウト(マイクロ秒)で、これを指定しないと物体が検出できない時にプログラム全体が固まるリスクがあります。AIはこの安全策を自発的に入れていますが、初心者が手書きすると見落としやすいポイントです。
測定ロジックを
loop()の外に関数として切り出しているのも読みやすさのポイントで、loop()は「何をするか」だけを記述し、「どう測るか」は関数に隠蔽されています。
④ loop() ― 状態判定とノンブロッキング点滅
delay()を使わない点滅の定石パターンです。「経過時間がインターバルを超えたら状態を反転させる」ことで、ブザーの判定やシリアル出力を止めずにLEDだけを一定間隔で点滅させられます。
now - lastBlinkTimeという引き算はmillis()が一周してもオーバーフロー演算で正しく動くよう設計された書き方です。
distance > 0の条件が入っているのは、計測失敗時に関数が-1を返す仕様(②で見たタイムアウト処理)と対応しています。異常値を警告条件から除外するという、センサコードにありがちな考慮漏れをAIが自動で埋めている箇所です。
AI生成コードにありがちな落とし穴
便利な一方で、AIの出力は「もっともらしいが実機では動かない」ことも珍しくありません。代表的な注意点をまとめます。
存在しないピン番号やライブラリ関数を指定してくることがある。特にボード固有の割り込み対応ピン(UnoならD2/D3のみ等)は必ずデータシートと突き合わせる。
複数の重い処理をloop()内に詰め込み、実質的にブロッキングになっているケース。「delayを使っていないから安全」とは限らない。
割り込みハンドラ内でSerial.print()のような重い処理を呼んでしまう、volatile修飾子の付け忘れなど、割り込み特有のミスは特に見落としやすい。
これらは「動かしてみないと分からない」ものが多いため、次のステップである実機検証が欠かせません。
実機で検証し、対話で直す
書き込んで終わりではなく、Arduino IDEのシリアルモニタで実測値を見ながら、期待通りに動いているかを確認します。
うまくいかない場合は、エラーメッセージやおかしな挙動をそのままAIに伝えるのが最短ルートです。
pulseIn()がタイムアウトした時の戻り値の扱いを見直してください。
このように「症状」を具体的に伝えると、AIは該当ブロックだけを修正した差分を返してくれます。全部を書き直させるのではなく、
問題箇所を絞り込んで対話することが、AI活用と自力デバッグ力の両方を伸ばすコツです。
まとめ:次に試すこと
AIはArduinoコードの「下書き」を高速に用意してくれますが、最終的に回路を安定して動かすのは、コードを読み解き検証する人間の理解です。
本記事のワークフロー(プロンプト設計 → 生成 → 解説読解 → 実機検証 → 対話修正)を繰り返すことで、AIと組む開発速度はどんどん上がっていきます。
- 状態機械への拡張:警告レベルを多段階にし、
enumで状態を管理させてみる - 無線化:ESP32へ移植し、検知結果をWi-Fi経由でスマホに通知するようAIに依頼する
- 省メモリ化:
F()マクロの活用など、AIにメモリ最適化案を出させて比較する
コメント