遅いPythonでもモーションとモーションの間の処理が遅くならない方法があります。WMXのAPIバッファー機能を使ってください。
APIバッファの使い方
ApiBufferクラスを作成して、「記録開始」「モーションの登録」「記録終了」「モーション動作開始」の流れになります。 ApiBufferは複数存在できますので、バッファを動作中にほかのバッファーに記録する事もできます。
検証コード
1つの軸で、3つの位置を移動するコードになります。モーションはリアルタイムスレッドで動作します。移動ポイント1に移動後、時間待ち。その後ポイント2を経由でポイント3に移動します。
# WMXに必要なコード
from WMX3ApiPython import *
from time import *
INFINITE = int(0xFFFFFFFF)
def main():
# 制御する軸番号(0から始まります。)
AXIS_NO = 0
print('WMXプログラムスタート ディバイスを作成します')
# WMXを使用するおまじない
Wmx3Lib = WMX3Api()
Wmx3Lib.CreateDevice('C:\\Program Files\\SoftServo\\WMX3\\', DeviceType.DeviceTypeNormal, INFINITE)
Wmx3Lib.SetDeviceName('devicePython')
Wmx3Lib_cm = CoreMotion(Wmx3Lib)
#スレーブとの通信開始
ret = Wmx3Lib.StartCommunication(INFINITE)
#ここでユーザーの処理を記述します。
print('WMXサーボオン')
Wmx3Lib_cm.axisControl.SetServoOn(AXIS_NO, 1)
# サーボがONするまで待機
while True:
ret, CmStatus = Wmx3Lib_cm.GetStatus()
if (CmStatus.GetAxesStatus(AXIS_NO).servoOn):
break
sleep(0.1)
# 原点復帰
homeParam = Config_HomeParam()
ret, homeParam = Wmx3Lib_cm.config.GetHomeParam(0)
homeParam.homeType = Config_HomeType.CurrentPos
Wmx3Lib_cm.config.SetHomeParam(0, homeParam)
Wmx3Lib_cm.home.StartHome(0)
Wmx3Lib_cm.motion.Wait(0)
API_NO = 0 # APIバッファーは複数定義することができます
api = ApiBuffer(Wmx3Lib)
api.Clear(API_NO)
api.CreateApiBuffer(API_NO) # チャネルを開く
print('待機中1。何かキーを押すとAPIバッファーの記録を開始します。')
input() # 1個目の待ち
# 記録開始
api.StartRecordBufferChannel(API_NO)
posCommand = Motion_PosCommand()
posCommand.profile.type = ProfileType.Trapezoidal
posCommand.axis = AXIS_NO #制御したい軸番号の設定
posCommand.profile.velocity = 100000 #スピード設定
posCommand.profile.acc = 100000
posCommand.profile.dec = 100000
#移動ポイント1
posCommand.target = 10000 #移動先の座標設定
Wmx3Lib_cm.motion.StartPos(posCommand)
Wmx3Lib_cm.motion.Wait(0) #移動命令の完了待ち(サーボの位置決め完了ではありません)
api.Sleep(100) # リアルタイムスレッドでの時間待ち(正確です)
#移動ポイント2
posCommand.target = 20000 #移動先の座標設定
Wmx3Lib_cm.motion.StartPos(posCommand)
Wmx3Lib_cm.motion.Wait(0) #移動命令の完了待ち(サーボの位置決め完了ではありません)
#移動ポイント3
posCommand.target = -1340 #移動先の座標設定
Wmx3Lib_cm.motion.StartPos(posCommand)
Wmx3Lib_cm.motion.Wait(0) #移動命令の完了待ち(サーボの位置決め完了ではありません)
# 記録終了
api.EndRecordBufferChannel()
print('待機中2。APIバッファーの記録を終了しました。何かキーを押すとAPIバッファーで動作します。')
input() # 2個目の待ち
#リアルタイム動作開始
api.Execute(API_NO)
print('待機中3。何かキーを押すと終了します。')
input()
api.Halt(API_NO) #APIバッファの実行を停止。この命令を行わないと、新しく記録した瞬間にモーションが実行されてしまいます(同じAPIチャンネルの場合)
# stopOnLastBlockオプションが有効の時は、Haltは不要です。
api.Clear(API_NO) # WMX3を開いているとAPIがクリアされません
print('WMXサーボオフ')
Wmx3Lib_cm.axisControl.SetServoOn(AXIS_NO, 0)
# サーボがOFFするまで待機
while True:
ret, CmStatus = Wmx3Lib_cm.GetStatus()
if (not CmStatus.GetAxesStatus(0).servoOn):
break
sleep(0.1)
#スレーブとの通信終了
Wmx3Lib.StopCommunication(INFINITE)
#WMXの終了
Wmx3Lib.CloseDevice()
print('WMXプログラム終了')
sleep(3)
return 0
if __name__ == '__main__':
main()
C#コードの記事はこちらです
上手く動かない場合はこちらの環境設定記事を参照してください。
動かしてみる
サンプルコードが正しく動いているかを確認するためにWMX3コンソールTOOLを起動します。
今回は、C:\WorkPython\PythonTest\のフォルダーにPythonTest_AIPバッファー.pyというファイルを作成して実行しました。
ANACONDAのコンソールを出し、ディレクトリを移動して”python PythonTest_AIPバッファー.py”で実行されます。

下図の状態で、コンソールが1個目の入力待ちの状態になっています。WMXが起動して、サーボONして、原点復帰が完了しています。動かす準備ができた状態です。

キーを押すと、次のコードが処理されます。
StartPos処理を実行しても、軸は動きません。モーションを記録するのみです。

キーを押すと、api.Execute関数が処理され、軸がリアルタイムスレッドで動き始めます。

APIバッファーコーディングの注意 APIバッファーを止めること
APIバッファーはデフォルトで動き続けます。(リアルタイムスレッドで指示待ち状態となっています) そのため、APIを記録しているつもりでStartPos()を行うと、即実行されます。
# 記録終了
api.EndRecordBufferChannel()
の命令を行っていても、APIバッファーに記録&即実行されてしまいますので注意してください。
APIバッファーを止める方法は2つあります。アプリケーションにより使い分けてください。
・Halt()命令をでAPIを止める
・stopOnLastBlockオプションを有効にしてAPIバッファーを起動する。(記録されたAPIを処理したら自動終了)
【調査中】PythonでstopOnLastBlockパラメータを変更したかった
作成したAPIバッファーに対して、GetOptions()でクラス値を取得して、SetOptions()でWMXに書き込みたいのですが、stopOnLastBlockパラメータに参照する方法がよくわかりませんでした。(詳しい人、コメントで教えてください。)
api = ApiBuffer(Wmx3Lib)
apiOptions = api.GetOptions(API_NO)
apiOptions.__setattr__("stopOnLastBlock",True) # true=バッファの最後のAPIが実行されたときに、Halt
【調査中】APIバッファーが止まったことを検知したい
APIバッファーが終わった(モーションが終わった)のを確認して、次の処理を行いたい時があります。
GetStatus()でtuple
(タプル)で値が戻ってきていそう。 要素にアクセスするのにapiStatus[0]で参照してもエラーとなる。(詳しい人、コメントで教えてください。)(ググてもやり方がよくわかりませんでした)
#APIバッファーが終了するまで待機(stopOnLastBlockがtrueが前提のコード)
while(True):
apiStatus = api.GetStatus(API_NO)
if(apiStatus["state"] == ApiBufferState.Stop):
break; # APIバッファーが完了した
time.sleep(3)
あとがき
結構前からPythonでAPIバッファにチャレンジしていましたが、やっと動きました。よかったよかった。 APIバッファーがない場合、装置の制御は絶望的ですので、道が開けました。
コメント