うごくものをつくる

個人的な学習ノート

雑記

ChatGPTにマイコン開発させてみたらまさかの結果に……

今流行りのチャットで対話可能なAI、ChatGPT。

僕はAI技術のことはよく知らないのでChatGPTのことは何も解説できないけど、かなり自然な言語で質問に答えてくれるとか、こちらが指示した通りに動くコードを生成してくれるとか、でも間違いやデタラメも結構あったりとか……。
百聞は一見にしかずということで、試しに使ってみたよ。

なにか間違いがあっても気づけるよう、何度も使ったことのあるマイコンのESP32を題材にしてやってみる。

おお!ちゃんと答えてくれてる!内容も正しい。
まあ項目7の回答が許されるならもう全部まとめてそれでええやろ感はあるけども……。

それではいよいよ、コードの自動生成の実力を試してみよう。

これも正解!まあ、いろんな本の一番最初に載っているような基礎基本のLチカ、ましてやArduinoフレームワークでの記述だから、これくらいはできてくれないと困るけど…。

でも、ただコードを出してくるだけじゃなくちゃんと「このプログラムはLEDをGPIO2に繋いでる時のものだよ」と伝えてくれるのは親切で良い。

LチカだけでなくADCやPWMだって使える。

無事にADC機能、PWM機能も使えました。
このへんからちょっと感動というか、最近のAIってすげーなという気持ちになってきた反面、もうちょっとボロを出してくれよと思い、いじわるを言ってみることにした。

上のコードを見て問題点に気づきましたか?delay関数による待ち時間の間は他に何の処理もできないので、電圧の変化を取得することができずただ固まっているだけの時間ができてしまう。LEDを点滅させるだけならいいんだけど、ADCなどの他の制御処理も行う場合、ChatGPT君が作ったように合計2秒もdelayで待ち時間を作っちゃうのはまずい。

というわけで、こういうリクエストを出してみる。

うん、そうだね。

LED点滅の部分をごっそり削除してくれれば、点滅動作のためのdelay関数も消えるので処理の待ち時間は発生せず、ADCで電圧の変化をリアルタイムに取得できる……

ってなんでやねん!

確かにそうだけども!そんないさぎよく機能削除しないで!

(こちらの意図を読み取って要求に応えられるコードに書き換えられるという意味では、予想外の方向性だったけどこれはこれでめっちゃすごい、とAIにあんまり詳しくない僕は思う。)

ちょっと軌道修正。

Lチカ部分を復活させてくれた。待ち時間が長くて嫌だというこちらの意図を汲み取って、delay関数で1秒のウェイトを入れていたところを、各500ミリ秒に待ち時間を減らすことで、トータルの待ち時間を2秒から1秒に短縮してくれてはいる。

ただ、これでも結局1秒処理を止めちゃってるので、”リアルタイム”ではないんだよね……

このままだと堂々巡りになりそうなので、ちょっと助け舟というか、誘導尋問的な質問をしてみる。

※ちょっと文章が長くてスクリーンショットだと文字が潰れてるかもしれないので、ここだけは文字を下に直接コピペした。

僕:これではLEDを点滅のために入れられたdelay関数によって、やはり1秒間の待ち時間ができてしまい、duty比をリアルタイムに変更できません。delay関数を使わず、LEDを1秒おきに点滅させつつ、duty比のリアルタイム応答も両立させてください。

ChatGPT:はい、LEDを1秒おきに点滅させながらもduty比をリアルタイムに変更するには以下のようにタイマーイベントを利用することができます:

#include <Arduino.h>
#define LED 2
#define ADC_PIN 3
#define PWM_PIN 4

hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR onTimer() {
  portENTER_CRITICAL_ISR(&timerMux);
  digitalWrite(LED, digitalRead(LED) ^ 1);
  int val = analogRead(ADC_PIN);
  int duty = map(val, 0, 4095, 0, 1023);
  analogWrite(PWM_PIN, duty);
  portEXIT_CRITICAL_ISR(&timerMux);
}

void setup() {
  pinMode(LED, OUTPUT);
  pinMode(PWM_PIN, OUTPUT);
  timer = timerBegin(0, 80, true);
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmWrite(timer, 1000000, true);
  timerAlarmEnable(timer);
}

void loop() {
  // 空のループ
}

おお!こちらがdelay関数を使わないようにという指示を出していたとはいえ、具体的にどういうふうにしろとは言っていないのに、自発的に「delayを使わずリアルタイム性を損ねない処理」として、タイマー割り込み機能でのLED点滅にしてくれたぞ!

これでdelay関数は使わなくても、LEDの点灯・消灯を切り替える処理が1秒に1回呼び出されるので、常にADCでピンに入力される電圧の変化をリアルタイムに捉えつつ、LEDを点滅させることができる。

いやー、最近のAIはすごいなぁ…………ん?

いやタイマー割り込み関数内にADC入れとるやないかーーーい!!!!

これじゃあ結局1秒に1回タイマー割り込み関数が呼ばれたときしか電圧値を取得しないから、電圧変化をリアルタイムに反映させられないじゃん!

正しくは、上のコードの12~14行目をloop()内に移動させると良いですね。

というわけで、ChatGPTにマイコン開発のコードを作成させると、一見それっぽく見えるけど色々となんかおかしい結果を返してくるよ、という話でした。

とはいえAIの精度は今後もどんどん上がっていくだろうからいずれはもっと正確で完璧なコードを返してくるということは十分考えられるし、実は現時点でも間違いのないコードを返してくれるということもあるのかもしれない。(※ChatGPTに同じ質問を何回か問いかけると、そのたびにちょっと返事が変わるということがあるらしいので。)

今(※2023年2月)の時点では、なんにも勉強しなくてもこれでバリバリハードウェア開発!マイコン制御は思いのまま!って感じじゃないけど、だからといって全く使いものにならないかというとそういうわけでもないと思う。

ある程度マイコン制御プログラムの書き方を学んで、おかしなところは多少修正できるようになった状態で、「この機能使い方わからないんだけどどうするんだろう……」みたいな場合のサンプルコード提供者としては使えるのかもしれない。

Google検索で普通にサンプルコード探すのとどちらが良いかと言われると微妙だけど……

おまけ

お気づきだろうか、先程までのコードに致命的な欠陥があることを……

以下はESP32の開発元、Espressifによるデータシートからの引用である……

そう、GPIO3ピンにはADC機能は付与されていないのである……

そんなわけで、今までのコードはADC部分が動きません。ADCを使いたいならGPIO3ではなく、ADC機能のある別のピン番号を選びましょう。

まあGPIO3でADCをやろうとしたのはAIが自発的にそうしたのではなく、こちらからのリクエストである「GPIO3でADCで電圧取得せよ」をまともにとらえた結果なんだけど、できればAIには「データシートによるとそのピンでADCは使えないから別のピン番号に訂正したよ」くらいのことはやってほしかった……

AIの生成したコードに間違いがないかを確認するためにコンパイルしてみても、GPIO3でADC機能を使おうとしている程度ではプログラミング上の誤りではないので、何のエラーも出ずにビルドできちゃう。

で、いざマイコンに書き込んだら全然うまくいかない……なんてことになり、どこがおかしいのか頭を抱えてしまうということもあるかもしれない。

電子工作するときはちゃんとデータシートを見て、最低限の知識を覚えてからAIを活用しようね、という教訓(?)で、この記事を締める。

(個人的には、何の勉強もしなくてもバリバリハードウェア開発!の世界観もそれはそれで面白そうなので、AIの発展には期待している)

おわり

返信する

メールアドレスが公開されることはありません。 が付いている欄は必須項目です