ブログ - KONDO PMX試食3

KONDO PMX試食3

カテゴリ : 
雑記
2024-4-18 11:20
前回に引き続き小出し第3弾。

その前に、今までPMXのボーレートを3Mbpsとしていたが、バックグラウンドで動かしているアプリケーションによって受信データの欠損やズレが散見されていた。そのために態々リトライする関数を用意した訳だが。
原因を追求すべく色々試した結果、Zero 2の都合で時折受信データを取りこぼしていると考えられ、最終的にはボーレートにも依存するところまで判明した。OSが過負荷状態であっても、今のところ1.5Mbps以下であれば受信データを取りこぼさないようだ。

それでは本題に。
前回の漫画にどうしてXC330-T181-Tがつながっていたかの答えでもあるが、常々やってみたかったのが、異なる異メーカのサーボを同時に使うという少々危険なネタ。
これをやってみようと思ったのは、DXLに用意されているV1/V2の通信プロトコルを混在させている実例があったのと、PMXの通信プロトコルがB3MやKRSシリーズのプロトコルに比べ格段に堅牢になっていたからでもある。また単一メーカに依存して無い物ねだりする事を無くす事も狙い。
ちなみにB3MやKRSでは深く考えるまでもなく絶対的に無理、というか危険極まりないのでやってはならない。またDXLもV1とV2を混在させるとV1側の挙動がおかしくなるのは既知なので、実質的に無理。プロトコルの混在を実現するには、各サーボが自身には無関係なパケットを即時破棄する事と、自身に関係のあるパケットを取りこぼさないというそこそこ厳しい条件が求められる。それらは当然こちらでどうにかできる話ではないので、完全に自己責任のネタである。

では徐にやってみる。
PMXはID=0でボーレートを1Mbps、DXLはID=1でボーレートを1Mbpsとした。そもそもプロトコルが異なるのでお互いにIDが同じであっても構わないだろう。ライブラリは前回同様にpyPMX.pypyDXL.pyを使用。以下は1つのコードになっているか、PMXとDXLを各々個別のスレッドで処理させ、互いの存在は全く意識していない。オープンしたポートのインスタンスとLockを両スレッド共通に使用している。いずれも正弦波を元に位置決め制御を行いつつ、現在位置を取得してモニタ用の変数に書き込んでいる。ループ中には適当な時間のsleepを入れておいた方が良いだろう。
#!/usr/bin/python3
from pyPMX import *
from pyDXL import *
import math, kbhit, time, serial, threading

# Communication task with PMX
def func1(arg):
id = 0
# Class instantiation
pmx = PMXProtocol(arg[0], lock = arg[1])
# Setting initial conditions
pmx.MemREAD(id, 400, 6) # Clear error flag
pmx.MotorWRITE(id, 2, ()) # Torque free
pmx.MemWRITE8(id, 501, (1, 0b11111)) # Control mode (All)
pmx.MotorWRITE(id, 1, ()) # Torque enable
while arg[2]:
ang = int(math.sin(time.time()) * 9000.0)
r = pmx.MotorWRITE(id, 0, (ang,)) # Angle command
if r != None:
arg[3] = r[1][0]
time.sleep(0.001)
pmx.MotorWRITE(id, 2, ()) # Torque free
del pmx

# Communication task with DXL
def func2(arg):
id = 1
cnt = 0
led = 0
# Class instantiation
dx2 = DXLProtocolV2(arg[0], lock = arg[1])
# Setting initial conditions
dx2.Write8(id, 64, 1) # Torque enable
while arg[2]:
ang = int(math.sin(time.time()) * 1024.0) + 2047
dx2.Write32(id, 116, ang) # Angle command
r = dx2.Read32(id, 132, signed = True) # Read feedback values
if r != None:
arg[4] = r
cnt += 1
if cnt % 10 == 0:
led ^= 1
dx2.Write8(id, 65, led) # Update LED status
time.sleep(0.001)
dx2.Write8(id, 65, 0) # LED off
dx2.Write8(id, 64, 0) # Torque free
del dx2

kb = kbhit.KBHit()
# Open serial port
com = serial.Serial('/dev/ttyAMA0', 1000000, timeout=0.005)
lock = threading.Lock()
act = True
v1 = 0
v2 = 0
SharedVar = [com, lock, act, v1, v2]

# Start thread
th1 = threading.Thread(target = func1, args = [SharedVar])
th2 = threading.Thread(target = func2, args = [SharedVar])
th1.start()
th2.start()

# Loop until keyboard input
while True:
if kb.kbhit():
break
print(f' pmx:{SharedVar[3]:6d}, dxl:{SharedVar[4]:6d}', end = '\r')
time.sleep(0.05)

# End
SharedVar[2] = False
th1.join()
th2.join()

del kb, lock, com, th1, th2
print()
結果、いずれのサーボもスムーズに動くし、更に長時間運転してみても各関数はエラーを吐いていない。
色々虐め始めるとボロも出て来るだろうが、サーボそのものが不可解な挙動をしない限り、もしかしたら新たな使い道が見い出せるかも知れない。

キャリアボードに装備した機能の検証を含んだ操作している様子を動画にしておいた。

以上で久々に新鮮な気持ちで遊興したレポートを終える。

技術

トラックバック

トラックバックpingアドレス https://www.besttechnology.co.jp/modules/d3blog/tb.php/250