【Blog】生成AIは制御設計もできる?ChatGPTでPLCの自動運転プログラムを作成
- 河野譲二

- 10月8日
- 読了時間: 8分
更新日:10月9日
ChatGPTやGeminiなど生成AIの進歩が日々話題となっていますが、私たちにとっても大きな変化をもたらしています。
そこで、今回はPLCのプログラムをChatGPTを使って行ってみたいと思います!

☆そもそもPLCとは??
まずPLCとは何か、こちらもChatGPTに聞いてみましょう! -----------------------------------------
PLC(ピー・エル・シー)は「プログラマブルロジックコントローラ」の略で、“工場のロボットや機械の頭脳” のようなものです。
🧠 たとえで説明すると…
工場の装置は、いろんなセンサーやボタン、モーターなどがつながっています。PLCは、それらの信号を見て「動け!」「止まれ!」「ライトをつけろ!」と命令を出すコンピュータです。
⚙️ たとえば…
たこ焼き機を例にすると――
ボタン(スイッチ)が押されると、
PLCが「スタートだ!」と判断して、
モーターに「回れ!」、ヒーターに「温めろ!」と指示を出します。
💡 ポイント
PLCはプログラムで動きを決めることができる。
人間が指示しなくても、自動で考えて動かせる。
だから工場では、たくさんの機械を同時に正確に動かすことができる。
-----------------------------------------
さすがChatGPT!わかりやすく説明です!
そしてこのPLCで使用するプログラムは、日本で主流となっているのは「ラダープログラム」というものです。C言語やPythonなどとは異なり、電気回路を基にしたプログラムで梯子のような形をしたものになります。
詳しくは下記の電気設計人さんのサイトを見た方がわかりやすいかと思いますので共有いたします。 https://denkisekkeijin.com/ladder/ladder_mean/
☆実際に生成AIでプログラミング!
ラダープログラムが主流であった日本にもST言語を活用する流れが到来しつつあります。ST言語はテキストベースのプログラムで高級言語に似ています。三菱電機製PLCでは以前よりSTでの記述が出来ていましたが、今年発売されたキーエンス製PLCのKV-Xでも使用できるようになりました!
現在、生成AIでラダープログラムの生成は難しいとされていますが、テキストベースのST言語であれば、生成AIの得意分野です。ということで簡単なデモを行いましたので、紹介させていただきます。
今回の仕様は、よくある自動運転の自己保持と運転時間や生産数、生産量の管理を行うプログラムをChatGPTに生成してもらいました!
私がChatGPT依頼した内容は・・・
-----------------------------------------------------------------
あなたはST言語の専門家です。私の要望に沿ってKV-Xで使用できるST言語を生成してください。なおキーエンスPLCのルールに則り記述してください。また、変数宣言は行わず、MRやR、DMといったデバイスを直接使用してください。
~仕様~・STARTボタン(R0)を押下で自動運転開始。自動運転は保持してください。・STOPボタン(R1)を押下で自動運転停止。
・自動運転中はシグナルタワーの緑(MR0)を点灯、停止中は赤(MR1)を点灯してください。・自動運転中は下記の処理を行ってください。
①運転時間を計測してください。単位は時(DM14):分(DM12):秒(DM10)で表示してください。秒が60までカウントすると分が1つカウントアップし、秒が0から再度カウントアップするといった要領で計測してください。
②自動運転中に生産完了ボタン(R2)が押されるたびに生産数(DM0)を1つカウントしてください。
③運転時間と生産数を計算し、1時間当たりの生産量をDM20に出力してください。④自動運転が停止と共に、時間・生産数・生産量をリセットしてください。
-----------------------------------------------------------------
すると下記のプログラムを30秒~1分ほどで作ってくれました!
----------------------------------------------------------------- (* ============================= *)
(* 自動運転ラッチ(START/STOP) *)
(* ============================= *)
IF R0 THEN (* STARTボタン押下で自動運転ON保持 *)
MR10 := 1; (* 自動運転ラッチ *)
END_IF;
IF R1 THEN (* STOPボタン押下で自動運転OFF *)
MR10 := 0; (* 自動運転ラッチ解除 *)
END_IF;
(* ============================= *)
(* シグナルタワー出力 *)
(* 自動中:緑ON(MR0) / 停止中:赤ON(MR1) *)
(* ============================= *)
MR0 := MR10; (* 緑灯:自動運転中に点灯 *)
MR1 := NOT MR10; (* 赤灯:停止中に点灯 *)
(* ============================= *)
(* 1秒クロック立上り検出(CR2001想定) *)
(* MR11: 前回状態保持 / MR12: 立上りパルス *)
(* ============================= *)
IF (CR2001 = 1) AND (MR11 = 0) THEN
MR12 := 1; (* 1秒立上りパルス *)
ELSE
MR12 := 0;
END_IF;
MR11 := CR2001; (* 前回状態更新 *)
(* ============================= *)
(* 生産完了ボタン 立上り検出(R2) *)
(* MR13: 前回状態保持 *)
(* ============================= *)
IF MR10 THEN (* 自動運転中のみカウント *)
IF (R2 = 1) AND (MR13 = 0) THEN
DM0 := DM0 + 1; (* 生産数インクリメント *)
END_IF;
END_IF;
MR13 := R2; (* 前回状態更新 *)
(* ============================= *)
(* 運転時間の加算(時:DM14 / 分:DM12 / 秒:DM10) *)
(* ============================= *)
IF (MR10 = 1) AND (MR12 = 1) THEN
DM10 := DM10 + 1; (* 秒++ *)
IF DM10 >= 60 THEN (* 60秒で繰上げ *)
DM10 := 0; (* 秒リセット *)
DM12 := DM12 + 1; (* 分++ *)
IF DM12 >= 60 THEN (* 60分で繰上げ *)
DM12 := 0; (* 分リセット *)
DM14 := DM14 + 1; (* 時++ *)
END_IF;
END_IF;
END_IF;
(* ============================= *)
(* 1時間当たりの生産量算出(DM20) *)
(* DM20 = (生産数 * 3600) / 経過秒 [整数] *)
(* 経過秒 = DM14*3600 + DM12*60 + DM10 *)
(* 参考:長時間運転では桁あふれ対策として32bit(DM.L)化を推奨 *)
(* ============================= *)
IF MR10 = 1 THEN
DM30 := DM14 * 3600; (* 作業用:時→秒 *)
DM32 := DM12 * 60; (* 作業用:分→秒 *)
DM34 := DM30 + DM32 + DM10; (* 経過秒(合算) *)
IF DM34 > 0 THEN
DM20 := (DM0 * 3600) / DM34; (* 整数演算。必要なら小数はREAL化 *)
ELSE
DM20 := 0;
END_IF;
END_IF;
(* ============================= *)
(* 停止時リセット(時間・生産数・生産量のクリア) *)
(* 仕様:自動運転が停止すると同時にリセット *)
(* ============================= *)
IF MR10 = 0 THEN
DM10 := 0; (* 秒 *)
DM12 := 0; (* 分 *)
DM14 := 0; (* 時 *)
DM0 := 0; (* 生産数 *)
DM20 := 0; (* 1時間当たり生産量 *)
(* 作業用レジスタも念のためクリア *)
DM30 := 0;
DM32 := 0;
DM34 := 0;
END_IF;
-----------------------------------------------------------------
このプログラムをKV-STUDIOに書き込みシュミレーションを行うと・・・
あれ?稼働時間と生産ペースが増えない!
ということでクレームをChatGPTにいれます(怒)笑
-----------------------------------------------------------------
自動運転の開始/停止、生産数のカウントは出来ていましたが、生産時間が0のまま変化がありませんでした。生産量に関しても同様です。プログラムを見直し、修正してください。
-----------------------------------------------------------------
それに対してChatGPTは・・・
-----------------------------------------------------------------
ご指摘どおり、原因は「1秒クロック」の参照先でした。
KVの特殊リレーは**CR2006=1sクロック(duty50%)*です(CR2001はシステム予約)ので、ここを正しく立上り検出するよう修正しています。合わせて、停止時のリセットは「自動運転ラッチの立下りエッジで1回だけ」実行、さらに生産量計算は内部で32bit(DM.L)を使って安全に演算するように直しました。参考:CR一覧でCR2006が1秒クロックと明記されています。
-----------------------------------------------------------------
原因究明を4秒で行い、プログラムを再生成してくれました!
そのプログラムがこちら↓↓↓
-----------------------------------------------------------------
(* ============================= *)
(* 自動運転ラッチ(START/STOP) *)
(* ============================= *)
IF R0 THEN (* STARTで自動運転ON保持 *)
MR10 := 1;
END_IF;
IF R1 THEN (* STOPで自動運転OFF *)
MR10 := 0;
END_IF;
(* ============================= *)
(* シグナルタワー出力 *)
(* 自動中:緑(MR0) / 停止中:赤(MR1) *)
(* ============================= *)
MR0 := MR10;
MR1 := NOT MR10;
(* ============================= *)
(* 1秒クロック立上り検出:CR2006=1sクロック *)
(* MR11: 前回状態保持 / MR12: 立上りパルス *)
(* ============================= *)
IF (CR2006 = 1) AND (MR11 = 0) THEN
MR12 := 1; (* 1秒立上りパルス *)
ELSE
MR12 := 0;
END_IF;
MR11 := CR2006; (* 前回状態更新 *)
(* ============================= *)
(* 生産完了ボタン 立上り検出(R2) *)
(* MR13: 前回状態保持 *)
(* ============================= *)
IF MR10 THEN (* 自動運転中のみカウント *)
IF (R2 = 1) AND (MR13 = 0) THEN
DM0 := DM0 + 1; (* 生産数++ *)
END_IF;
END_IF;
MR13 := R2; (* 前回状態更新 *)
(* ============================= *)
(* 運転時間の加算(時:DM14 / 分:DM12 / 秒:DM10) *)
(* ============================= *)
IF (MR10 = 1) AND (MR12 = 1) THEN
DM10 := DM10 + 1; (* 秒++ *)
IF DM10 >= 60 THEN (* 60秒で繰上げ *)
DM10 := 0; (* 秒リセット *)
DM12 := DM12 + 1; (* 分++ *)
IF DM12 >= 60 THEN (* 60分で繰上げ *)
DM12 := 0; (* 分リセット *)
DM14 := DM14 + 1; (* 時++ *)
END_IF;
END_IF;
END_IF;
(* ============================= *)
(* 1時間当たりの生産量(DM20) *)
(* 32bit中間演算で安全に計算 *)
(* 経過秒 = DM14*3600 + DM12*60 + DM10 *)
(* DM20 = (DM0 * 3600) / 経過秒 [整数] *)
(* ============================= *)
IF MR10 = 1 THEN
(* 経過秒を32bitで合成 -> DM106.L *)
DM100.L := DM14; (* 32bit化(時) *)
DM100.L := DM100.L * 3600; (* 時→秒 *)
DM102.L := DM12; (* 32bit化(分) *)
DM102.L := DM102.L * 60; (* 分→秒 *)
DM104.L := DM10; (* 32bit化(秒) *)
DM106.L := DM100.L + DM102.L; (* 合算1 *)
DM106.L := DM106.L + DM104.L; (* 経過秒 *)
IF DM106.L > 0 THEN
DM108.L := DM0; (* 32bit化(生産数) *)
DM108.L := DM108.L * 3600; (* 生産数×3600 *)
DM110.L := DM108.L / DM106.L; (* 1時間当たり生産量(32bit) *)
DM20 := DM110.L; (* 下位16bitをDM20へ格納 *)
ELSE
DM20 := 0;
END_IF;
END_IF;
(* ============================= *)
(* 停止時リセット:自動運転の立下りで1回だけクリア *)
(* MR14: 自動運転の前回状態保持 *)
(* ============================= *)
IF (MR14 = 1) AND (MR10 = 0) THEN
DM10 := 0; (* 秒 *)
DM12 := 0; (* 分 *)
DM14 := 0; (* 時 *)
DM0 := 0; (* 生産数 *)
DM20 := 0; (* 生産量(個/h) *)
(* 作業用32bitもクリア *)
DM100.L := 0;
DM102.L := 0;
DM104.L := 0;
DM106.L := 0;
DM108.L := 0;
DM110.L := 0;
END_IF;
MR14 := MR10; (* 自動運転の前回状態更新 *)
-----------------------------------------------------------------
さぁ、正確に仕様を満たすことができているか確認しましょう!
しっかり修正されていますね!次は稼働時間の繰り上げ処理ができているか確認します!
秒と分の確認だけですが、問題なく動作しています!(1時間は待てないので割愛)
といったように、言葉を書くことができれば簡単にプログラムが出来る時代です。数年後には制御設計の仕事の在り方も変わっていることでしょう。
新しい技術に怯えたり、年齢を言い訳に見てないふりをするのではなく、自分の仕事をより良いものに変えていく努力をしていきたいと思います!





コメント