PLC上で様々な制御上のアクティビティを定義するフレームワークです。FB_Executorと呼ばれる実行エンジンによってInterfaceFutureインターフェースを実装したFutureという単位のオブジェクトを実行します。
| メソッド | 説明 | 終了条件 |
|---|---|---|
| init() | オブジェクト内部の変数を初期化します。 | init()の戻り値がTRUEとなる |
| execute() | 実際に処理を定義します。 | execute()の戻り値がTRUEとなる |
| quit() | 処理後の処理を定義します。 | quit()の戻り値がTRUEとなる |
FB_ExecutorとFutureオブジェクトが組み合わせたものを「ジョブ」と呼びます。ジョブそのものは特定のアクチュエータに対する特定の動作モード毎に定義しますが、これら複数のジョブを組み合わせて動作させるための「コンテナ」という形式のFutureオブジェクトもあります。
コンテナには、組み合わせたジョブを実行させる方法の違いによる4種類が用意されています。
| コンテナ名 | 説明 |
|---|---|
| FB_BatchJobContainer | あらかじめ登録したジョブを順次実行するコンテナです。 |
| FB_ParallelJobContainer | あらかじめ登録したジョブを同時並列で実行するコンテナです。 |
| FB_QueueJobContainer | 順次実行するコンテナですが、実行中も随時ジョブを登録することができます。 |
| FB_ParallelQueueJobContainer | 同時並列で実行するコンテナですが、実行中も随時ジョブを登録することができます。 |
このコンテナを用いることで、複数のジョブを順次実行、または、並列実行させることができます。また、コンテナには、子コンテナを含む事もでき、階層状の複雑なジョブを構成することができます。
-
以下のTwinCATプロジェクトをGithubリポジトリからクローンしてください。
-
TwinCAT XAEでプロジェクトを開き、ライブラリ作成手順に従ってライブラリファイル
JobManagement.libraryを保存してください。 -
こちらの手順に従い目的のTwinCATのPLCプロジェクトに保存したライブラリをインストール・追加します。
-
まず、Futureファンクションブロックを定義します。
InterfaceFutureを実装すると全てのメソッドを定義する必要がありますが、あらかじめ最低限のロジックが実装されたFB_AbstructFuture抽象クラスを継承して定義する方が楽です。 -
作成したファンクションブロックに
{attribute `enable_dynamic_creation`}を追加します。{attribute 'enable_dynamic_creation'} FUNCTION_BLOCK FB_TaskMoveToPosition EXTENDS FB_AbstructFuture VAR :
-
ファンクションブロックのメンバ変数を定義します。
{attribute 'enable_dynamic_creation'} FUNCTION_BLOCK FB_TaskMoveToPosition EXTENDS FB_AbstructFuture VAR _axis : AXIS_REF; _target_position : MC_REAL; _velocity : MC_REAL; _acceralation : MC_REAL; _deceralation : MC_REAL; _jark : MC_REAL; _buffer_mode : MC_BufferMode; _options : ST_MoveOptions; _mc_move_abs : MC_MoveAbsolute; _mc_reset : MC_Reset; END_VAR
-
入出力変数や独自パラメータを受け渡すメソッドやプロパティを追加します。入出力変数は、REFERENCEにより参照渡しする必要があります。
METHOD set_parameter : BOOL VAR_INPUT axis : REFERENCE TO AXIS_REF; target_position : MC_REAL; velocity : MC_REAL; acceralation : MC_REAL; deceralation : MC_REAL; jark : MC_REAL; END_VAR _axis REF= axis; _target_position := target_position; _velocity := velocity; _acceralation := acceralation; _deceralation := deceralation; _jark := jark; -
init()とexecute()メソッドを定義します。MethodをAddし、Name欄の選択肢にはオーバライド可能なメソッドが一覧されますので、実装したい任意のメソッドを選びます。各メソッドの完了時はいずれもBOOL型の戻り値をTRUEにしてください。
: IF <終了条件> THEN execute := TRUE ELSE execute := FALSE END_IF
例) init() 使用する変数の初期化等を行う
METHOD init : BOOL VAR END_VAR _mc_move_abs.Execute := FALSE; _mc_reset.Execute := FALSE; init := TRUE;例) execute() 実際の制御を定義
METHOD execute : BOOL VAR_INST // メソッド内だけで使用できる state : UDINT END_VAR CASE _state OF 0: _mc_move_abs.Position := _target_position_; _mc_move_abs.Velocity := _velocity_; _mc_move_abs.BufferMode := _buffer_mode; _mc_move_abs.Execute := TRUE; IF _mc_move_abs.Active THEN _mc_move_abs.Execute := FALSE; state := 1; ELSIF _mc_move_abs.CommandAborted OR _mc_move_abs.Error THEN _error_id := _mc_move_abs.ErrorID; // _error_id はFB_AbstructFuture で定義されている。 execute := TRUE; // エラー中断時は_error_idを0以外の値にしてexecute = TRUEを返す。 END_IF 1: IF _mc_move_abs.Done THEN _mc_move_abs.Execute := FALSE; _error_id := 0; execute := TRUE; // 正常終了時は_error_idを0にしてexecute = TRUEを返す。 ELSIF _mc_move_abs.CommandAborted OR _mc_move_abs.Error THEN _error_id := _mc_move_abs.ErrorID; execute := TRUE; // エラー中断時は_error_idを0以外の値にしてexecute = TRUEを返す。 END_IF END_CASE _mc_move_abs(); // call MC_MoveAbsolute every cycle _mc_reset(); // call MC_Reset every cycle
他にも必要に応じて API に示された他ののメソッドを定義してください。上記では abort() の定義例が示されていませんが、FB_Executorは、_error_id が0以外の値でinit(), execute(), quit()が終了すると、自動的に abort() を実行しますので、_error_id の値に応じたエラー発生時の処理を定義してください。
コンテナオブジェクト、またはFB_executorへFutureを登録する方法は次の二つがあります。
- あらかじめFutureインスタンス変数を宣言して、
add_futureで追加する方法 - インスタンスを動的に生成してくれるファクトリファンクションブロックを使って、
create_futureを使った動的なインスタンス生成方法
ここでは後者のファクトリファンクションブロックを使ってインスタンス生成する場合に使うファクトリファンクションブロックの作り方を説明します。
まず、InterfaceTaskCreator を実装するファンクションブロックを作成します。生成したいインスタンスのファンクションブロック名にCreatorを付けた名前にすると良いでしょう。
このファンクションブロックにもメンバ変数、および、set_parameterのようなアクセッサを用意します。
FUNCTION_BLOCK FB_TaskMoveToPositionCreator IMPLEMENTS InterfaceTaskCreator
:create_future メソッドを定義します。
METHOD create_future : InterfaceFuture
VAR_INPUT
future_name :STRING;
END_VAR
VAR
_p_future : POINTER TO FB_TaskMoveToPosition; // Futureファンクションブロック名を指定
END_VAR
_p_future := __NEW(FB_TaskMoveToPosition); // Futureファンクションブロック名を指定
_p_future^.future_name := future_name;
// ここから インスタンス独自の設定(パラメータ設定等)を定義
_p_future^.set_parameter(
axis := _axis;
target_position := _target_position;
velocity := _velocity;
acceralation := _acceralation;
deceralation := _deceralation;
jark := _jark;
);
// ここまで
create_future := _p_future^;destroy_future メソッドを定義します。_p_future のポインタ型をFutureファクションブロック型に変更するだけで、その他はそのままコピーして使ってください。
METHOD destroy_future : InterfaceFuture
VAR_INPUT
future : InterfaceFuture;
END_VAR
VAR
_p_future : POINTER TO FutureCounterBlink; // ここだけFutureファンクションブロック名に変える。
END_VAR
IF __QUERYPOINTER(future, _p_future) THEN
__DELETE(_p_future);
IF _p_future = 0 THEN
destroy_future := 0;
END_IF
END_IF
メインプログラムにおけるジョブの生成方法について説明します。まずメインジョブとなるFB_executorのインスタンスを作成します。その下にFB_BatchJobContainerを生成し、そこへ、これまで作成したFutureを使って複数の位置への位置決めを順次行うジョブを生成する例を示します。
PROGRAM MAIN
VAR
main_job : FB_Executor;
move_pos_creater : FB_TaskMoveToPositionCreator;
Vel : UDINT := 400;
Acc : UDINT := 4000;
Dcc : UDINT := 4000;
Jerk : UDINT := 20000;
axis : AXIS_REF;
state : UDINT;
bStart : BOOL; // シーケンススタート
bStop : BOOL; // 中断ボタン
bReset : BOOL; // ジョブのオールクリア
bResume : BOOL; // 再開ボタン
END_VAR
CASE state OF
0:
IF bStart THEN
state := 1;
END_IF
1: // Job creating
main_job.create_container(ContainerType.BATCH, 'MAIN JOB');
// Move Postion1
move_pos_creater.set_parameter(
axis := axis;
target_position := 320.14;
velocity := vel;
acceralation := Acc;
deceralation := Dcc;
jark := Jark;
);
main_job.children.create_future(move_pos_creater, 'MOVE TO POSITION 1');
// Move Postion2
move_pos_creater.set_parameter(
axis := axis;
target_position := 450.00;
velocity := vel;
acceralation := Acc;
deceralation := Dcc;
jark := Jark;
);
main_job.children.create_future(move_pos_creater, 'MOVE TO POSITION 2');
// Move to home
move_pos_creater.set_parameter(
axis := axis;
target_position := 0.00;
velocity := vel;
acceralation := Acc;
deceralation := Dcc;
jark := Jark;
);
main_job.children.create_future(move_pos_creater, 'MOVE TO HOME');
state := 2;
2: // initialization
IF main_job.init() THEN
state := 3;
END_IF
3: // executing
// execute()で実行しつつ、戻り値TRUEを監視。
IF main_job.execute() AND fbJob.nErrorID = 0 THEN
state := 0; // エラー無しにTRUEが戻ると終了。
END_IF
// 初期化が完了し、start()で実行
IF main_job.current_state = jobmgmt.E_FutureExecutionState.wait_for_process AND fbJob.ready THEN
main_job.start();
END_IF
// 一時停止する
IF bStop THEN
main_job.abort();
END_IF
// 中止、オールクリア
IF bReset THEN
main_job.reset();
state := 0;
END_IF
// 再開
IF main_job.current_state = jobmgmt.E_FutureExecutionState.abort AND bResume THEN
main_job.start();
END_IFFB_Executorインスタンスのメソッド create_containerにより次の引数を指定してコンテナを生成します。
| 引数 | 型 | 説明 |
|---|---|---|
| container_type | ContainerType | 生成するコンテナ型に対応したEnumの列挙子を指定します。 |
| name | STRING | コンテナのfuture名を設定します。 |
列挙しに設定可能な値は次の通りです。
| ContainerType | 生成されるコンテナ型 |
|---|---|
| BATCH | FB_BatchJobContainer |
| PARALLEL | FB_ParallelJobContainer |
| QUEUE | FB_QueueJobContainer |
| PARALLEL_QUEUE | FB_ParallelQueueJobContainer |
生成したコンテナオブジェクトへは、children プロパティを通じてアクセスする事ができます。
main_job.create_container(ContainerType.BATCH, 'MAIN JOB');
main_job.children.create_future(...);ジョブ生成方法は2とおりあります。まず、変数宣言によって明示的に作成したInterfaceFutureの実装オブジェクトを直接futureプロパティにセットする方法です。動作パターン毎に個別のインスタンスを作成する必要があります。
VAR
move_pos1 : FB_TaskMoveToPosition; // pos1へ移動するための位置決めインスタンス
move_pos2 : FB_TaskMoveToPosition; // pos2へ移動するための位置決めインスタンス
move_home : FB_TaskMoveToPosition; // homeへ移動するための位置決めインスタンス
main_job : FB_Executor;
parameter_set :BOOL;
END_VAR
move_pos1.set_parameter(
axis := axis;
target_position := 320.14;
velocity := vel;
acceralation := Acc;
deceralation := Dcc;
jark := Jark;
);
move_pos1.future_name := 'MOVE TO POSITION 1';
move_pos2.set_parameter(
axis := axis;
target_position := 450.00;
velocity := vel;
acceralation := Acc;
deceralation := Dcc;
jark := Jark;
);
move_pos2.future_name := 'MOVE TO POSITION 2';
move_home.set_parameter(
axis := axis;
target_position := 0;
velocity := vel;
acceralation := Acc;
deceralation := Dcc;
jark := Jark;
);
move_home.future_name := 'MOVE TO HOME';
main_job.create_container(ContainerType.BATCH, 'MAIN JOB');
main_job.children.add_future(move_pos1);
main_job.children.add_future(move_pos2);
main_job.children.add_future(move_home);もう一つが、インスタンス変数を定義せず、暗黙的にジョブを生成する方法です。FB_Executorインスタンスのメソッド create_future にファクトリクラスを通じて動的に生成しますので、宣言する変数は一つだけで構いません。
ファクトリクラスを通じてcreate_container実行前に必要な動作パラメータを都度設定します。
VAR
move_pos_creater : FB_TaskMoveToPositionCreator;
main_job : FB_Executor;
END_VAR
main_job.create_container(ContainerType.BATCH, 'MAIN JOB');
move_pos_creater.set_parameter(
axis := axis;
target_position := 0.00;
velocity := vel;
acceralation := Acc;
deceralation := Dcc;
jark := Jark;
);
main_job.children.create_future(move_pos_creater, 'MOVE TO HOME');なお、ContainerTypeがBATCH, PARALLELの場合、いちど生成したジョブは残留し続けますので、main_jobは何度でも繰り返し実行可能です。配下のジョブ全てを削除するには、reset()を実行します。
IF main_job.reset() THEN
// reset()からTRUEの戻り値が有れば全ジョブ削除完了
END_IFContainerTypeがQUEUEやPARALLEL_QUEUEの場合は、各子JOBが完了すると自動的にジョブは消滅します。
その他の本フレームワークについての詳細記事がありますのでご参照ください。
https://beckhoff-jp.github.io/TwinCATHowTo/job_management/index.html



