この連載で使っているモータ・コントローラBLVD-KRDは、次の三つのモードをサポートしています(最新のバージョンではProfile Torque Mode (tq)をサポート)。
- プロファイル位置モード(pp)
- プロファイル速度モード(pv)
- 原点復帰モード(hm)
初期状態では、「プロファイル速度モード(pv)」が設定されていて、前回まで、位置決めのできる「プロファイル位置モード(pp)」に設定を変更して利用しました。ここでは、「プロファイル速度モード(pv)」を利用します。
(※)同じ動作モードで、異なる表現が混在しています。
- プロファイル位置モード(pp)は、「Profile position mode;位置制御モード」と同じ
- プロファイル速度モード(pv)は、「Profile velocity mode;速度制御モード」と同じ
●プロファイル速度モード(pv)とは
目標位置の定義なしでオブジェクトTarget velocityに書かれた速度設定ポイントに追従します。
設定すべきパラメタ(オブジェクト)です。
- Target velocity (60FFh) 初期値0
- Profile acceleration (6083h) 初期値1000
- Profile deceleration (6084h) 初期値1000
そのほかの設定パラメタです。
- Quick stop deceleration (6085h) 初期値1000
- Quick stop option code (605Ah) 初期値2
- Max torque (6072h) 初期値10000
- Halt option code (605Dh) 初期値1
- Velocity window (606Dh) 初期値15
- Velocity threshold (606Fh) 初期値15
モータ側から返ってくる値です。
- Target reached in statusword
- Speed in statusword
- Velocity actual value (606Ch)
- Torque actual value (6077h)
なじみのないオブジェクト;
◆Velocity window (606Dh) 初期値15
現在の目標速度 (Target velocity) + (Velocity offset) に対して、現在速度 (Velocity actual value)が到達したとみなす速度の差を設定
◆Velocity threshold (606Fh) 初期値15
停止しているとみなす速度の閾値を設定
●MEXE02を用いてプロファイル速度モード(pv)に変更する
接続OFF状態で、「(p5) CANopen object通信初期値・設定」を見ます。
Profile velocity mode = プロファイル速度モード(pv)ですね。なぜか、Profile position modeに変更していた状態から初期状態に戻っています。理由は不明です。
接続をONにし、「(m14) CANopenオブジェクトディクショナリモニタ」を見ます。
Modes of operation、Modes of operation displayが'1'のProfile Position Modeになっています。
つまり、(p5) CANopen object通信初期値・設定で、 Profile Position Mode(1)に変更にして保存した状態は保たれているけど、画面は、あくまでも初期値なので、Profile Velocity Modeになっていたということですね。
「(p5) CANopen object通信初期値・設定」で、接続OFF状態、Modes of operationがProfile velocity mode の状態で、データの書き込みを行います。
●Profile Velocity Modeには2種類の動作がある
Profile Velocity Modeには、Controlwordのbit12の状態によって、2種類の動作があると説明されています。
Controlwordのbit12の説明です。
「(m14) CANopenオブジェクトディクショナリモニタ」の6040h=Controlwordは0x0004です。bit12は'0'ですね。
動作の違いが図示されています。
trajectory generator for positioningは、位置決めの際に使われる軌道ジェネレータのことのようです。bit12が'1'の場合、目標位置(607Ah)の絶対値を相対移動距離として扱うという説明です。軌道ジェネレータは、振動などが起こらないように素早い計算をするという目的で使われるようです。図では、減速時の事例が出ているので、そのような用途に使うときにメリットがあるのかもしれません。
●canppm2.pyを修正してcampvm.py
プログラムcampvm.pyです。move()関数は、引数に速度を入れます。mainでは、CWに10秒、CCWに10秒回転して止まるプログラムです。
「(m16) トレースモニタ」を使うために、最初のresetNmt()は使わず、node.nmt.send_command(0x1) # NMT startに変更してあります。
#node.sdo[0x6060].raw = 0x0003 # Modes of operation <- Profile Velocity Mode
は、MEXE02で'3'へ変更ができていなくても、この1行を生かしておけば、プログラムはProfile Velocity Modeで動作します。
import canopen import time import logging # logging.basicConfig(level=logging.DEBUG)
# Start with creating a network representing one CAN bus network = canopen.Network()
# Connect to the CAN bus # sudo ip link set can0 up type can bitrate 1000000 network.connect(bustype='socketcan', channel='can0') print("\n===start ID=12 OrientalMotor===\n")
# Add some nodes with corresponding Object Dictionaries node = canopen.BaseNode402(12,'Downloads/BLVD-KRD_CANopen_V200.eds') network.add_node(node)
def resetNmt(): # all nodes simulaneously as a broadcast message network.nmt.state = 'RESET' time.sleep(0.5) # Reset this node node.nmt.state = 'RESET' node.nmt.wait_for_bootup(15) node.nmt.state = 'RESET COMMUNICATION' node.nmt.wait_for_bootup(15) node.nmt.send_command(0x1) # NMT start network.check() print('---node state = {0}\n'.format(node.nmt.state))
def startState_machine(): node.setup_402_state_machine() node.sdo[0x6040].raw = 0x0010 # Fault Reset time.sleep(0.5) node.state = 'SWITCH ON DISABLED' time.sleep(0.1) timeout = time.time() + 15 node.state = 'READY TO SWITCH ON' while node.state != 'READY TO SWITCH ON': if time.time() > timeout: raise Exception('Timeout when trying to change state') time.sleep(0.01) time.sleep(0.1) timeout = time.time() + 15 node.state = 'SWITCHED ON' while node.state != 'SWITCHED ON': if time.time() > timeout: raise Exception('Timeout when trying to change state') time.sleep(0.001) time.sleep(0.1) timeout = time.time() + 15 node.state = 'OPERATION ENABLED' while node.state != 'OPERATION ENABLED': if time.time() > timeout: raise Exception('Timeout when trying to change state') time.sleep(0.001) time.sleep(0.1) print("---SWITCH state ready\n") network.check() print('---switch state = {0}\n'.format(node.state))
def move(targetVelocity): node.rpdo[1]['Controlword'].phys = 0x000f node.rpdo[1].transmit() time.sleep(0.02) node.rpdo[4]['Controlword'].phys = 0x200f node.rpdo[4]['Target velocity'].phys = targetVelocity node.rpdo[4].transmit() time.sleep(0.02)
def moveStop(): #node.rpdo[1]['Controlword'].phys = 0x000f #node.rpdo[1].transmit() #time.sleep(0.02) node.rpdo[4]['Controlword'].phys = 0x010f #node.rpdo[4]['Target velocity'].phys = targetVelocity node.rpdo[4].transmit() time.sleep(0.02)
def dispParameter(): Modes_of_Operation = node.sdo[0x6060].raw print('#Modes of Operation',Modes_of_Operation) Modes_of_Operation_Display = node.sdo[0x6061].raw print('#Modes of Operation Display',Modes_of_Operation_Display,'\n') Target_Position = node.sdo[0x607a].raw print('#Target Position',Target_Position) Target_Velocity = node.sdo[0x60ff].raw print('#Target Velocity', Target_Velocity,'\n') Position_Actual_Value = node.sdo[0x6040].raw print('#Position Actual Value',Position_Actual_Value) Velocity_Actual_Value = node.sdo[0x606c].raw print('#Velocity Actual Value', Velocity_Actual_Value,'\n') Profile_velocity = node.sdo[0x6081].raw print('#Profile velocity',Profile_velocity) Profile_acceleration = node.sdo[0x6083].raw print('#Profile acceleration',Profile_acceleration) Profile_deceleration = node.sdo[0x6084].raw print('#Profile deceleration', Profile_deceleration,'\n')
def dispPosition(): node.tpdo[3].wait_for_reception() print('Target position {:4d}'.format(node.tpdo[3]['Position actual value'].phys))
#----main----------------
#resetNmt() node.nmt.send_command(0x1) # NMT start network.sync.start(0.1) # 100ms startState_machine() time.sleep(0.2)
#node.sdo[0x6060].raw = 0x0003 # Modes of operation <- Profile Velocity Mode node.sdo[0x607a].raw = 0 # Target position node.sdo[0x6081].raw = 1000 # Profile velocity node.sdo[0x6083].raw = 1000 # Profile acceleration node.sdo[0x6084].raw = 1000 # Profile deceleration
dispParameter() dispPosition()
print(' ===start move===\n')
move(1000) time.sleep(10) dispPosition()
move(-1000) time.sleep(10) dispPosition()
moveStop()
#------------------- print("\n---closed---") node.sdo[0x6040].raw = 0x0080 # Fault Reset node.nmt.send_command(0x02) # NMT remote stop node.nmt.send_command(0x81) # NMT reset time.sleep(0.5) node.nmt.send_command(0x82) # NMT Reset Communication network.sync.stop() network.disconnect()
|
「(m16) トレースモニタ」の画面です。プログラム実行時の最後のほうで、モータの軸を手でつまんでいるのでトルクが変化しています。