exoskeleton/code/test/broadcast_control.py

140 lines
4.1 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
瓴控电机 CAN 广播控制V2.35
- 力矩/开环控制帧ID 0x280data[0..7] 4 个电机的 int16 torqueValue低字节在前小端
- 混合命令帧ID 0x288data[0,2,4,6] 4 个电机 motorCmd 0x88 开启 / 0x81 停止 / 0x80 关闭
依赖
pip install python-can
运行前准备Linux 推荐 SocketCAN
sudo ip link set can0 up type can bitrate 500000
或者 1000000看你驱动与设备设置
"""
from __future__ import annotations
import time
from typing import Iterable, Tuple
import can
TORQUE_CMD_ID = 0x280
MIXED_CMD_ID = 0x288
# 混合命令 motorCmd来自文档
CMD_READ_STATUS1 = 0x9A
CMD_CLR_ERROR = 0x9B
CMD_READ_STATUS2 = 0x9C
CMD_MOTOR_OFF = 0x80
CMD_MOTOR_ON = 0x88
CMD_MOTOR_STOP = 0x81
def _clamp_int16(x: int) -> int:
"""限制到 int16 范围(-32768..32767),随后按补码打包。"""
return max(-32768, min(32767, int(x)))
def _pack_i16_le(x: int) -> Tuple[int, int]:
"""int16 -> (low_byte, high_byte) 小端。"""
x = _clamp_int16(x)
u = x & 0xFFFF
return (u & 0xFF, (u >> 8) & 0xFF)
def build_torque_broadcast(t1: int, t2: int, t3: int, t4: int = 0) -> can.Message:
"""
帧ID 0x280:
data[0..1]=#1 torqueValue (low,high)
data[2..3]=#2
data[4..5]=#3
data[6..7]=#4
"""
d0, d1 = _pack_i16_le(t1)
d2, d3 = _pack_i16_le(t2)
d4, d5 = _pack_i16_le(t3)
d6, d7 = _pack_i16_le(t4)
data = [d0, d1, d2, d3, d4, d5, d6, d7]
return can.Message(arbitration_id=TORQUE_CMD_ID, is_extended_id=False, data=data)
def build_mixed_cmd(cmd1: int, cmd2: int, cmd3: int, cmd4: int = 0x00) -> can.Message:
"""
帧ID 0x288:
data[0]=#1 motorCmd, data[1]=0
data[2]=#2 motorCmd, data[3]=0
data[4]=#3 motorCmd, data[5]=0
data[6]=#4 motorCmd, data[7]=0
"""
data = [cmd1 & 0xFF, 0x00, cmd2 & 0xFF, 0x00, cmd3 & 0xFF, 0x00, cmd4 & 0xFF, 0x00]
return can.Message(arbitration_id=MIXED_CMD_ID, is_extended_id=False, data=data)
def send_many(bus: can.BusABC, msgs: Iterable[can.Message], gap_s: float = 0.005) -> None:
"""连续发几帧(给驱动一点处理间隔)。"""
for m in msgs:
bus.send(m)
print(m)
time.sleep(gap_s)
def main():
# 1) 选择 CAN 接口
# - Linux SocketCAN: channel="can0", bustype="socketcan"
# - 如果你用的是 USB-CAN 且已有 python-can 对应驱动,也可改 bustype/channel
bus = can.Bus(interface="canalystii", channel=0, bitrate=1000000)
# 2) 可选:先广播“电机开启”
send_many(bus, [build_mixed_cmd(CMD_MOTOR_ON, CMD_MOTOR_ON, CMD_MOTOR_ON, CMD_MOTOR_ON)], gap_s=0.02)
# 3) 力矩模式:控制 3 个电机一起转(示例:#1=+T, #2=-T, #3=+T第4路=0
# 注意 torqueValue 的具体量程与含义:文档写 MF/MG 为 -2000..2000电流力矩MS 为 -850..850(开环电压)
# 发送频率:文档提示 500kbps 下 4 电机广播最大约 600Hz1Mbps 下约 1.2kHz。这里示例用 200Hz 更稳妥。
freq_hz = 500.0
dt = 1.0 / freq_hz
T = 200 # 示例力矩指令(根据你的电机系列调整范围)
count = 0
try:
while True:
# now = time.time()
# if now - t0 > duration_s:
# break
msg = build_torque_broadcast(
t1=50,
t2=50,
t3=40,
t4=50
)
bus.send(msg)
count += 1
if count % 100 == 0:
print(msg)
time.sleep(dt)
except KeyboardInterrupt:
pass
finally:
# 4) 停止(建议退出前先 stop再按需 off
msg = build_torque_broadcast(
t1=0,
t2=0,
t3=0,
t4=0
)
bus.send(msg)
send_many(bus, [build_mixed_cmd(CMD_MOTOR_STOP, CMD_MOTOR_STOP, CMD_MOTOR_STOP, CMD_MOTOR_STOP)], gap_s=0.02)
send_many(bus, [build_mixed_cmd(CMD_MOTOR_OFF, CMD_MOTOR_OFF, CMD_MOTOR_OFF, CMD_MOTOR_OFF)], gap_s=0.02)
bus.shutdown()
if __name__ == "__main__":
main()