日記；回すだけⅤ ② ST言語（ファンクションブロック）でモータを回す記述＜その2 MAINに記述＞


　TwinCAT3でプログラムを書くときに使えるファンクションブロックを利用する方法は、三つあります。
- MAINにST言語で記述
- POUのMAINの下にアクションを追加し、ファンクションブロックダイアグラムを利用する
- MAINのPOUと同じレベルにPOUを追加し、ファンクションブロックダイアグラムを利用する

　プログラムを記述するのは、PLCの項目です。
　モータを動かすのはMOTIONの項目です。入出力はI/Oの中のドライブ4(EPOS4)に情報が入っています。
### MAINにST言語でファンクションブロックを記述
##### 軸関係の設定
　スキャンで検出されたBLDCコントローラのEPOS4は、MOTIONの軸の項目に表示されます。軸1という名称がデフォルトで割り当てられますが、プログラミングでは使えないのでAX1と変更しました。
![e301.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/ad4c185e-32de-8757-280e-49b614bb1e12.png)
　EPOS4特有の設定をします。パラメータ・タブのその他の設定の中にあるデッドタイム補正を、デフォルトの0から6msに変更します。
![e302.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/a0e18e28-719c-6ca9-b2a3-b022821adc64.png)

　AX1の下にあるエンコーダEncのパラメータ・タブにあるスケーリング係数計算機は、1000パルスがデフォルトだと思われます。今回512パルスのエンコーダを使っているので、0.005に変更しました。正しい係数の算出でないかもしれません。ほとんど動作に影響はないです。
　その下のスケーリング係数の母数をデフォルトの1から20に変更しました。これは、指定する速度や加速度が粗い指定になります。細かな位置決めは、デフォルトのままがよいでしょう。
　すべてを保存します。
![e303.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/3eeab13b-2703-247c-824d-6c7f40d3f11b.png)
##### MAINの場所
　PLCがプログラミング関係の設定エリアです。POUsがソース・エリアです。デフォルトでMAINがあります。
　MAINをダブルクリックすると、右の領域にソースを記述エリアが表示されます。上側が変数宣言、下側が本体です。

![e304.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/cc0c4342-6c4e-9524-75e8-13e25be36602.png)
##### モーションのライブラリを追加
　Referencesの上で右クリックをしてライブラリの追加を選びます。
　検索欄にMC2と入れ、Tc2_MC2を選択してOKを押します。

![2022-10-08 (5)aaa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/3b909312-ed0e-a266-3824-702d590679bd.png)

　デフォルトの三つに、Tc2_MC2が追加されました。モーション関係はこのTc2_MC2ライブラリにあるファンクションブロックを使います。

#### プログラムの記述を開始
　MAINのプログラム本体のエリアで右クリックし、入力アシスタントを選択します。
　入力アシスタントのパネルが出ます。カテゴリからファンクションブロックを選び、折りたたまれたTc2_MC2をクリックしていき、MC_Powerを見つけて、右下のOKを押します。


![e405.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/36890303-7f71-ee73-a4eb-2566488930a2.png)


　自動宣言のパネルが出るので、名前をPower_Onにして、OKをクリックします。
![e406.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/b06a4308-2afd-b138-fc2a-12c723adc977.png)

　ST言語によるモーションの記述が張り込まれました。

![e407.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/5554626e-489a-8cd0-dec3-11cc6148837c.png)

　ソースを修正していきます。
　Axis:=にAX1を代入します。すぐに自動宣言が出ます。何もせず、OKを押します。
![e408.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/388b4c2f-99de-7411-5f65-d18286f09a75.png)

```cpp
	Enable:= TRUE, 
	Enable_Positive:= TRUE, 
	Enable_Negative:= TRUE, 
	Override:= 99,
```

と入力します。Overrideは入力しないと100のようです。テスト時には低い数値を入れるとどこかで読みました。
　メニューのビルドをクリックします。
![e409.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/7e29905b-d8a4-dbf7-9649-55f49e6c4fae.png)

　ソリューションのビルドを選択します。
![e410.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/2351b74e-1020-6ba1-b25a-e9f47b9ff8ec.png)

　エラーがないことを確認します。
![e411.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/2a1b6acd-0a06-8ed3-278f-2b7e1996ad1b.png)

　続けて、一番下の行で、右クリックして入力アシスタントを選択します。
　Motionの下あたりみある MC_MoveAbsoluteを選択してOKを押します。

![e412.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/5bf35b6b-4626-87c5-8673-c994abfe2e7c.png)

　自動宣言が出るので、名前をfb_MoveAbsoluteにしました。
　値を追加していきます。
![e413.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/eb7d2448-221e-9771-484c-b97d31b6394a.png)
　ビルドしてエラーがないことを確認します。

　構成の有効化をクリックします。TwinCATが再起動します。
　AX1をダブルクリックして設定のタブを開きます。
　PLCにリンクをクリックして出てきたパネルから、MAIN.AX1を選択してOKを押します。


![e414aaa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/2d11963a-f0aa-d644-154d-d64061f5919e.png)

　再度ビルドします。
　AX1をダブルクリックして、オンラインのタブを開きます。有効化の設定を三つ全部チェックします。
　動作を確認します。エラーにないことを確認します。エラーになるときは、構成の有効化でエラーをクリアできることが多いです。エラーになるときは、原因を探して修正をしないといけません。とても時間がかかることがあります。
　モータ単体のチューナップがすんでいてぴたっと停止するような状態でも、TwinCAT3のMotionでもPID制御が行われるので、停止位置が微妙に修正される場合があります。

![e416.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/48e648fc-4b1b-a4b0-5fda-e4fe5a846f62.png)



##### スイッチ入力部

　プログラムを追加していきます。
　最初に、fb_MoveAbsoluteの入力ExecuteとPositionを修正します。どちらも何も入れません。

![e501.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/79db28b5-f773-3e4e-d235-0ddcfa0417ac.png)


　四つあるディジタル入力は、I/Oのドライブ4、CSP InputsのDigital Inputsに反映されます。

![e415ddd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/0004a669-59ad-8407-1c64-1ed81e84c288.png)

　最下行に移動します。

　``IF  Din1 = 917504  THEN  // sw1``を入力すると自動宣言が出ます。INTではなくUDINTに修正してOKを押します。

![e502.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/09a90aa0-69d0-a01f-883f-de6cfdf9711e.png)

　``Dout1 := 917503;``を入力すると自動宣言が出ます。INTではなくDUINTに修正してOKを押します。

![e503.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/8be972c0-5941-f020-db8f-842cf8696655.png)

　続けて条件文を完成させます。
　Din1が917504＝sw1が押されたら、ExecuteをTRUEにし、Positionに10を代入します。
　Din1が851968＝sw2が押されたら、ExecuteをTRUEにし、Positionに-10を代入します。
　それ以外の状態ならば、ExecuteをFALSEにして回転させません。

![e504.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/fd313426-0d60-d277-c16c-1ce37d717ccd.png)


　つぎに、物理的なスイッチとプログラムを関連づけます。
　変数領域のDin1とDout1を修正します。
![e505.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/bbbbe74a-e2bc-5985-760f-fccf74e28534.png)

　ビルドします。
　CSP InputsのDigital Inputsを右クリックしてリンクを変更をクリックすると、変数Digital Inputsのアタッチ（入力）パネルが出て、該当するプログラムの変数を選択してOKを押します。
![e506.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/e0a1a499-d5f7-6ac2-5599-5c0825580841.png)

　CSP OutputsのDigital Oututsも同様にリンクを変更してDout1と関連付けます。
　ビルドします。

　この関連付けは、プログラムを修正していると簡単に外れてしまうので、再度関連付けをします。



　実行します。sw1、sw2を押すと、それぞれの方向で回転し、LEDが点灯します。
　回転する距離はPositionの値、速度はVelocity、台形駆動の立ち上がりはAcceleration、立ち下がりはDecelerationの値を変更すれば変化します。モータに合わせて値を変更します。
![e508.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/550322b6-4138-1a2a-3ec8-998cedd071d4.png)

　ソースです。


```cpp
PROGRAM MAIN
VAR
	Power_On: MC_Power;
	AX1: AXIS_REF;
	fb_MoveAbsolute: MC_MoveAbsolute;

	Din1  AT %I*: UDINT;
	Dout1 AT %Q*: UDINT;
END_VAR
```

```cpp
Power_On(
	Axis:= AX1, 
	Enable:= TRUE, 
	Enable_Positive:= TRUE, 
	Enable_Negative:= TRUE, 
	Override:= 99, 
	BufferMode:= , 
	Options:= , 
	Status=> , 
	Busy=> , 
	Active=> , 
	Error=> , 
	ErrorID=> );
	
fb_MoveAbsolute(
	Axis:= AX1, 
	Execute:= , 
	Position:= , 
	Velocity:= 20, 
	Acceleration:= 30, 
	Deceleration:= 20, 
	Jerk:= 200, 
	BufferMode:= , 
	Options:= , 
	Done=> , 
	Busy=> , 
	Active=> , 
	CommandAborted=> , 
	Error=> , 
	ErrorID=> );
	
IF  Din1 = 917504  THEN  // sw1
	Dout1 := 917503;
	fb_MoveAbsolute.Execute  := TRUE;
	fb_MoveAbsolute.Position := 10;

ELSIF Din1 = 851968  THEN  // sw2
	Dout1 := 917504;
	fb_MoveAbsolute.Execute  := TRUE;
	fb_MoveAbsolute.Position := -10;

ELSE
	fb_MoveAbsolute.Execute  := FALSE;
	fb_MoveAbsolute.Position := 1;	
		
END_IF
```