🙆‍♀️

Gemini 2.5 Flash / Pro / Pro+Gem でST言語プログラムの出力比較

に公開

検証テーマ

Geminiのモデルを使ってST言語プログラムを作成する場合、どのモデルが適切か気になりました。そこで、共通のプロンプトを与えて出力されるコード・説明文を比較しました。対象は、Gemini 2.5 Flash, Gemini 2.5 Pro、そして OpenPLCのガイドラインを読み込ませたGem+Pro環境の3つです。

検証では、以下のプロンプトを使用しました。現場でよく使いそうなステートマシンコードの生成を試すことにしました。CODESYS特有のライブラリを活用したい場合などは、今回の結果と異なる可能性があるのでご注意ください。

Geminiへのプロンプト
ST言語でCASE文を使った簡単なステートマシンのサンプルコードを示してください。
メインの処理は、Main(PRG)というファイル名、ステートマシンのステートや各ステートで実行するメソッドは、StateMachine(FB)というファイルに定義してください。

Geminiのモデル

結果の説明の前に検証で使用したGeminiのモデルについて確認しておきましょう。詳しくは本家のサイトを確認してください。その他、詳しい方がまとめている記事も参考になります。

Gemini 2.5 Proは3月、Gemini 2.5 Flashは4月に発表されたモデルです。6月現在、2.5 ProはPreview状態です。Flashは処理が早く、Proはより複雑な問題に適用できます。Gemは、選択したモデルに加えてカスタム指示や知識を与えることができる機能です。GeminiのWeb操作画面から、Gemを表示 > Gemを作成を選択すると以下のようなGem作成画面が表示されます。

Gem設定画面
Gem作成画面

画面の説明通りにGemに名前を付けたり、カスタム指示を保存することができます。知識の追加では、ファイルやGoogleドライブから情報の追加が可能です。今回の検証では、OpenPLCのコーディングガイドラインなどを知識として与えています。

評価結果

生成されたコード・ドキュメントを元に、主観的に評価した結果を示します。やはり、Gemを使った方が良い結果が得られました。生成速度は、Flashの場合一瞬で回答が得られますが、その他の場合は、数秒から数十秒かかりました。

モデル 推奨用途 生成速度 コード品質 説明の深さ 全体評価*
Flash “とにかく速く雛形が欲しい” ★★★★★ ★★☆☆☆ ★★☆☆☆ 60 / 100
Pro “実用コードのたたき台が欲しい” ★★★☆☆ ★★★★☆ ★★★★☆ 80 / 100
Pro+Gem “設計レビュー込みで提案してほしい” ★★☆☆☆ ★★★★☆ ★★★★★ 85 / 100

*筆者主観の総合スコア。詳細は後述。

結果の詳細

それぞれのモデルの出力を以下に示します。

Flash

はい、ST言語でCASE文を使った簡単なステートマシンのサンプルコードを示します。
メインプログラム Main.PRG とファンクションブロック StateMachine.FB の2つのファイルで構成します。


ファイル: StateMachine.FB (ファンクションブロック)

このファイルには、ステートマシンを定義します。

//****************************************************************************************
// ファンクションブロック名: StateMachine
// 説明: CASE文を使用した簡単なステートマシン
//****************************************************************************************
FUNCTION_BLOCK StateMachine
VAR_INPUT
    xEnable : BOOL; // ステートマシンを有効にするトリガ
    xReset  : BOOL; // ステートマシンをリセットするトリガ
END_VAR
VAR_OUTPUT
    sCurrentState : STRING; // 現在のステート名
END_VAR
VAR
    iState : INT := 0; // 現在のステート番号
    iCounter : INT := 0; // 各ステートで実行されるカウンター
    TON_Delay : TON; // 遅延タイマー
END_VAR

//****************************************************************************************
// メソッド: Initialize
// 説明: ステートマシンを初期化します
//****************************************************************************************
METHOD Initialize : VOID
VAR_INPUT
END_VAR
    iState := 0;
    iCounter := 0;
    sCurrentState := 'IDLE';
    TON_Delay(IN:=FALSE, PT:=T#0S); // タイマーをリセット
END_METHOD

//****************************************************************************************
// メソッド: State0_Idle
// 説明: IDLEステートでの処理
//****************************************************************************************
METHOD State0_Idle : VOID
VAR_INPUT
END_VAR
    sCurrentState := 'IDLE';
    // 何もしない、または待機
END_METHOD

//****************************************************************************************
// メソッド: State1_ProcessingA
// 説明: 処理Aステートでの処理
//****************************************************************************************
METHOD State1_ProcessingA : VOID
VAR_INPUT
END_VAR
    sCurrentState := 'PROCESSING_A';
    iCounter := iCounter + 1; // カウンターをインクリメント
    // 例えば、ここで何らかの計算やデータ処理を行う
END_METHOD

//****************************************************************************************
// メソッド: State2_Delay
// 説明: 遅延ステートでの処理
//****************************************************************************************
METHOD State2_Delay : VOID
VAR_INPUT
END_VAR
    sCurrentState := 'DELAY';
    // タイマーを起動
    TON_Delay(IN:=TRUE, PT:=T#2S); // 2秒間遅延
    IF TON_Delay.Q THEN
        TON_Delay(IN:=FALSE); // タイマーをリセット
        iState := 3; // 次のステートへ遷移
    END_IF
END_METHOD

//****************************************************************************************
// メソッド: State3_ProcessingB
// 説明: 処理Bステートでの処理
//****************************************************************************************
METHOD State3_ProcessingB : VOID
VAR_INPUT
END_VAR
    sCurrentState := 'PROCESSING_B';
    iCounter := iCounter - 1; // カウンターをデクリメント
    // 例えば、ここで別の計算や出力処理を行う
END_METHOD

//****************************************************************************************
// メソッド: State4_Done
// 説明: 完了ステートでの処理
//****************************************************************************************
METHOD State4_Done : VOID
VAR_INPUT
END_VAR
    sCurrentState := 'DONE';
    // 全ての処理が完了したことを示す
    // 例えば、ここで完了フラグをセットするなど
END_METHOD


//****************************************************************************************
// メイン実行部 (FBの内部処理)
//****************************************************************************************
IF xReset THEN
    Initialize(); // リセットがTRUEの場合、初期化
ELSE
    IF xEnable THEN // xEnableがTRUEの場合のみステートマシンを動作
        CASE iState OF
            0: // IDLE
                State0_Idle();
                IF iCounter >= 10 THEN // 例: カウンターが10以上になったら次のステートへ
                    iState := 1;
                    iCounter := 0; // カウンターをリセット
                END_IF

            1: // PROCESSING_A
                State1_ProcessingA();
                IF iCounter >= 5 THEN // 例: カウンターが5以上になったら次のステートへ
                    iState := 2;
                    iCounter := 0; // カウンターをリセット
                END_IF

            2: // DELAY
                State2_Delay();
                // State2_Delayメソッド内で次のステートへの遷移を制御

            3: // PROCESSING_B
                State3_ProcessingB();
                IF iCounter <= -5 THEN // 例: カウンターが-5以下になったら次のステートへ
                    iState := 4;
                    iCounter := 0; // カウンターをリセット
                END_IF

            4: // DONE
                State4_Done();
                // 処理が完了したらIDLEに戻るか、特定の条件で停止
                // ここでは、一定時間後にIDLEに戻る例
                IF iCounter >= 3 THEN // 例: 完了ステートで3サイクル経過したらIDLEに戻る
                    iState := 0;
                    iCounter := 0;
                END_IF
                iCounter := iCounter + 1; // 完了ステートでの経過サイクルをカウント

            ELSE // 未定義のステート
                Initialize(); // 不明なステートの場合は初期化
        END_CASE
    END_IF
END_IF

ファイル: Main.PRG (メインプログラム)

このファイルは、StateMachine ファンクションブロックをインスタンス化し、制御します。

//****************************************************************************************
// プログラム名: Main
// 説明: StateMachineファンクションブロックのインスタンス化と制御
//****************************************************************************************
PROGRAM Main
VAR
    fbStateMachine : StateMachine; // StateMachineファンクションブロックのインスタンス
    bStartMachine : BOOL := FALSE; // ステートマシンを開始/停止するトリガ
    bResetMachine : BOOL := FALSE; // ステートマシンをリセットするトリガ
    sMachineState : STRING; // ステートマシンの現在のステート名
    // デバッグ用の変数
    iDebugCounter : INT;
END_VAR

//****************************************************************************************
// プログラム実行部
//****************************************************************************************

// ステートマシンを有効にするトリガ
// 例: PLCの入力やHMIからの信号など
// ここでは、シミュレーションのため一定間隔でON/OFFを切り替えるか、手動で制御することを想定
IF bStartMachine THEN
    fbStateMachine.xEnable := TRUE;
ELSE
    fbStateMachine.xEnable := FALSE;
END_IF

// ステートマシンをリセットするトリガ
// 例: エラー発生時や初期化時など
IF bResetMachine THEN
    fbStateMachine.xReset := TRUE;
ELSE
    fbStateMachine.xReset := FALSE;
END_IF

// StateMachineファンクションブロックの実行
fbStateMachine();

// 現在のステート名を取得 (デバッグ/表示用)
sMachineState := fbStateMachine.sCurrentState;

// StateMachineファンクションブロックの内部カウンターを監視 (デバッグ用)
iDebugCounter := fbStateMachine.iCounter;

// ここに他のPLCプログラムロジックを記述できます
// 例: ステートに応じて外部機器を制御する
// IF sMachineState = 'DONE' THEN
//     // 完了時の処理
//     // 例えば、出力フラグをセット
// END_IF

説明

  1. StateMachine.FB (ファンクションブロック)

    • 変数:
      • xEnable (VAR_INPUT): ステートマシンを有効にするためのブール入力。
      • xReset (VAR_INPUT): ステートマシンを初期状態にリセットするためのブール入力。
      • sCurrentState (VAR_OUTPUT): 現在のステート名を文字列で出力します。デバッグやHMI表示に便利です。
      • iState (VAR): 現在のステートを表す整数変数。CASE文のセレクタとして使用します。
      • iCounter (VAR): 各ステートでの処理の進行を示すためのカウンタ。
      • TON_Delay (VAR): 遅延処理のためのタイマー(TONはIEC 61131-3標準のタイマーファンクションブロック)。
    • メソッド:
      • Initialize: ステートマシンを初期状態に戻します。
      • State0_Idle, State1_ProcessingA, State2_Delay, State3_ProcessingB, State4_Done: 各ステートで実行される具体的な処理を記述するメソッドです。ステートごとに処理を分離することで、コードの可読性と保守性が向上します。
    • メイン実行部:
      • xResetTRUEの場合、Initialize()メソッドを呼び出してステートマシンをリセットします。
      • xEnableTRUEの場合のみ、CASE iState OF ... END_CASE構造に入り、iStateの値に応じて対応するメソッドを呼び出します。
      • 各ステートのメソッド内で、次のステートへの遷移条件を記述し、iStateの値を変更することでステート遷移を行います。
  2. Main.PRG (メインプログラム)

    • fbStateMachine : StateMachine; で、StateMachine ファンクションブロックのインスタンスを作成します。
    • bStartMachinebResetMachineは、StateMachine FBのxEnablexReset入力を制御するための変数です。これらはHMIのボタンや他のPLCロジックから制御されることを想定しています。
    • fbStateMachine(); を呼び出すことで、StateMachineファンクションブロックの内部ロジックが実行されます。
    • sMachineState := fbStateMachine.sCurrentState; で、現在のステート名を取得し、監視することができます。

このサンプルコードの利点

  • モジュール化: ステートマシンのロジックがStateMachine.FBにカプセル化されており、メインプログラムから独立して管理できます。
  • 可読性: CASE文と各ステートごとのメソッドにより、現在のステートと実行される処理が明確になります。
  • 拡張性: 新しいステートを追加する際に、既存のコードへの影響を最小限に抑えられます。
  • デバッグのしやすさ: sCurrentStateiStateの値を監視することで、ステートマシンの現在の状態を容易に把握できます。

このコードを参考に、実際のアプリケーションに合わせてステートの数や各ステートの処理内容を調整してください。

Pro

はい、承知いたしました。
ST言語でCASE文を使った簡単なステートマシンのサンプルコードを、ご指定のファイル構成で作成します。

この例では、開始信号で処理を開始し、3秒間のタイマー処理を行った後、完了状態になり、リセット信号で初期状態に戻る、というシンプルなステートマシンを実装します。


1. StateMachine (FB) - ステートマシンの定義

まず、ステート(状態)の定義と、ステートマシンのロジックを記述するファンクションブロック(FB)を作成します。

ファイル名: StateMachine.st

(* データ型(DUT)としてステートを列挙型で定義 *)
TYPE E_State :
(
	IDLE,		(* 初期/待機状態 *)
	RUNNING,	(* 実行中状態 *)
	DONE		(* 完了状態 *)
);
END_TYPE

(* ステートマシン本体のファンクションブロック *)
FUNCTION_BLOCK StateMachine
VAR_INPUT
	i_xStart : BOOL;		(* 開始トリガ *)
	i_xReset : BOOL;		(* リセットトリガ *)
END_VAR
VAR_OUTPUT
	o_xBusy : BOOL;			(* 実行中フラグ *)
	o_xDone : BOOL;			(* 完了フラグ *)
END_VAR
VAR
	eState : E_State := IDLE;	(* 現在のステートを保持する変数 *)
	fbRunTimer : TON;			(* 実行中状態用のオンディレイタイマー *)
END_VAR

// 毎サイクル、タイマーを呼び出します
fbRunTimer(IN:= , PT:= T#3S);

// CASE文で現在のステート(eState)に応じて処理を分岐
CASE eState OF
	E_State.IDLE:
		(* --- 待機状態 --- *)
		// 出力を初期化
		o_xBusy := FALSE;
		o_xDone := FALSE;
		
		// 開始信号(i_xStart)を受け取ったら、RUNNINGステートへ移行
		IF i_xStart THEN
			eState := E_State.RUNNING;
		END_IF
		
	E_State.RUNNING:
		(* --- 実行中状態 --- *)
		o_xBusy := TRUE;
		o_xDone := FALSE;
		
		// タイマーを起動
		fbRunTimer.IN := TRUE;
		
		// タイマーが3秒経過(fbRunTimer.QがTRUE)したら、DONEステートへ移行
		IF fbRunTimer.Q THEN
			fbRunTimer.IN := FALSE; // 次のサイクルのためにタイマー入力をリセット
			eState := E_State.DONE;
		END_IF
		
	E_State.DONE:
		(* --- 完了状態 --- *)
		o_xBusy := FALSE;
		o_xDone := TRUE;
		
		// リセット信号(i_xReset)を受け取ったら、IDLEステートへ移行
		IF i_xReset THEN
			eState := E_State.IDLE;
		END_IF
		
	ELSE
		// 想定外のステートになった場合、安全のためIDLEに戻す
		eState := E_State.IDLE;
		
END_CASE
END_FUNCTION_BLOCK

2. Main (PRG) - メイン処理

次に、上で定義したStateMachineファンクションブロックをインスタンス化(実体化)して呼び出すメインプログラムを作成します。

ファイル名: Main.st

PROGRAM Main
VAR
	// StateMachineファンクションブロックのインスタンスを生成
	fbSM : StateMachine;
	
	// FBに渡すための変数
	xStartSignal	: BOOL := FALSE;	(* この変数をTRUEにすると開始 *)
	xResetSignal	: BOOL := FALSE;	(* この変数をTRUEにするとリセット *)
	
	// FBから受け取るための変数
	xMachineIsBusy	: BOOL;
	xMachineIsDone	: BOOL;
END_VAR

// StateMachineのインスタンスを呼び出し
// 入力(i_*)と出力(o_*)をMainプログラム内の変数に接続
fbSM(
	i_xStart := xStartSignal, 
	i_xReset := xResetSignal, 
	o_xBusy => xMachineIsBusy, 
	o_xDone => xMachineIsDone
);

// --- 動作確認のための簡単な操作ロジック ---
// 完了したら開始信号をリセットする
IF xMachineIsDone THEN
	xStartSignal := FALSE;
END_IF

コードの解説 📝

  • E_State (ENUM): IDLE, RUNNING, DONE という状態名を数値ではなく分かりやすい名前で扱うために列挙型を定義しています。コードの可読性が大幅に向上します。
  • StateMachine (FUNCTION_BLOCK): ステートマシンのロジックをカプセル化した部品です。これにより、同じステートマシンをプログラムの他の場所で簡単に再利用できます。
  • eState (VAR): ファンクションブロック内の変数で、現在の状態を記憶します。この変数の値がCASE文によって評価されます。
  • CASE eState OF ...: ステートマシンの心臓部です。eState変数の値に応じて、実行する処理ブロックを切り替えます。
  • Main (PROGRAM): StateMachineのインスタンスfbSMを作成し、毎スキャンサイクルで呼び出します。デバッグ時にxStartSignalxResetSignalの値を強制的に変更することで、ステートの遷移を簡単にテストできます。
Pro+Gem

承知いたしました。シニアPLCエンジニアとして、CODESYSおよびST言語を用いたステートマシンの実装についてアドバイスします。

ご要望の通り、CASE文を使用したステートマシンのサンプルコードを、メイン処理(Main.PRG)とステートマシン本体(StateMachine.FB)に分割して作成します。これはソフトウェアの部品化と再利用性を高めるための基本的な設計パターンです。


サンプルコードの構成

このサンプルは、以下の3つのPOU (Program Organization Unit) から構成されます。

  1. E_State (DUT): ステートマシンの状態を定義する列挙型です。
  2. StateMachine (FB): CASE文を用いて状態遷移を管理する本体です。
  3. Main (PRG): StateMachineのインスタンスを生成し、実行するメインプログラムです。
MyProject
 ├── GVL (Global Variable List)
 │
 ├── E_State (DUT)
 ├── StateMachine (FB)
 └── Main (PRG)

1. 状態定義 (DUT: Data Unit Type)

まず、ステートマシンの状態を管理するための列挙型 (Enumeration)E_Stateという名前のDUTとして定義します。数値(マジックナンバー)を直接使う代わりに列挙型を用いることで、コードの可読性と保守性が飛躍的に向上します。これはPLCopenのコーディングガイドラインでも推奨される手法です。

ファイル名: E_State.dut

TYPE E_State :
(
    STATE_INIT,     // 0: 初期化状態
    STATE_IDLE,     // 1: 待機状態
    STATE_RUNNING,  // 2: 実行状態
    STATE_STOP,     // 3: 停止状態
    STATE_ERROR     // 4: エラー状態
);
END_TYPE

2. ステートマシン (FB: Function Block)

次に、ステートマシンのロジックを実装するファンクションブロックStateMachineを作成します。内部に状態を保持する変数 eCurrentState を持ち、CASE文で現在の状態に応じた処理と次の状態への遷移を記述します。

ファイル名: StateMachine.fb

FUNCTION_BLOCK StateMachine
VAR_INPUT
    xStart      : BOOL; // 実行開始トリガ
    xStop       : BOOL; // 停止トリガ
    xReset      : BOOL; // リセットトリガ
END_VAR
VAR_OUTPUT
    xRunning    : BOOL; // 実行中フラグ
    xError      : BOOL; // エラー発生フラグ
    eState      : E_State; // 現在の状態を出力
END_VAR
VAR
    eCurrentState : E_State := E_State.STATE_INIT; // 状態変数。初期値はINIT
    iCounter      : INT; // RUNNING状態での処理カウンタ
END_VAR

// 処理本体
CASE eCurrentState OF
    E_State.STATE_INIT:
        // 初期化処理
        xRunning := FALSE;
        xError := FALSE;
        iCounter := 0;
        eCurrentState := E_State.STATE_IDLE; // IDLE状態へ遷移

    E_State.STATE_IDLE:
        // 待機状態
        xRunning := FALSE;
        IF xStart THEN
            eCurrentState := E_State.STATE_RUNNING; // Start信号でRUNNING状態へ
        END_IF

    E_State.STATE_RUNNING:
        // 実行状態
        xRunning := TRUE;

        // 簡単な内部処理(例:カウンタ)
        iCounter := iCounter + 1;

        // 停止条件
        IF xStop THEN
            eCurrentState := E_State.STATE_STOP;
        END_IF

        // エラー条件(例:カウンタが上限を超えた)
        IF iCounter > 1000 THEN
            eCurrentState := E_State.STATE_ERROR;
        END_IF

    E_State.STATE_STOP:
        // 停止状態
        xRunning := FALSE;
        iCounter := 0; // カウンタリセット

        // リセットで初期状態に戻る
        IF xReset THEN
            eCurrentState := E_State.STATE_INIT;
        END_IF

    E_State.STATE_ERROR:
        // エラー状態
        xError := TRUE;
        xRunning := FALSE;

        // リセットで初期状態に戻る
        IF xReset THEN
            eCurrentState := E_State.STATE_INIT;
        END_IF

ELSE
    // 予期せぬ状態に陥った場合のフェールセーフ
    eCurrentState := E_State.STATE_ERROR;

END_CASE

// 現在の状態を出力変数に反映
eState := eCurrentState;

3. メイン処理 (PRG: Program)

最後に、MainプログラムでStateMachineファンクションブロックのインスタンスを生成し、周期的に呼び出します。

ファイル名: Main.prg

PROGRAM Main
VAR
    // ステートマシンのインスタンスを生成
    fbMachine   : StateMachine;

    // FBへの入力信号
    bStart      : BOOL;
    bStop       : BOOL;
    bReset      : BOOL;

    // FBからの出力状態の確認用
    bIsRunning  : BOOL;
    bHasError   : BOOL;
    eCurrentState: E_State;
END_VAR

// StateMachine FBのインスタンスを呼び出し
fbMachine(
    xStart := bStart, 
    xStop := bStop, 
    xReset := bReset
);

// FBからの出力をローカル変数に格納(モニタリング用)
bIsRunning := fbMachine.xRunning;
bHasError := fbMachine.xError;
eCurrentState := fbMachine.eState;

// --- 以下は動作シミュレーションのためのロジック例 ---
// 実際には、他のロジックやHMIからの入力で bStart 等を操作します。
// 例:5秒後に自動スタート
// IF T#5s < GVL.tCycleTime THEN
//     bStart := TRUE;
// END_IF

アドバイザーからのコメント

  • 状態遷移のトリガ:
    このサンプルでは、xStartTRUEである間、遷移条件が成立し続けます。実際のアプリケーションでは、信号の立ち上がりエッジ(R_TRIG)や立ち下がりエッジ(F_TRIG)を検出して、一度だけ状態遷移を発生させることが一般的です。これにより、意図しない再度の状態遷移を防ぎ、より安定したロジックを構築できます。

  • CASE文のELSE:
    [cite_start]CASE文にELSE句を追加することは、プログラムの堅牢性を高める上で非常に重要です [cite: 999, 1000, 1001]。予期せぬ状態(メモリ破損など)に陥った場合に、安全な状態(例えばERROR状態)に強制的に移行させるフェールセーフの役割を果たします。

  • PLCopenコーディングガイドライン:
    今回提示したコードは、以下のPLCopenコーディングガイドラインの考え方を反映しています。

    • [cite_start]命名規則: 変数名や型名にアッパーキャメルケースやローワーキャメルケースを使用(Rule N4 [cite: 745])。
    • 可読性: 状態を列挙型で定義し、コードの意図を明確化。
    • [cite_start]構造化: 処理を機能単位(FB)に分割し、再利用性とテスト容易性を向上(Rule CP5 [cite: 825])。

このサンプルが、ST言語による高品質な制御ソフトウェア開発の一助となれば幸いです。ご不明な点があれば、いつでもご質問ください。

各モデルの特徴と評価

Gemini 2.5 Flash

長所

  • レスポンス最速。
  • 指示通り各ステートに対応してMethodを定義してくれている。

短所

  • CASE文が数値で分岐する記述になっていて可読性が悪い。
  • Method の戻り値が VOID と明示されているため、CODESYS ではコンパイル エラーになる。戻り値を書かないか、BOOLなど適当な型を設定する必要がある。
  • TON_Delay の初期化や iCounter のロジックに矛盾があり、実行すると意図せず無限ループの恐れ。
  • 説明文書が冗長。

総評: “動かしながら整える” 前提なら可。ただし 手直しは必須。

Gemini 2.5 Pro

長所

  • E_State 列挙型を導入し、マジックナンバー排除してくれている。
  • CASE 内が 3 ステートのみで 最小限・シンプル。
  • コードと解説がほぼ 1:1 で対応し、学習教材として分かりやすい。

短所

  • ステートに対応するMethod作成を指示したが省略されている。
  • 説明量は Flash より増えたが、設計意図やベストプラクティスまでは踏み込んでいない。

総評: 実装の土台には最適。細部を詰められるエンジニア向け。

Gemini 2.5 Pro + Gem

長所

  • サンプルコードのファイル構成から説明されており、わかりやすい。
  • PLCopen ガイドライン引用で設計根拠を明示してくれている。
  • ELSE 句によるフェールセーフ、入力信号をエッジ検出にすべきといった 改善アドバイス付き。
  • コードは Pro と同等の品質で、STATE_ERROR など 実運用を見据えた拡張ポイントが増えている。

短所

  • Gem インタラクション分のレイテンシー増大(=レスポンス最遅)。
  • 生成コード自体は Pro と大差ないため、「速度<解説」のケースでのみ優位。

総評: レビュー・ドキュメント作成まで自動化したい場面で威力を発揮。

どのモデルを選ぶべきか?

利用シーン 最適モデル 理由
アイデアスケッチ/試作を秒で回したい Flash とにかく早い。多少の構文ミスは自分で修正前提。
評価用 PLC コードを短時間で整えたい Pro バランス型。列挙型や簡潔な設計で保守しやすい。
社内レビュー資料や学習教材を一括生成 Pro+Gem コード+設計解説+ベストプラクティスまで自動生成。

まとめ

  • 処理時間が気にならなければ Pro+Gem を使っておくのが良さそう。
  • いずれも 「完全コンパイル保証」ではない ため、最終的には自分のIDE上にコピペしてビルドチェックは必須。
  • 今回の検証は ST コード 1例題のみ。大型プロジェクトや複数ファイル生成では差がさらに拡大する可能性があるため、用途に応じて追加ベンチマークを行う方が良い。

今後の課題

  • Claude4やChatGPT4.5など他のモデルとの比較
  • プログラムの品質を高める最適なGem設定の探索

Discussion