import time import can import threading from typing import Dict, List, Tuple, Optional from canbus import RxCache4Ch, BroadcastSenderThread, SingleSenderThread from usb_can import resolve_canalyst_device_index from can_msg_builder import * class Exoskeleton: def __init__(self): self.bitrate = 1000000 self.motor_map = { ("dev0", 0): [1, 2, 3, 4], ("dev0", 1): [1, 2, 3, 4], ("dev1", 0): [1, 2, 3, 4], ("dev1", 1): [1, 2, 3, 4], } self.joint_map = { "sender-dev0-ch0": ["LJ1", "LJ2", "RJ1", "RJ2"], "sender-dev0-ch1": ["LJ5", "LJ3", "RJ5", "RJ3"], "sender-dev1-ch0": ["LJ7", "LJ6", "LJ4"], "sender-dev1-ch1": ["RJ7", "RJ6", "RJ4"], } idx0 = resolve_canalyst_device_index("/dev/canalystii_1") idx1 = resolve_canalyst_device_index("/dev/canalystii_0") self.bus0 = can.Bus(interface="canalystii", channel=[0, 1], bitrate=self.bitrate, device=idx0) self.bus1 = can.Bus(interface="canalystii", channel=[0, 1], bitrate=self.bitrate, device=idx1) # ========= 接收缓存:每个设备一个 Notifier,一个 cache(按 channel 分流) ========= self.cache0 = RxCache4Ch({0: ["LJ1", "LJ2", "RJ1", "RJ2"], 1: ["LJ5", "LJ3", "RJ5", "RJ3"]}) self.cache1 = RxCache4Ch({0: ["LJ7", "LJ6", "LJ4"], 1: ["RJ7", "RJ6", "RJ4"]}) self.notifier0 = can.Notifier(self.bus0, [self.cache0], timeout=0.01) self.notifier1 = can.Notifier(self.bus1, [self.cache1], timeout=0.01) # ========= 发送线程:4个逻辑channel ========= self.stop_event = threading.Event() self.cmd_event = threading.Event() self.barrier = threading.Barrier(4 + 1) # 4个sender + 主线程 self.bus0_lock = threading.Lock() self.bus1_lock = threading.Lock() sender_dev0_ch0 = BroadcastSenderThread( "sender-dev0-ch0", self.bus0, self.bus0_lock, 0, self.cmd_event, self.barrier, self.stop_event) sender_dev0_ch1 = SingleSenderThread( "sender-dev0-ch1", self.bus0, self.bus0_lock, 1, self.cmd_event, self.barrier, self.stop_event, [1, 3]) sender_dev1_ch0 = BroadcastSenderThread( "sender-dev1-ch0", self.bus1, self.bus1_lock, 0, self.cmd_event, self.barrier, self.stop_event) sender_dev1_ch1 = BroadcastSenderThread( "sender-dev1-ch1", self.bus1, self.bus1_lock, 1, self.cmd_event, self.barrier, self.stop_event) self.senders = [sender_dev0_ch0, sender_dev0_ch1, sender_dev1_ch0, sender_dev1_ch1] for sender in self.senders: sender.start() def turn_on(self): for sender in self.senders: sender.turn_on() self.cmd_event.set() try: self.barrier.wait(timeout=0.05) except threading.BrokenBarrierError: pass self.cmd_event.clear() def turn_off(self): for sender in self.senders: sender.turn_off() self.cmd_event.set() try: self.barrier.wait(timeout=0.05) except threading.BrokenBarrierError: pass self.cmd_event.clear() def clear_error(self): for sender in self.senders: sender.clear_error() self.cmd_event.set() try: self.barrier.wait(timeout=0.05) except threading.BrokenBarrierError: pass self.cmd_event.clear() def stop_all(self): for sender in self.senders: sender.stop() self.cmd_event.set() try: self.barrier.wait(timeout=0.05) except threading.BrokenBarrierError: pass self.cmd_event.clear() def set_zero(self): for sender in self.senders: sender.set_zero() self.cmd_event.set() try: self.barrier.wait(timeout=0.05) except threading.BrokenBarrierError: pass self.cmd_event.clear() def set_torq(self, torq: Dict[str, float]): torq_cmd = {} for sender in self.senders: torq_cmd[sender.name] = [torq[x] for x in self.joint_map[sender.name]] for sender in self.senders: sender.set_torq(torq_cmd[sender.name]) self.cmd_event.set() try: self.barrier.wait(timeout=0.05) except threading.BrokenBarrierError: pass self.cmd_event.clear() def set_pos(self, pos: Dict[str, float]): pos_cmd = {} for sender in self.senders: pos_cmd[sender.name] = [pos[x] for x in self.joint_map[sender.name]] for sender in self.senders: sender.set_pos(pos_cmd[sender.name]) self.cmd_event.set() try: self.barrier.wait(timeout=0.05) except threading.BrokenBarrierError: pass self.cmd_event.clear() def get_states(self): c0 = self.cache0.snapshot() c1 = self.cache1.snapshot() print({"c0": c0, "c1": c1}) @staticmethod def _arb_id_single(motor_id: int) -> int: return 0x140 + int(motor_id) if __name__ == "__main__": exoskeleton = Exoskeleton() exoskeleton.turn_on() count = 0 try: while True: time.sleep(0.02) exoskeleton.set_torq({ "LJ1": 30, "LJ2": 30, "LJ3": 30, "LJ4": 30, "LJ5": 100, "LJ6": 100, "LJ7": 100, "RJ1": 30, "RJ2": 30, "RJ3": 30, "RJ4": 30, "RJ5": 100, "RJ6": 100, "RJ7": 100, }) count += 1 if count % 10 == 0: exoskeleton.get_states() except KeyboardInterrupt: exoskeleton.set_torq({ "LJ1": 0, "LJ2": 0, "LJ3": 0, "LJ4": 0, "LJ5": 0, "LJ6": 0, "LJ7": 0, "RJ1": 0, "RJ2": 0, "RJ3": 0, "RJ4": 0, "RJ5": 0, "RJ6": 0, "RJ7": 0, }) exoskeleton.stop_all() exoskeleton.turn_off() exoskeleton.stop_event.set() exoskeleton.cmd_event.set() for th in exoskeleton.senders: th.join(timeout=0.5) exoskeleton.notifier0.stop() exoskeleton.notifier1.stop() exoskeleton.bus0.shutdown() exoskeleton.bus1.shutdown()