Sysmac StudioとSimumatikを使用して仮想のリニアガイドを動かす
はじめに
本記事は、PLC(Programmable Logic Controller)向けのソフトウェア開発に従事、または関心のある方で、Structured Text(ST)による開発に興味がある方向けです。OMRON社のSysmac Studioを使用します。
今回は、Simumatikを使用して仮想環境下でサーボ制御のリニアガイドを動かします。Simumatik上にあるジョイスティックとボタンでリニアガイドを操作できるようにします。Simumatikは、いわゆるデジタルツインプラットフォームの一つです。仮想環境を使用すれば、人が介在するインタラクティブな操作もテストしやすくなります。
SysmacシミュレータとSimumatikによる仮想リニアガイド操作
制御ソフトウェアは、Sysmacシミュレータ上で動作し、ローカルで動作するSimumatikのGatewayが介在して、ローカルのWorkspaceでシミュレーションを実行した後、ブラウザ上のWeb-app clientにレンダリングされます。基にしたSystemはCODESYS向けですが、少し修正するだけで汎用的に使用できます。Simumatikのウェビナーに、Sysmac Studioによるモーション制御があったのですが、もう少し単純でインタラクティブなものが欲しかったのです。
FA向けの仮想環境は、構造的な解析や実物ができる前のお披露目の為にあるわけではありません。大規模な装置であれば、現在操作を行っている場所から死角となる対象についても操作を行いたいということはよくあります。仮想環境があればこれらを事前に確認し、その品質を高めることができます。納品後に大きな変更を加えたり、立ち合い時に慌てて行うことに比べれば、顧客からの信頼も違ったものになります。装置は、完全に自動化していない限り人が介在します。また、完全に自動化していてもメンテナンスには人が介在します。そして、操作性の過不足は装置の生産性に影響します。
Sysmacプロジェクト
次にSysmacプロジェクトがあります。
Simumatikのセットアップ
Simumatik Platformは、ブラウザ上でシミュレーション結果のレンダリングを行うWeb-app client、ローカルでシミュレーション処理を行うWorkspace、SysmacシミュレータのようなサードパーティーとWorkspaceのやり取りを仲介するGatewayから成ります。Web-app clientはSimumatikのWebプラットフォームへのサインイン、WorkspaceとGatewayは端末へのソフトウェアインストール(Simumatik Launcher)を必要とします。
Simumatik Platformへのサインインは次にアクセスします。
Simumatik Launcherのインストールは次を参考にします。
SimumatikのSystemのセットアップ
Simumatikにシミュレーションを行うSystemのセットアップを行います。無料アカウントは制限により公開されているSystemのCloneとSaveができないため、公開されているSystemをロードし、変更を加えてセットアップします。今回は、"Introduction to Motion Control System" を使用します。次の手順で行います。モデリングツールやUnity環境に触れたことがあれば困難はないと思います。
SimumatikのSystemのセットアップ
変更項目は次です。操作ユニットのボタン配置は好みに合わせて変更します。
Component | Property | Value |
---|---|---|
Inductive_sensor_IN4 | Z | 0.797m |
Linear_Driver_1 | Actual position variable | Drive1.ActualPosition |
Driver type | Omron_nexsocket | |
Encoder relation | 1000.0 | |
Setpoint variable | Drive1.SetPosition | |
Linear_Driver_2 | Actual position variable | |
Driver type | Omron_nexsocket | |
Setpoint variable | ||
Linear_motion_slide_encoder | Relation | 0.001 |
PB_NC_IN1 | Label visible | ✅ |
Label text | #Stop | |
PB_NO_IN0 | Label visible | ✅ |
Maintained | ✅ | |
Label text | #Servo on | |
PB_NO_IN2 | Label visible | ✅ |
Label text | #Move to Zero | |
PLC_16DIO_4AIO | Analog range | -4000.00 to 4000.00 |
Driver type | Omron_nexsocket | |
Var AI1 | AI1 | |
Var DI1 | DI1 | |
Var DI2 | DI2 | |
Var DO1 | DO1 | |
Var DO2 | DO2 | |
Voltage range | -10.00 to 10.00 | |
Potentionmeter | Initial value | 100.0 |
Simumatikでのシミュレーション
Simumatikは、Sysmacシミュレータの実行周期に同期した処理を行うわけではありません。Simumatikでシミュレーションを行う場合、時間に強く依存した制御は避けます。例えば、位置制御のモーション制御について、モーション制御命令にSimumatik内の現在位置をフィードバックとして与えてもうまくいきません。時間がかかりすぎて位置偏差異常になります。時間に強く依存した制御は、Sysmacシミュレータ内だけで完結させ、Simumatikからのフィードバックは使わないようにします。
一方、イベントベースの制御は、Simumatikをどの程度の負荷で動作させるかにもよりますが、極端にシビアでなければSimumatikからのフィードバックを使用してもうまくいきます。目視レベルで判別できるものであれば機能しそうです。
使用する端末は、そこそこのものが必要です。Sysmac Studioで作業を行いながら、Sysmacシミュレータを起動し、Simumatikも走らせる必要があります。
Sysmacプロジェクトの構成
リニアガイドの寸動操作と原点位置移動操作だけですが、モーション制御命令を使用します。今回使用するSystem内のリニアドライブは、いわゆるサーボモータを細かにシミュレートするわけではありません。外部シミュレータとやり取りするのは、目標位置、現在位置だけです。よって、サーボドライブの細かなパラメータ設定の体験はできません。また、モーション軸設定はSysmac Studioに比べると抽象的で簡素であり、Sysmac Studioのモーション軸設定とは概念が異なるため設定の転用はできません。1Sサーボを模したComponentが公開されれば同様の設定で意図した動作を行うものを使えるようになるかもしれません。どうしても必要であれば自作という手もあります。
Sysmac Studio側は、ドライブプロファイルを満たしたサーボドライバを使用する前提とし、リニアガイドは、長さが1mの適当な仕様のものとします。軸設定で単位とスケールを合わせます。エンコーダの設定とサーボパラメータは、1Sサーボによる標準的な単軸位置制御としておけばよいです。詳細は、Sysmacプロジェクトを確認してください。I/Oについては、入出力共に16bit分、アナログ1chを満たす構成にすれば十分です。
プログラム
プログラムは次のPOUから成ります。
-
プログラム/Main
制御プログラムのエントリポイントです。 -
プログラム/SimDriveReflection
シミュレーション時にモーション制御値を全ての使用軸に反映します。 -
ファンクションブロック/SliderController
リニアガイドを制御します。 -
ファンクションブロック/SimMCReflector
シミュレーション時にモーション制御値を軸変数に反映します。
Main
Mainは制御プログラムのエントリポイントです。"入力-処理-出力"の基本的な構造です。IO割り付けは、Simumatik上のPLCに合わせています。Simumatikは仮想環境ですが、構築したSysmacプロジェクトは、NXで同様に機能させるのに必要なデバイス構成とI/O割り付けを行っています。もし、同等の物理デバイスがあればそのまま動かせることになります。そして、このMain下に含まれるコードは、シミュレーションに関連したコードを含んでいません。実行環境に関係なく同一のコードが動作します。
// IO in
iSliderModel.CtrlServoOn := DI1[0];
iSliderModel.CtrlStop := NOT DI1[1];
iSliderModel.CtrlMoveToZero := DI1[2];
iSliderModel.PowerOn := DI1[3];
iSliderModel.NegLimit := DI1[4];
iSliderModel.PosLimit := DI1[5];
iSliderModel.CtrlJogLeft := DI1[6];
iSliderModel.CtrlJogRight := DI1[7];
iSliderModel.Velocity
:= ScaleTrans(SclIN:=AI1,
X0:=0, Y0:=0,
X1:=4000, Y1:=190,
SclOfs:=10);
// Process
iSliderModel.AllowMotion := TRUE;
iSliderController(Enable:=TRUE,
Axis:=_MC_AX[0],
Model:=iSliderModel);
// IO out
DO1[0] := _MC_AX[0].DrvStatus.ServoOn;
DO1[1] := _MC_AX[0].DrvStatus.DrvAlarm;
SimDriveReflection
SimDriveReflectionは、シミュレーション時にモーション軸制御の出力を全ての使用軸変数に反映します。SimDriveReflectionはデバッグを有効とし、実機では動作しないように設定します。
// Simulation
FOR i := 0 TO 15 DO
iSimMCRefrectors[i](Enable:=TRUE,
Axis:=_MC_AX[i]);
END_FOR;
// Simumatik
Drive1.SetPosition := TO_REAL(_MC_AX[0].Act.Pos);
Drive2.SetPosition := TO_REAL(_MC_AX[1].Act.Pos);
SliderController
SliderControllerは、リニアガイドを制御するFBです。分量はありますが、単純なモーション制御の集合です。ソフトウェアリミット、セーフティ機能は使用していません。
// FB control
IF Enable AND NOT Busy THEN
Busy := TRUE;
iState := STATE_WAIT;
END_IF;
// IO in
iPrevStop := iStop;
iStop := Model.CtrlStop
OR iMC_Power.Error
OR NOT Model.AllowMotion;
// Control
IF Model.CtrlImmediateStop THEN
iState := STATE_IMMEDIATE_STOP;
ELSIF iStop AND NOT iPrevStop THEN
CASE iState OF
20..69:
iMC_MoveJog.NegativeEnable := FALSE;
iMC_MoveJog.PositiveEnable := FALSE;
iMC_MoveZeroPosition.Execute := FALSE;
iState := STATE_STOP;
END_CASE;
END_IF;
// Process
CASE iState OF
// STATE_INIT
0:
iMC_ImmediateStop.Execute := FALSE;
iMC_Stop.Execute := FALSE;
iMC_Power.Enable := FALSE;
iMC_Reset.Execute := FALSE;
iMC_Home.Execute := FALSE;
iMC_MoveJog.NegativeEnable := FALSE;
iMC_MoveJog.PositiveEnable := FALSE;
iMC_MoveZeroPosition.Execute := FALSE;
IF NOT Enable THEN
iState := STATE_DONE;
ELSE
Inc(iState);
END_IF;
1:
IF Model.PowerOn THEN
Inc(iState);
END_IF;
2:
IF Model.CtrlServoOn THEN
iMC_Power.Enable := TRUE;
Inc(iState);
END_IF;
3:
IF Axis.DrvStatus.ServoOn THEN
iState := STATE_WAIT;
ELSIF iMC_Power.Error THEN
iState := STATE_INIT;
END_IF;
// STATE_WAIT
10:
IF NOT Model.PowerOn
OR NOT Model.CtrlServoOn
OR iMC_Power.Error
THEN
iMC_Power.Enable := FALSE;
iState := STATE_INIT;
ELSIF Model.CtrlStop THEN
iState := STATE_STOP;
ELSIF Model.CtrlResetError THEN
iState := STATE_RESET_ERROR;
ELSIF Model.CtrlHome THEN
iState := STATE_HOME;
ELSIF Model.AllowMotion THEN
IF Model.CtrlJogLeft THEN
iState := STATE_JOG_LEFT;
ELSIF Model.CtrlJogRight THEN
iState := STATE_JOG_RIGHT;
ELSIF Model.CtrlMoveToZero THEN
iState := STATE_MOVE_TO_ZERO;
END_IF;
END_IF;
// STATE_JOG_LFET
20:
IF Model.NegLimit THEN
iState := iState + 9;
ELSIF Model.CtrlJogLeft THEN
iMC_MoveJog.NegativeEnable := TRUE;
iMC_MoveJog.Velocity := Model.Velocity;
Inc(iState);
END_IF;
21:
IF iMC_MoveJog.Error THEN
iMC_MoveJog.NegativeEnable := FALSE;
iMC_Stop.Execute := TRUE;
Inc(iState);
ELSIF NOT Model.CtrlJogLeft OR Model.NegLimit THEN
iMC_MoveJog.NegativeEnable := FALSE;
iMC_Stop.Execute := TRUE;
Inc(iState);
END_IF;
22:
IF iMC_Stop.Done OR iMC_Stop.Error THEN
iMC_Stop.Execute := FALSE;
iState := iState + 7;
END_IF;
29:
IF Axis.Status.Standstill THEN
iState := STATE_WAIT;
END_IF;
// STATE_JOG_RIGHT
30:
IF Model.PosLimit THEN
iState := iState + 9;
ELSIF Model.CtrlJogRight THEN
iMC_MoveJog.PositiveEnable := TRUE;
iMC_MoveJog.Velocity := Model.Velocity;
Inc(iState);
END_IF;
31:
IF iMC_MoveJog.Error THEN
iMC_MoveJog.PositiveEnable := FALSE;
iMC_Stop.Execute := TRUE;
Inc(iState);
ELSIF NOT Model.CtrlJogRight OR Model.PosLimit THEN
iMC_MoveJog.PositiveEnable := FALSE;
iMC_Stop.Execute := TRUE;
Inc(iState);
END_IF;
32:
IF iMC_Stop.Done OR iMC_Stop.Error THEN
iMC_Stop.Execute := FALSE;
iState := iState + 7;
END_IF;
39:
IF Axis.Status.Standstill THEN
iState := STATE_WAIT;
END_IF;
// STATE_MOVE_TO_ZERO
40:
iMC_MoveZeroPosition.Velocity := Model.Velocity;
iMC_MoveZeroPosition.Execute := TRUE;
Inc(iState);
41:
IF iMC_MoveZeroPosition.Done OR iMC_MoveZeroPosition.Error THEN
iMC_MoveZeroPosition.Execute := FALSE;
iState := iState + 8;
END_IF;
49:
IF NOT Model.CtrlMoveToZero THEN
iState := STATE_WAIT;
END_IF;
// STATE_HOME
70:
iMC_Home.Execute := TRUE;
Inc(iState);
71:
IF iMC_Home.Done OR iMC_Home.Error THEN
iMC_Home.Execute := FALSE;
iState := iState + 8;
END_IF;
79:
IF NOT Model.CtrlHome THEN
iState := STATE_WAIT;
END_IF;
// STATE_STOP
80:
iMC_MoveJog.NegativeEnable := FALSE;
iMC_MoveJog.PositiveEnable := FALSE;
iMC_MoveZeroPosition.Execute := FALSE;
IF Axis.Status.Standstill THEN
iState := iState + 9;
ELSE
iMC_Stop.BufferMode := _eMC_BUFFER_MODE#_mcAborting;
iMC_Stop.Execute := TRUE;
Inc(iState);
END_IF;
81:
IF iMC_Stop.Done OR iMC_Stop.Error THEN
iMC_Stop.Execute := FALSE;
iState := iState + 8;
END_IF;
89:
IF Axis.Status.Standstill THEN
iState := STATE_WAIT;
END_IF;
// STATE_RESET_ERROR
90:
iMC_Reset.Execute := TRUE;
Inc(iState);
91:
IF iMC_Reset.Done OR iMC_Reset.Error THEN
iMC_Reset.Execute := FALSE;
iState := iState + 8;
END_IF;
99:
IF NOT Model.CtrlResetError THEN
iState := STATE_WAIT;
END_IF;
// STATE_IMMADIATE_STOP
100:
iMC_MoveJog.PositiveEnable := FALSE;
iMC_MoveJog.NegativeEnable := FALSE;
iMC_MoveZeroPosition.Execute := FALSE;
iMC_ImmediateStop.StopMode := _eMC_STOP_MODE#_mcImmediateStop;
iMC_ImmediateStop.Execute := TRUE;
Inc(iState);
101:
IF iMC_ImmediateStop.Done OR iMC_ImmediateStop.Error THEN
iMC_ImmediateStop.Execute := FALSE;
iState := iState + 8;
END_IF;
109:
IF NOT Model.CtrlImmediateStop THEN
iState := STATE_WAIT;
END_IF;
// STATE_DONE
1000:
Busy := FALSE;
Inc(iState);
END_CASE;
iMC_ImmediateStop(Axis:=Axis);
iMC_Stop(Axis:=Axis);
iMC_Power(Axis:=Axis);
iMC_Reset(Axis:=Axis);
iMC_Home(Axis:=Axis);
iMC_MoveJog(Axis:=Axis);
iMC_MoveZeroPosition(Axis:=Axis);
SimMCReflector
SimMCReflectorは、シミュレーション時にモーション制御値を軸変数に反映するFBです。軸変数は、直接に値を書き込むことができないため、このような処理が必要です。
CASE Axis.Cfg.AxEnable OF
_eMC_AXIS_USE#_mcNoneAxis,
_eMC_AXIS_USE#_mcUnusedAxis:
RETURN;
END_CASE;
IF Enable AND NOT Busy THEN
Busy := TRUE;
iState := STATE_INIT;
END_IF;
CASE iState OF
// STATE_INIT
0:
iSimSetActPos.Enable := FALSE;
iSimSetActVel.Enable := FALSE;
iSimSetActTrq.Enable := FALSE;
iState := STATE_WAIT;
// STATE_WAIT
10:
IF NOT Enable THEN
iState := STATE_DONE;
ELSIF NOT Axis.Status.Standstill THEN
iSimSetActPos.SetPos := Axis.Cmd.Pos;
iSimSetActVel.SetVel := Axis.Cmd.Vel;
iSimSetActTrq.SetTrq := Axis.Cmd.Trq;
iSimSetActPos.Enable := TRUE;
iSimSetActVel.Enable := TRUE;
iSimSetActTrq.Enable := TRUE;
iState := STATE_REFRECT_MOTION;
END_IF;
// STATE_REFRECT_MOTION
20:
iSimSetActPos.SetPos := Axis.Cmd.Pos;
iSimSetActVel.SetVel := Axis.Cmd.Vel;
iSimSetActTrq.SetTrq := Axis.Cmd.Trq;
IF Axis.Status.Standstill THEN
iState := iState + 9;
END_IF;
29:
iSimSetActPos.Enable := FALSE;
iSimSetActVel.Enable := FALSE;
iSimSetActTrq.Enable := FALSE;
iState := STATE_WAIT;
// STATE_DONE
1000:
iSimSetActPos.Enable := FALSE;
iSimSetActVel.Enable := FALSE;
iSimSetActTrq.Enable := FALSE;
Busy := FALSE;
Inc(iState);
END_CASE;
iSimSetActPos(Axis:=Axis);
iSimSetActVel(Axis:=Axis);
iSimSetActTrq(Axis:=Axis);
シミュレーションの実行
SimumatikとSysmacシミュレータを使用したシミュレーションは次の手順で実行します。
- Simumatik LauncherでGatewayが動作していることを確認
- Web-app clientとGatewayが接続していることを確認
- Sysmacシミュレータを開始
- Web-app clientでシミュレーションを開始
Web-app clientでシミュレーション中にSysmacシミュレータを終了した場合、再度、Sysmacシミュレータを開始してもシミュレーションに反映されないことがあります。その場合、一度Web-app clientのシミュレーションを終了し、再度、開始します。シミュレーションを無事に開始できると、Web-app client内で次のような操作が行えるようになります。
SysmacシミュレータとSimumatikによる仮想リニアガイド操作
まとめ
Simumatikは、まだドキュメントが弱いですが、Sysmacシミュレータを使用でき、構成物がシンプルでComponentの振る舞いであるBehaviorの記述も簡易なので手軽に使えます。Simumatikはどことなくゲームのような雰囲気がありますが、そのカジュアルさが良さです。シミュレーションは便利なのですが、どのような妥当性を確認できるのかを見失わないようにする必要があります。Simumatikは万能CAEではありません。Simumatikでシミュレートした対象について、シミュレーションで確認した事項が、その対象を具現化した場合にどのよう事項の妥当性を評価するものであるのかを読み違えないようにする必要があります。
Discussion