キャリアボードに供給する電源が内蔵のスイッチ回路を介してEHコネクタからサーボへ供給される。
Raspberry Pi Zero 2 Wの操作はモニタとキーボードを直接接続して行うも良し、USB経由のRNDISでリモートログインしても良し、WiFi経由でリモートログインしても良し。
これでハードウェアの準備は完了。
ではようやくソフトウェアに。
Raspberry Pi Zero 2 WをホストとしたのでLinuxが前提、Zeroは極めてメモリが少ないのでCLIを基本とした。今回はモータが動きさえすれば良いので、プログラムのデバッグはキャラクタベースで十分と判断。
キャリアボードはRaspberry Piの機能を利用するので、本家のドキュメントやDXHATの使用方法を元に設定。念のためcmdline.txtからconsoleの記述が消えているのを確認しておこう。
キャリアボードのRS-485 I/FはZeroの「/dev/ttyAMA0」に割り当てられる。
この辺は先人の知恵を借りれば良し。
_retrynum = 3 # mode set & torque enable def _setmode(pmx, id, m): for i in range(_retrynum): if pmx.MemWRITE8(id, 500, pmx.MOTW_OPT_FREE): if m != 0: # 1:pos,2:speed,4:cur,8:torq,16:pwm,32:time if pmx.MemWRITE8(id, 501, m): if pmx.MemWRITE8(id, 502, 0b11111): if pmx.MemWRITE8(id, 503, 5): if pmx.MemWRITE8(id, 500, pmx.MOTW_OPT_TORQUEON): return True else: return True return False
def SetMode(pmx, ids, m): if isinstance(ids, list) or isinstance(ids, tuple): r = 0 for i, id in enumerate(ids): if isinstance(m, list) or isinstance(m, tuple): r += 1 if _setmode(pmx, id, m[i]) else 0 else: r += 1 if _setmode(pmx, id, m) else 0 return True if r == len(ids) else False else: return _setmode(pmx, ids, m)
# set angle def _setangle(pmx, id, ang, t): for i in range(_retrynum): r = pmx.MotorWRITE(id, pmx.MOTW_OPT_NONE, (int(ang * 100), t)) if r != None: if len(r) > 0: return r[1] return ()
def SetAngle(pmx, ids, angs, t): if isinstance(ids, list) or isinstance(ids, tuple): r = () for i, id in enumerate(ids): if isinstance(angs, list) or isinstance(angs, tuple): r += _setangle(pmx, id, angs[i], t), else: r += _setangle(pmx, id, angs, t), return r else: return _setangle(pmx, ids, angs, t)
# set velocity def _setvelocity(pmx, id, velo): for i in range(_retrynum): r = pmx.MotorWRITE(id, pmx.MOTW_OPT_NONE, (int(velo),)) if r != None: if len(r) > 0: return r[1] return ()
def SetVelocity(pmx, ids, velos): if isinstance(ids, list) or isinstance(ids, tuple): r = () for i, id in enumerate(ids): if isinstance(velos, list) or isinstance(velos, tuple): r += _setvelocity(pmx, id, velos[i]), else: r += _setvelocity(pmx, id, velos), return r else: return _setvelo(pmx, ids, velos)
def _getpresent(pmx, id): for i in range(_retrynum): r = pmx.MemREAD16(id, 300, 5, signed = True) if r != None: return r return ()
def GetPresent(pmx, ids): if isinstance(ids, list) or isinstance(ids, tuple): r = () for i, id in enumerate(ids): r += _getpresent(pmx, id), return r else: return _getpresent(pmx, ids)
if __name__ == "__main__": import os, sys, time, kbhit from pyPMX import PMXProtocol
# Position Control print('Position Control') print(f'{ID1}:angle velo cur torque pwm {ID2}:angle velo cur torque pwm') if SetMode(pmx, (ID1, ID2), 1|32): while not kb.kbhit(): t = 1000 for ang in (0, 45, 90, 45, 0, -45, -90, -45): if kb.kbhit(): break SetAngle(pmx, (ID1, ID2), (ang, ang * 2), t) s = time.time() + t / 1000.0 while s > time.time(): if kb.kbhit(): break r = GetPresent(pmx, (ID1, ID2)) for r in r: print(('{:6d} '*len(r)).format(*r), end='') print(end='\r') SetMode(pmx, (ID1, ID2), 0) kb.getch()
# Velocity Control print('\nVelocity Control') print(f'{ID1}:angle velo cur torque pwm {ID2}:angle velo cur torque pwm') if SetMode(pmx, (ID1, ID2), 2): while not kb.kbhit(): t = 3000 for velo in (0, 500, 1000, 1500, 1000, 500, 0, -500, -1000, -1500, -1000, -500): if kb.kbhit(): break SetVelocity(pmx, (ID1, ID2), (velo*1, velo*1.5)) s = time.time() + t / 1000.0 while s > time.time(): if kb.kbhit(): break r = GetPresent(pmx, (ID1, ID2)) for r in r: print(('{:6d} '*len(r)).format(*r), end='') print(end='\r') SetMode(pmx, (ID1, ID2), 0)