exoskeleton/code/hardware/exoskeleton.py

173 lines
6.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()