ガイド · 読了まで17分

AIでArduinoのコードを書く:上手なプロンプト、テストと修正

ChatGPTなどのAIツールでArduinoのコードを書く方法を解説します。プロンプトのテンプレート、書き込み前の確認、存在しない関数、間違ったピン、delay()によるフリーズ、商用電源の安全について。

AIでArduinoのコードを書くとは、ChatGPT、Gemini、Claude、Copilotなどのチャットアシスタントにプロジェクトの内容を説明し、Arduino、ESP32、Raspberry Pi Picoで動くコードを書いてもらうことです。上手に使えば、何時間もかかる作業が数分で終わります。白紙から始める代わりに、すぐにコンパイルできる下書きが手に入るからです。ただし、AIには回路が見えず、机の上にどのボードがあるかも分かりません。しかも、間違ったことを自信たっぷりに言うこともあります。存在しないライブラリの関数を作り出したり、間違ったピンを選んだり、すべてを止めてしまうdelay()のループを書いたりします。だからこそ、本当に必要なスキルはコードを頼むことではなく、上手に頼み、返ってきたものを確かめることです。

このガイドでは、AIアシスタントがどのようにArduinoのコードを作り、なぜ間違えるのか、ボード、ピン、ライブラリ、期待する動作を含む上手なプロンプト(指示文)の書き方、そして書き込む前にコードを確認する手順を紹介します。よくある3つの間違いを、実際のコンパイラのメッセージと修正済みのコードで見ていきます。さらに、コンパイルエラーを貼り付けて直してもらう正しい方法、商用電源を扱うときにAIを信用してはいけない理由、学ぶことをやめずにこれらのツールを使う方法も説明します。

Arduino Uno R3ボード
AIはコードを書けますが、ボードや配線、使っているモジュールは見えません。その情報はプロンプトで伝える必要があります。

AIはどのようにArduinoのコードを書き、なぜ間違えるのか?

ChatGPTのような大規模言語モデル(LLM)は、コンパイラのようにコードを実行して書くのではありません。学習中に見た何百万もの例をもとに、最もありそうな続きを予測して書いています。ネット上に例がたくさんあるテーマ(LEDの点滅、DHT11の読み取り、サーボの回転)では、この方法はとてもうまくいきます。しかし、モデルの知識はある時点で止まっているため、新しいバージョンのライブラリで変わった関数を知らないことがあります。同じ名前の2つの別のライブラリの関数を混同することもあります。最も重要なのは、「分かりません」と言う代わりに、もっともらしく聞こえる答えを作り出すことがある点です。これをハルシネーションと呼びます。モデルには回路が見えないので、ピン番号、電圧レベル、モジュールのバージョンは、こちらが書いた内容か、モデル自身の推測から決まります。

作業AIの得意度理由
簡単なサンプルコード(LED、ボタン、センサーの読み取り)とても得意ネット上に似た例が何千もある
既存のコードを1行ずつ説明するとても得意コードを読んで説明するのに推測はいらない
コンパイルエラーの原因を見つける得意エラーメッセージには決まったパターンがあり、モデルはそれを見分けられる
最新バージョンのライブラリに合ったコード苦手知識がある時点で止まっていて、新しい関数を知らないことがある
回路に合ったピンを選ぶ苦手ボードや配線が見えないので、推測で選ぶ
タイミング処理と複数の作業の同時実行まあまあほとんどの例がdelay()を使っているため、処理を止めるコードを書く
商用電源、バッテリー、大電流の回路信頼できない間違いの代償はやけど、火災、感電。モデルは責任を負えない

上手なプロンプトの書き方は?

AIが出すコードは、こちらが与えた情報より良くなることはありません。「温度を測るArduinoのコードを書いて」のような1行の依頼では、ボード、センサー、ピン、ライブラリをモデルが自分で選びます。その選択が手元のものと合わなければ、コードはコンパイルできないか、コンパイルできても動きません。上手なプロンプトは、初めてプロジェクトの話を聞く友達に電話で説明するように書きます。ボード、部品、接続、ライブラリ、期待する動作、制約を1つずつ伝えましょう。Arduinoのプロンプトに入れるべき内容を下の表にまとめました。

プロンプトに入れる内容重要な理由例
ボードの正確な名前Uno、ESP32、Picoではピン、電圧、命令が違うArduino Uno R3(ATmega328P)
IDEとコアのバージョンESP32ではコア2.xと3.xで関数が変わったArduino IDE 2.3、esp32コア3.x
部品の型番DHT11とDHT22、SG90とMG996Rは同じではないDHT22、16x2 I2C LCD(PCF8574、アドレス0x27)
ピンの接続モデルがピンを作り出さず、実際の配線に従うDHT22のDATA → D2、ボタンはD3とGNDの間
ライブラリの名前と作者同じ名前の別のライブラリは使う関数が違うAdafruit DHT sensor library、Frank de Brabander氏のLiquidCrystal I2C
期待する動作を数字で「暑くなったら鳴らす」はあいまい、「30 °Cを超えたら」なら測れる2秒ごとに測定し、30 °Cを超えたらブザーを3回鳴らす
制約モデルの悪いくせを最初から防げるdelay()は使わず、millis()を使う
出力の形式コードとセットアップの情報が一緒に手に入る.inoファイル1つ、日本語のコメント、必要なライブラリの一覧

たとえば、次のプロンプトは1行の依頼よりはるかに良い結果を出します。「Arduino Uno R3とArduino IDE 2.3を使っています。DHT22のDATAピンはD2、アクティブブザーはD8、16x2 I2C LCD(PCF8574、アドレス0x27)はSDAがA4、SCLがA5です。Adafruit DHT sensor libraryとFrank de Brabander氏のLiquidCrystal I2Cライブラリをインストール済みです。2秒ごとに温度と湿度をLCDに表示し、温度が30 °Cを超えたらブザーを短く断続的に鳴らしてください。delay()ではなくmillis()を使い、各行にコメントを付けてください。最初にインストールが必要なライブラリを、最後に前提にしたことを一覧にしてください。」このプロンプトなら、モデルが推測しなければならないことはほとんど残りません。

コードを頼む前に、「このプロジェクトを書くのに足りない情報はありますか?まず質問してください」と付け加えましょう。良いモデルなら、電源電圧、センサーが単体かモジュールか、LCDのアドレスなどを聞いてきます。Wi-Fiのパスワード、APIキー、ボットのトークンは決してプロンプトに書かないでください。代わりに「YOUR_PASSWORD」のようなプレースホルダーを使い、本当の値は最後に自分でコードに入力します。

AIが書いたコードを確認する手順

コードがどれだけきれいに見えても、ボードに書き込む前にチェックリストで確認しましょう。ほとんどの手順は数分で終わり、ピンのつなぎ間違いで壊れたモジュールよりずっと安くすみます。

  1. まずコンパイルだけする:ボードをつながずに「検証」(チェックマークのボタン)を押します。エラーが出たら、後で紹介する方法で直してもらいましょう。メッセージの意味は「Arduinoのコンパイルエラー」の記事を見てください。
  2. ライブラリを1つずつ確認する:コード内のすべての#include行をライブラリマネージャで検索し、名前、作者、スケッチ例がコードと合うライブラリをインストールします。やり方が分からない場合は「Arduinoにライブラリを追加する方法」のガイドで手順を説明しています。
  3. ピンを照らし合わせる:コード内のすべてのピン番号を、実際の配線とボードのピン配置と比べます。PWMピンや避けるべきピンは「ピン配置」ツールで確認しましょう。
  4. 電気的な値を計算する:提案された抵抗値はLED抵抗計算ツールで確認します。5 V出力のセンサーを3.3 VのESP32やPicoにつなぐなら、間に分圧回路を入れます。
  5. シミュレーターで試す:実際の回路につなぐ前に、WokwiやTinkercadでコードを動かします。部品を危険にさらさずに論理の誤りを見つけられます。
  6. 少しずつテストする:プロジェクト全体を一度に書き込まないでください。まずセンサーを読んでシリアルモニタに表示するだけの小さなスケッチを試し、次にディスプレイを、最後にブザーやリレーを加えます。
  7. シリアルモニタで見守る:重要な箇所にSerial.println()を入れて、変数が期待どおりの値になっているか確認します。ボーレートがコードのSerial.begin()と同じかも確かめましょう。詳しくは「Arduinoのシリアルモニタ」の記事で。
  8. コードを説明してもらう:理解できない行があれば、そのたびに「この行は何をしますか?消したらどうなりますか?」と聞きます。説明できないコードは決して書き込まないでください。

よくある間違い1:存在しないライブラリ関数

AIの最もやっかいな間違いは、実際には存在しないのに、とてももっともらしい名前の関数を書くことです。たとえば標準のServoライブラリにはattach()、write()、writeMicroseconds()、read()、detach()がありますが、setSpeed()という関数はありません。サーボをゆっくり動かしたいと頼むと、モデルがこれを作り出すことがあります。関数が本当に存在しても、別のボード用の場合もあります。Serial.printf()はESP32では動きますが、Arduino Unoではコンパイルできません。古いバージョンの関数の場合もあります。2024年に公開されたESP32 Arduinoコアのバージョン3.xではledcSetup()とledcAttachPin()が削除されましたが、ほとんどのモデルはいまだにこれらを使ってコードを書きます。さらに、同じヘッダーファイルを使う別のライブラリもあります。LiquidCrystal_I2C.hという名前のあるライブラリではlcd.init()でディスプレイを初期化し、同じ名前の別のライブラリではlcd.begin()を使います。コンパイルの出力に「Multiple libraries were found」(複数のライブラリが見つかった)という警告が出たら、この混同を疑いましょう。

AIが書いたものコンパイラのメッセージまたは症状本当の直し方
UnoでのSerial.printf("%d", x)エラー:'class HardwareSerial' has no member named 'printf'; did you mean 'print'(printfというメンバーがない。printのことかという提案)Serial.print()で少しずつ出力するか、先にsnprintf()で文字列を作る
Unoでのsprintf(buf, "%.1f", t)コンパイルできるが、数値の代わりに?が表示されるAVRではprintf系の関数が小数に対応していないので、dtostrf(t, 4, 1, buf)を使う
servo.setSpeed(10)(存在しない関数)エラー:'class Servo' has no member named 'setSpeed'(setSpeedというメンバーがない)ループの中で角度を少しずつ変える
ESP32コア3.xでのledcSetup(0, 5000, 8)エラー:'ledcSetup' was not declared in this scope(宣言されていない)ledcAttach(pin, 周波数, 分解能)とledcWrite(pin, 値)を使う
DHTライブラリだけをインストールエラー:fatal error: Adafruit_Sensor.h: No such file or directory(ファイルまたはディレクトリがない)Adafruit Unified Sensorライブラリもインストールする
インストール済みのライブラリに合わないlcd.begin()エラー:no matching function for call to 'LiquidCrystal_I2C::begin()'(一致する関数がない)インストール済みのライブラリのスケッチ例を開き、その初期化命令(lcd.init()など)を使う
UnoでのanalogReadResolution(12)エラー:'analogReadResolution' was not declared in this scope(宣言されていない)UnoのADCは10ビット。この行を削除すれば、値は0〜1023になる

ESP32の古い関数のわな:ledcSetupではなくledcAttach

LEDの明るさやモーターの速度を調整するESP32のコードを頼むと、AIはたいていledcSetup(チャンネル, 周波数, 分解能)、ledcAttachPin(ピン, チャンネル)、ledcWrite(チャンネル, 値)の3つを書きます。このコードはコアのバージョン2.xでは動きます。しかしバージョン3.xではチャンネルが自動で割り当てられ、ledcAttach(pin, 周波数, 分解能)が一度にピンを準備し、ledcWrite(pin, 値)はチャンネルではなくピン番号を受け取るようになりました。インストールされているバージョンは、ボードマネージャのesp32パッケージの横で確認できます。次のコードはコンパイル時にバージョンを確認するので、どちらのコアでも動きます。

C++ (Arduino IDE)
1// ESP32 PWM: çekirdek 2.x ve 3.x ile uyumlu LED soldurma / LED fade for both core 2.x and 3.x
2#include <esp_arduino_version.h>   // ESP_ARDUINO_VERSION_MAJOR için / for ESP_ARDUINO_VERSION_MAJOR
3
4const int LED_PIN = 2;             // çoğu DevKit'te dahili LED / onboard LED on most DevKits
5const uint32_t FREKANS = 5000;     // PWM frekansı, Hz / PWM frequency, Hz
6const uint8_t COZUNURLUK = 8;      // 8 bit: 0-255 / 8-bit: 0-255
7
8#if ESP_ARDUINO_VERSION_MAJOR >= 3
9// Çekirdek 3.x: kanal otomatik seçilir, fonksiyonlar pin alır / Core 3.x: channel is automatic, functions take the pin
10void pwmBaslat() { ledcAttach(LED_PIN, FREKANS, COZUNURLUK); }
11void pwmYaz(uint32_t deger) { ledcWrite(LED_PIN, deger); }
12#else
13// Çekirdek 2.x: önce kanal kurulur, sonra pine bağlanır / Core 2.x: set up a channel, then attach the pin
14const uint8_t KANAL = 0;
15void pwmBaslat() { ledcSetup(KANAL, FREKANS, COZUNURLUK); ledcAttachPin(LED_PIN, KANAL); }
16void pwmYaz(uint32_t deger) { ledcWrite(KANAL, deger); }
17#endif
18
19void setup() {
20  Serial.begin(115200);
21  Serial.print("ESP32 Arduino cekirdegi / core: ");
22  Serial.println(ESP_ARDUINO_VERSION_MAJOR);
23  pwmBaslat();
24}
25
26void loop() {
27  // Tek iş yaptığı için burada delay() sorun değil / delay() is fine here: only one task
28  for (int d = 0; d <= 255; d++) { pwmYaz(d); delay(4); }   // yavaşça yan / fade in
29  for (int d = 255; d >= 0; d--) { pwmYaz(d); delay(4); }   // yavaşça sön / fade out
30}

ここでの教訓はESP32だけのものではありません。プロンプトにコアとライブラリのバージョンを書けば、モデルが正しい関数を選べる可能性が高まります。バージョンを伝えても古い関数を使う場合は、「ファイル」>「スケッチ例」からライブラリの公式のスケッチ例を1つ開き、「このスケッチ例の関数で書き直してください」と添えてプロンプトに貼り付けましょう。公式のスケッチ例は、インストール済みのバージョンと必ず合っています。PWMの仕組みが気になる場合は「PWMとは?」をご覧ください。

よくある間違い2:間違ったピンを選ぶ

コードがコンパイルできて書き込めても、ピンが間違っていれば、何も起きない回路や壊れたモジュールになります。コンパイラにとってピン番号はただの数字なので、この間違いは見つけられません。AIがよくするピンの間違いをボードごとにまとめました。

ボードAIのよくある間違いどうなるか正しい方法
Arduino UnoanalogWrite()にPWM非対応のピンを使う(例:D7)LEDが暗くならない。128未満では消え、128以上では全点灯PWMピン:3、5、6、9、10、11
Arduino UnoモジュールをD0やD1につなぐ書き込みに失敗したり、シリアルモニタが文字化けしたりするD0とD1はUSBシリアルの線。D2から使う
Arduino NanoA6とA7をデジタルピンとして使うdigitalRead()とdigitalWrite()が動かないA6とA7はアナログ入力専用
ESP32GPIO 6〜11を使うボードがクラッシュする、または再起動を繰り返すこれらのピンはフラッシュメモリにつながっている。GPIO 4、5、16〜19、21〜23などの安全なピンを選ぶ
ESP32GPIO 34〜39を出力として使うLEDが点灯しない。ボタンはプルアップ抵抗がないと不安定に読まれるこれらのピンは入力専用で、内部プルアップ抵抗がない
ESP32Wi-Fiがオンのとき、ADC2のピンでアナログ値を読むanalogRead()が失敗するか、意味のない値を返すアナログセンサーはADC1のピン(GPIO 32〜39)につなぐ
Raspberry Pi Pico W内蔵LEDにPin(25)を使うLEDが点灯しないPico WではLEDが無線チップにつながっている。Pin("LED")を使う
AIは電圧レベルを無視することがよくあります。ESP32とRaspberry Pi Picoのピンは3.3 Vで動作し、5 Vトレラントではありません。5 V出力のセンサーを直接つなぐと、ピンが永久に壊れることがあります。Arduino Unoでも、1本のピンから継続的に流す電流は20 mAまでにしてください(絶対最大は40 mA)。モーター、リレーのコイル、長いLEDテープは決してピンに直接つながず、間にトランジスタやドライバを入れます。ボードのピン配置は「Arduino Unoのピン配置」を見てください。

よくある間違い3:delay()によるフリーズ

ネット上のArduinoの例のほとんどがdelay()を使っているので、AIも当たり前のようにdelay()を使います。delay(1000)の実行中、プロセッサーはまる1秒間ほかに何もしません。ボタンを読まず、センサーも確認せず、ディスプレイも更新しません。1つのことしかしないコードなら問題ありません。しかし「LEDを点滅させ、ボタンを押したらブザーを鳴らす」のように2つのことを同時に頼むと、次のようなコードが出てくることがよくあります。

C++ (Arduino IDE)
1// Yapay zekanın sık ürettiği, kilitlenen kod / Blocking code that AI often produces
2const int BUTON_PIN = 2;    // buton: D2 ile GND arası / button between D2 and GND
3const int LED_PIN = 13;     // dahili LED / onboard LED
4const int BUZZER_PIN = 8;   // aktif buzzer / active buzzer
5
6void setup() {
7  pinMode(BUTON_PIN, INPUT_PULLUP);
8  pinMode(LED_PIN, OUTPUT);
9  pinMode(BUZZER_PIN, OUTPUT);
10}
11
12void loop() {
13  digitalWrite(LED_PIN, HIGH);
14  delay(1000);                          // 1 sn boyunca buton okunmaz / button is not read for 1 s
15  digitalWrite(LED_PIN, LOW);
16  delay(1000);                          // 1 sn daha kör bekleme / another blind second
17
18  if (digitalRead(BUTON_PIN) == LOW) {  // yalnızca tam bu anda basılıysa / only if pressed right now
19    digitalWrite(BUZZER_PIN, HIGH);
20    delay(200);
21    digitalWrite(BUZZER_PIN, LOW);
22  }
23}

このコードはエラーなくコンパイルできますが、ボタンを押してもほとんどの場合何も起きません。loop()の1周のうち約2秒は2つのdelay()の中で過ぎ、ボタンが読まれるのはその間の数マイクロ秒だけです。短く押すと、ほぼ必ずその瞬間を逃します。確実にブザーを鳴らすには、ボタンを2秒以上押し続ける必要があります。解決策は待つことではなく、時計を確認することです。millis()はボードの起動からのミリ秒を返し、それぞれの処理が自分の番が来たかを確認し、loop()は1秒間に何千回も回ります。

C++ (Arduino IDE)
1// millis() ile kilitlenmeyen sürüm / Non-blocking version with millis()
2const int BUTON_PIN = 2;    // buton: D2 ile GND arası / button between D2 and GND
3const int LED_PIN = 13;     // dahili LED / onboard LED
4const int BUZZER_PIN = 8;   // aktif buzzer / active buzzer
5
6const unsigned long LED_ARALIK = 1000;  // LED değişim aralığı, ms / LED toggle interval, ms
7const unsigned long BIP_SURE = 200;     // bip süresi, ms / beep length, ms
8const unsigned long SICRAMA = 30;       // debounce süresi, ms / debounce time, ms
9
10unsigned long ledZaman = 0;     // LED'in son değiştiği an / last LED toggle
11unsigned long bipZaman = 0;     // bipin başladığı an / beep start
12unsigned long butonZaman = 0;   // butonun son değiştiği an / last button change
13bool ledDurum = false;
14bool bipCaliyor = false;
15int oncekiButon = HIGH;         // önceki buton seviyesi / previous button level
16
17void setup() {
18  pinMode(BUTON_PIN, INPUT_PULLUP);
19  pinMode(LED_PIN, OUTPUT);
20  pinMode(BUZZER_PIN, OUTPUT);
21}
22
23void loop() {
24  unsigned long simdi = millis();
25
26  // 1) LED: zamanı geldiyse durum değiştir / toggle the LED when its time has come
27  if (simdi - ledZaman >= LED_ARALIK) {
28    ledZaman = simdi;
29    ledDurum = !ledDurum;
30    digitalWrite(LED_PIN, ledDurum ? HIGH : LOW);
31  }
32
33  // 2) Buton: yalnızca basıldığı anı yakala / catch only the moment of the press
34  int buton = digitalRead(BUTON_PIN);
35  if (buton != oncekiButon && simdi - butonZaman >= SICRAMA) {
36    butonZaman = simdi;
37    oncekiButon = buton;
38    if (buton == LOW && !bipCaliyor) {  // HIGH -> LOW: yeni basış / new press
39      bipCaliyor = true;
40      bipZaman = simdi;
41      digitalWrite(BUZZER_PIN, HIGH);
42    }
43  }
44
45  // 3) Buzzer: süre dolunca sustur / silence it when the time is up
46  if (bipCaliyor && simdi - bipZaman >= BIP_SURE) {
47    bipCaliyor = false;
48    digitalWrite(BUZZER_PIN, LOW);
49  }
50}

このバージョンでは、LED、ボタン、ブザーがお互いを待たずに動きます。simdi - ledZaman >= LED_ARALIKという引き算の形は、millis()が約49.7日ごとに0に戻っても正しい結果になります。一方、AIがときどき書くmillis() > targetTimeという比較は、この折り返しのときに壊れます。ボタンがHIGHからLOWに変わる瞬間をとらえることで、押し続けている間にブザーが何度も鳴るのを防ぎ、30 msの待ち時間で接点のチャタリングを取り除きます(チャタリング対策)。全体については「millis()とdelay()の違い」のガイドを、ボタンの配線については「Arduinoに押しボタンをつなぐ方法」を見てください。

プロンプトの最初に「delay()は使わず、すべての処理をmillis()でタイミング管理してください」と書いておけば、この問題にはまず出会いません。確認すべきフリーズのパターンがあと2つあります。LeonardoやMicroのようにUSBを直接持つボードでは、while (!Serial);という行があると、パソコンにつながっていないときにプログラムが永遠に待ち続けます。また、割り込みサービスルーチン(ISR)の中のdelay()は、割り込み中にmillis()が進まないため、プログラムが止まったままになることがあります。

コンパイルエラーを貼り付けて直してもらう

AIはコンパイルエラーの説明が本当に得意です。ただし、エラー全体と前後の状況を伝えることが条件です。「コードが動きません」とだけ書くと、モデルは推測するしかありません。次の順番で進めましょう。

  1. Arduino IDE 2でコンパイルエラーが出たら、右下に出る通知のエラーメッセージをコピーをクリックするか、出力パネルのテキストをすべて選んでコピーします。最後の行のexit status 1だけでは役に立ちません。本当の原因はその上のerror:の行にあります。
  2. プロンプトには、ボードとコアのバージョン、コード全体、エラーメッセージ全体、インストール済みのライブラリの名前とバージョンを、この順番で入れます。
  3. 修正を頼む前に、「まずエラーの原因を説明し、その後、変更が必要な行だけを示してください」と書きます。こうすればモデルがスケッチ全体を書き直して新しいエラーを加えることがなく、何がなぜ変わったのかも学べます。
  4. 提案された変更を反映して、もう一度コンパイルします。新しいエラーが出たら、また一番上のerror:の行を貼り付けます。エラーは1つずつ直しましょう。
  5. 2〜3回やり取りしても同じエラーが残る場合は、その流れを断ち切って、ライブラリの公式のスケッチ例をコンパイルします。スケッチ例もコンパイルできなければ、問題はコードではなく環境にあります。ボードの選び間違い、ライブラリの不足、同じ名前の2つのライブラリの衝突などです。

エラーがコンパイルではなく書き込みのときに出る場合(「avrdude: stk500_recv(): programmer is not responding」(書込装置が応答しない)や、ESP32の「Failed to connect to ESP32」(ESP32に接続できない)など)、コードを変えても意味がありません。ポート、ケーブル、ドライバ、ボードの選択を確認する必要があります。こうしたケースは「Arduinoに書き込めないとき」のガイドで手順を説明しています。書き込みエラーについてAIに聞くときも、メッセージ全体と使っているOSを伝えましょう。

Raspberry Pi PicoとMicroPythonのコードをAIに書いてもらうとき

MicroPythonのコードを頼むときも同じルールが当てはまりますが、ここではAIがプラットフォームを混同することもあります。Raspberry Piのコンピューター向けにRPi.GPIOやgpiozeroで書かれたコードはPicoでは動きません。PicoではMicroPythonのmachineモジュールを使います。CircuitPythonのboardやdigitalioモジュールもMicroPythonにはありません。そのため、プロンプトには「Raspberry Pi Pico W、MicroPython、Thonny」のようにはっきりした情報を書きましょう。次のコードはPicoとPico Wの両方で動き、待つ代わりにticks_ms()でタイミングを管理します。

MicroPython
1# Pico ve Pico W: bekletmeden LED + buton / Pico and Pico W: LED + button without blocking
2from machine import Pin
3import time
4
5led = Pin("LED", Pin.OUT)             # Pico W'da Pin(25) çalışmaz / Pin(25) does not work on Pico W
6buton = Pin(14, Pin.IN, Pin.PULL_UP)  # buton: GP14 ile GND arası / button between GP14 and GND
7
8ARALIK = 500                          # LED değişim aralığı, ms / LED toggle interval, ms
9SICRAMA = 30                          # debounce süresi, ms / debounce time, ms
10son = time.ticks_ms()                 # LED'in son değiştiği an / last LED toggle
11degisim = time.ticks_ms()             # butonun son değiştiği an / last button change
12onceki = 1                            # önceki buton seviyesi / previous button level
13sayac = 0
14
15while True:
16    simdi = time.ticks_ms()
17    if time.ticks_diff(simdi, son) >= ARALIK:      # taşmada da doğru / correct even on overflow
18        son = simdi
19        led.toggle()
20    deger = buton.value()
21    if deger != onceki and time.ticks_diff(simdi, degisim) >= SICRAMA:
22        degisim = simdi
23        onceki = deger
24        if deger == 0:                # basıldığı an / moment of the press
25            sayac += 1
26            print("Basma / press:", sayac)

Thonnyでコードを実行すると、内蔵LEDが0.5秒ごとに点滅し、ボタンを押すたびにシェルのウィンドウに増えていく数字が表示されます。time.ticks_diff()はカウンターが一周して戻っても正しい差を返します。一方、AIがよく書く単純なtime.ticks_ms() - sonという引き算は、長時間動くコードでは間違った結果になることがあります。Picoが初めての場合は「Raspberry Pi Picoとは?」から始めましょう。

商用電源:AIを信用しない

AIは、商用電源のランプ、コンセント、ヒーターをリレーで切り替えるコードを数秒で書き、配線も自信たっぷりに説明します。しかし商用電源は命を奪うことがあります(日本の商用電源は100V(50/60Hz)です)。接続の間違いやゆるんだ線は、感電や火災の原因になります。モデルは説明している配線を測ることも、回路を見ることもできず、結果に責任を負うこともできません。AIの指示だけを頼りに商用電源の接続をしないでください。18歳未満の場合は、必ず大人か電気に詳しい人と一緒に作業しましょう。

商用電源で動かすプロジェクトなら、まず低い電圧で試しましょう。ランプの代わりにLEDを、コンセントの代わりに12 VのLEDテープを使います。どうしても商用電源を切り替える必要がある場合、譲れないルールがあります。作業するときは回路のプラグを抜きます。リレーで切るのは中性線ではなく電圧側(L)です。リレーモジュールに書かれた電流と電圧の定格(ほとんどのモジュールで10 A 250 VAC)を超えないようにし、高電圧側は閉じた絶縁ケースに入れます。安いリレーモジュールは、低電圧側と高電圧側の間の距離が足りないことがよくあります。できれば、市販の認証済みスマートプラグやリレーボックスを選びましょう。リレーモジュールの配線は「リレーモジュールとは?」で詳しく説明しています。

学ぶことをやめずにAIを使う

AIにすべてのスケッチを書いてもらうと、初めてコードが動かなかった日に何をすればいいか分からなくなります。電子工作とプログラミングを学ぶことが目的なら、AIをコードを出す機械ではなく、辛抱強い先生として使いましょう。

  • まず自分で書く:自分でコードを書いてみてから、「間違いを指摘してください。ただし修正したコードは出さないでください」と頼んでAIに確認してもらいます。
  • 答えではなくヒントを頼む:行き詰まったら「次のステップのヒントだけください」と言います。
  • 1行ずつ説明してもらう:説明を聞いたら、同じ考え方を自分の言葉で説明してみます。説明できないところが、まだ学べていないところです。
  • コピーせずに入力する:コードを貼り付けずに手で入力すると、構文や関数名をずっと早く覚えられます。
  • 予想してから試す:値を変える前に何が起きるかを予想し(例:LED_ARALIKを200にしたら)、それから書き込んで確かめます。
  • 自分をテストする:学んだばかりのテーマについて5問出してもらうようAIに頼みます。基本の復習には「Arduinoプログラミングの基本」を使いましょう。
  • ルールを守る:学校の課題や科学コンテストでは、AIの使用に関するルールに従い、使った場合ははっきりそう書きましょう。

AIで試せる最初のプロジェクト

  • 温度表示:DHT11で測った値をI2C LCDに表示します。プロンプトにはLCDのアドレスとライブラリの作者を書きましょう。
  • 駐車センサー:HC-SR04で距離を測り、障害物が近づくほどブザーを速く鳴らします。タイミングはmillis()で管理するよう頼みましょう。
  • 常夜灯:LDRを使って、暗くなったらLEDを点灯します。しきい値はまずシリアルモニタで読み取り、プロンプトに数値で書きましょう。
  • Wi-FiでLEDを操作:ESP32で、スマホで開いたページからLEDを点灯・消灯します。プロンプトにはコアのバージョンを書きましょう。
  • 自分のアイデア:「Arduinoのプロジェクトアイデア」の一覧からプロジェクトを選び、このガイドのプロンプトのテンプレートでAIに説明してみましょう。

正しい情報を伝え、返ってきたコードをコンパイルし、ピンを確認し、少しずつテストし、理解できない行は決して書き込まない。これを守れば、AIはArduinoを学ぶうえで最も手早い助っ人になります。AIが書いたコードと比べられる信頼できる例を探しているなら、BlueGraysアプリには、ステップごとの回路図とテスト済みのコードがそろったLED、ボタン、DHT11、ESP32のPWM、Picoのプロジェクトがあります。

よくある質問

AIでArduinoのコードは書けますか?

はい。ChatGPT、Gemini、Claude、Copilotなどのアシスタントは、Arduino、ESP32、Raspberry Pi Picoの簡単なプロジェクトのほとんどで動くコードを作れます。ただし書き込む前に、コンパイルして、ピン、ライブラリ、電圧レベルを自分で確認してください。AIには回路が見えず、間違えることもあります。

Arduinoのコードを書くのに最適なAIは?

唯一の正解はありません。現在の大規模なモデルは、簡単なArduinoのコードではほぼ同じような結果を出します。差はたいていモデルではなくプロンプトから生まれます。ボード、ピンの接続、ライブラリ、期待する動作をはっきり書いたプロンプトなら、どのアシスタントを使ってもより良いコードが返ってきます。

ChatGPTが書いたArduinoのコードが動かないのはなぜ?

よくある原因は、存在しない関数や別のボード用の関数、別のバージョンのライブラリ向けに書かれたコード、間違ったピン、そしてすべてを止めてしまうdelay()です。まずコードをコンパイルしてください。エラーがあれば、ボードとバージョンの情報と一緒にメッセージ全体を貼り付けます。コンパイルできても動かない場合は、シリアルモニタに途中の値を表示して、問題の場所を見つけましょう。

Arduinoのコンパイルエラーの修正をAIに頼むには?

ボード名、コアとライブラリのバージョン、コード全体、出力パネルのエラーメッセージ全体を1つのメッセージで伝えます。「まず原因を説明し、その後、変わる行だけを示してください」と付け加えれば、正しい修正が得られ、エラーの原因も学べます。

商用電源のリレーの配線はAIを信用していい?

いいえ、AIだけを頼りにしてはいけません。コードはたいてい問題ありませんが、危険は配線にあります。AIには回路が見えず、指示が正しいことを保証できません。商用電源側の配線は、詳しい人と一緒に、プラグを抜いた状態で、電圧側を切り替え、閉じたケースに収めたリレー構成で行ってください。できれば市販の認証済みスマートプラグを使いましょう。

AIを使うとArduinoの学習に悪い?

理解せずにコードをコピーするなら、悪いと言えます。最初のエラーで何をすればいいか分からなくなります。まず自分で書いてAIに確認してもらい、1行ずつ説明してもらい、答えではなくヒントを頼むなら、学習のスピードが上がります。ルールはシンプルです。説明できない行は決して書き込まないことです。

全プロジェクトを見る
LEDの点滅
#1初級

LEDの点滅

電子工作の第一歩は、1個のLEDを点けたり消したりすることです。Arduinoで短い間隔で点灯と消灯を繰り返すと、LEDが素早く点滅します。ボードが光を制御する仕組みを最もシンプルな形で確かめ、これから取り組むプロジェクトの基礎を身につけます。

4.6(188)
1127
ボタンでLEDを点灯(押している間のみ)
#9初級

ボタンでLEDを点灯(押している間のみ)

呼び鈴のように、押している間は点灯し、離すと消灯します。Arduinoはボタンの状態を常に読み取り、押されている間はLEDを点灯させ、指を離した瞬間に消灯させます。このシンプルな回路で、ボードが外部からの操作を検知する仕組みを学べます。

4.8(113)
229
DHT11で温度と湿度を測定
#55中級

DHT11で温度と湿度を測定

部屋の温度は何度で、空気は湿っているでしょうか、それとも乾燥しているでしょうか?DHT11センサーが温度と湿度を測定し、Arduinoが2行のLCDディスプレイに値を表示して、数秒ごとに更新します。センサーに異常があればエラーメッセージが表示されます。自分だけの小さな気象観測装置を作る第一歩です。

4.7(47)
73
ESP32でLEDを点滅
#103初級

ESP32でLEDを点滅

ESP32のGPIO出力の基本を学びます。デジタルピンからLEDを点灯・消灯させて、点滅させます。Arduino UNOの定番のLED点滅プロジェクトのESP32版です。Arduino環境で使う基本的な点滅コマンドは同じですが、ESP32のピン配置と3.3 VのGPIO電圧レベルはArduino UNOとは異なります。

4.7(37)
99
Raspberry Pi Picoの内蔵LEDを点滅(PicoとPico W)
#147初級

Raspberry Pi Picoの内蔵LEDを点滅(PicoとPico W)

Raspberry Pi Picoシリーズの最初のプロジェクトです!ボード上の緑色LEDを点滅させて動作を確認する、定番の「Hello World」に相当する実験です。外付け部品は不要で、PicoとUSBケーブルだけで始められます。コードはMicroPython(Raspberry Pi Foundationが公式にサポートする言語)で書きます。Thonny IDEでmachine.Pinクラス、Pin.OUTモード、led.on()/off()メソッド、time.sleep()を学びます。シリアル(REPL)出力で、切り替わる様子をリアルタイムに確認できます。

5.0(1)
10
ESP32のPWMでLEDをフェード
#110初級

ESP32のPWMでLEDをフェード

LEDの明るさを0から最大へ、最大から0へと滑らかに変化させます。Arduinoと同じようにanalogWrite()でPWMを制御します。ESP32 Arduino Core 3.0+では同じ構文がそのまま使えます。ピンの定義とpinMode、analogWriteだけで実現できます。

4.8(36)
54
Raspberry Pi PicoのPWMでLEDをフェード(呼吸のような明滅)
#160初級

Raspberry Pi PicoのPWMでLEDをフェード(呼吸のような明滅)

LEDを単に点滅させるだけでなく、呼吸するように明滅させます!Raspberry Pi PicoのPWM(パルス幅変調)を使い、スリープ中のMacBookのランプのように、明るさをゆっくり上げてからゆっくり下げます。machine.PWMクラス、duty_u16()(0–65535の16ビットの明るさ)、PWM周波数(freq(1000)で1秒間に1000回オン・オフし、ちらつきを感じさせない)、range()による段階的なループ(増加と減少)、デジタルピンからのアナログのような出力を学びます。PWMはRGBの混色やモーターなどに使われる、組み込み開発の基本技術です。

0.0(0)
4
I2CでLCDディスプレイを使う
#32初級
プレミアム

I2CでLCDディスプレイを使う

Arduinoにディスプレイを接続し、最初のメッセージを表示します。2行のLCDディスプレイは数本の配線だけで接続できます。まず上の行にあいさつを表示し、次に下の行にもう1つのメッセージを表示します。その後、表示を消去して最初から繰り返します。温度や時刻、スコアを表示するプロジェクトは、すべてこのステップから始まります。

4.8(53)
70