#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 瓴控电机 CAN 广播控制(V2.35): - 力矩/开环控制:帧ID 0x280,data[0..7] 为 4 个电机的 int16 torqueValue(低字节在前,小端) - 混合命令:帧ID 0x288,data[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 电机广播最大约 600Hz;1Mbps 下约 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()