632 lines
22 KiB
Python
632 lines
22 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
'''
|
||
# Description:电机库
|
||
'''
|
||
|
||
from time import sleep
|
||
import numpy as np
|
||
from enum import IntEnum
|
||
from struct import unpack
|
||
from struct import pack
|
||
|
||
|
||
class Motor:
|
||
def __init__(self, MotorType, SlaveID, MasterID):
|
||
"""
|
||
define Motor object 定义电机对象
|
||
:param MotorType: Motor type 电机类型
|
||
:param SlaveID: CANID 电机ID
|
||
:param MasterID: MasterID 主机ID 建议不要设为0
|
||
"""
|
||
self.Pd = float(0)
|
||
self.Vd = float(0)
|
||
self.state_q = float(0)
|
||
self.state_dq = float(0)
|
||
self.state_tau = float(0)
|
||
self.SlaveID = SlaveID
|
||
self.MasterID = MasterID
|
||
self.MotorType = MotorType
|
||
self.isEnable = False
|
||
self.NowControlMode = Control_Type.MIT
|
||
self.temp_param_dict = {}
|
||
|
||
def recv_data(self, q: float, dq: float, tau: float):
|
||
self.state_q = q
|
||
self.state_dq = dq
|
||
self.state_tau = tau
|
||
|
||
def getPosition(self):
|
||
"""
|
||
get the position of the motor 获取电机位置
|
||
:return: the position of the motor 电机位置
|
||
"""
|
||
return self.state_q
|
||
|
||
def getVelocity(self):
|
||
"""
|
||
get the velocity of the motor 获取电机速度
|
||
:return: the velocity of the motor 电机速度
|
||
"""
|
||
return self.state_dq
|
||
|
||
def getTorque(self):
|
||
"""
|
||
get the torque of the motor 获取电机力矩
|
||
:return: the torque of the motor 电机力矩
|
||
"""
|
||
return self.state_tau
|
||
|
||
def getParam(self, RID):
|
||
"""
|
||
get the parameter of the motor 获取电机内部的参数,需要提前读取
|
||
:param RID: DM_variable 电机参数
|
||
:return: the parameter of the motor 电机参数
|
||
"""
|
||
if RID in self.temp_param_dict:
|
||
return self.temp_param_dict[RID]
|
||
else:
|
||
return None
|
||
|
||
|
||
class MotorControl:
|
||
send_data_frame = np.array(
|
||
[0x55, 0xAA, 0x1e, 0x03, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0, 0, 0, 0, 0x00, 0x08, 0x00,
|
||
0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0x00], np.uint8)
|
||
# 4310 4310_48 4340 4340_48
|
||
Limit_Param = [[300, 30, 10], [12.5, 50, 10], [12.5, 8, 28], [12.5, 10, 28],
|
||
# 6006 8006 8009 10010L 10010
|
||
[12.5, 45, 20], [12.5, 45, 40], [12.5, 45, 54], [12.5, 25, 200], [12.5, 20, 200],
|
||
# H3510 DMG6215 DMH6220
|
||
[12.5 , 280 , 1],[12.5 , 45 , 10],[12.5 , 45 , 10]]
|
||
|
||
def __init__(self, serial_device):
|
||
"""
|
||
define MotorControl object 定义电机控制对象
|
||
:param serial_device: serial object 串口对象
|
||
"""
|
||
self.serial_ = serial_device
|
||
self.motors_map = dict()
|
||
self.data_save = bytes() # save data
|
||
if self.serial_.is_open: # open the serial port
|
||
print("Serial port is open")
|
||
serial_device.close()
|
||
self.serial_.open()
|
||
|
||
def controlMIT(self, DM_Motor, kp: float, kd: float, q: float, dq: float, tau: float):
|
||
"""
|
||
MIT Control Mode Function 达妙电机MIT控制模式函数
|
||
:param DM_Motor: Motor object 电机对象
|
||
:param kp: kp
|
||
:param kd: kd
|
||
:param q: position 期望位置
|
||
:param dq: velocity 期望速度
|
||
:param tau: torque 期望力矩
|
||
:return: None
|
||
"""
|
||
if DM_Motor.SlaveID not in self.motors_map:
|
||
print("controlMIT ERROR : Motor ID not found")
|
||
return
|
||
kp_uint = float_to_uint(kp, 0, 500, 12)
|
||
kd_uint = float_to_uint(kd, 0, 5, 12)
|
||
MotorType = DM_Motor.MotorType
|
||
Q_MAX = self.Limit_Param[MotorType][0]
|
||
DQ_MAX = self.Limit_Param[MotorType][1]
|
||
TAU_MAX = self.Limit_Param[MotorType][2]
|
||
q_uint = float_to_uint(q, -Q_MAX, Q_MAX, 16)
|
||
dq_uint = float_to_uint(dq, -DQ_MAX, DQ_MAX, 12)
|
||
tau_uint = float_to_uint(tau, -TAU_MAX, TAU_MAX, 12)
|
||
data_buf = np.array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], np.uint8)
|
||
data_buf[0] = (q_uint >> 8) & 0xff
|
||
data_buf[1] = q_uint & 0xff
|
||
data_buf[2] = dq_uint >> 4
|
||
data_buf[3] = ((dq_uint & 0xf) << 4) | ((kp_uint >> 8) & 0xf)
|
||
data_buf[4] = kp_uint & 0xff
|
||
data_buf[5] = kd_uint >> 4
|
||
data_buf[6] = ((kd_uint & 0xf) << 4) | ((tau_uint >> 8) & 0xf)
|
||
data_buf[7] = tau_uint & 0xff
|
||
self.__send_data(DM_Motor.SlaveID, data_buf)
|
||
self.recv() # receive the data from serial port
|
||
|
||
def control_delay(self, DM_Motor, kp: float, kd: float, q: float, dq: float, tau: float, delay: float):
|
||
"""
|
||
MIT Control Mode Function with delay 达妙电机MIT控制模式函数带延迟
|
||
:param DM_Motor: Motor object 电机对象
|
||
:param kp: kp
|
||
:param kd: kd
|
||
:param q: position 期望位置
|
||
:param dq: velocity 期望速度
|
||
:param tau: torque 期望力矩
|
||
:param delay: delay time 延迟时间 单位秒
|
||
"""
|
||
self.controlMIT(DM_Motor, kp, kd, q, dq, tau)
|
||
sleep(delay)
|
||
|
||
def control_Pos_Vel(self, Motor, P_desired: float, V_desired: float):
|
||
"""
|
||
control the motor in position and velocity control mode 电机位置速度控制模式
|
||
:param Motor: Motor object 电机对象
|
||
:param P_desired: desired position 期望位置
|
||
:param V_desired: desired velocity 期望速度
|
||
:return: None
|
||
"""
|
||
if Motor.SlaveID not in self.motors_map:
|
||
print("Control Pos_Vel Error : Motor ID not found")
|
||
return
|
||
motorid = 0x100 + Motor.SlaveID
|
||
data_buf = np.array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], np.uint8)
|
||
P_desired_uint8s = float_to_uint8s(P_desired)
|
||
V_desired_uint8s = float_to_uint8s(V_desired)
|
||
data_buf[0:4] = P_desired_uint8s
|
||
data_buf[4:8] = V_desired_uint8s
|
||
self.__send_data(motorid, data_buf)
|
||
# time.sleep(0.001)
|
||
self.recv() # receive the data from serial port
|
||
|
||
def control_Vel(self, Motor, Vel_desired):
|
||
"""
|
||
control the motor in velocity control mode 电机速度控制模式
|
||
:param Motor: Motor object 电机对象
|
||
:param Vel_desired: desired velocity 期望速度
|
||
"""
|
||
if Motor.SlaveID not in self.motors_map:
|
||
print("control_VEL ERROR : Motor ID not found")
|
||
return
|
||
motorid = 0x200 + Motor.SlaveID
|
||
data_buf = np.array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], np.uint8)
|
||
Vel_desired_uint8s = float_to_uint8s(Vel_desired)
|
||
data_buf[0:4] = Vel_desired_uint8s
|
||
self.__send_data(motorid, data_buf)
|
||
self.recv() # receive the data from serial port
|
||
|
||
def control_pos_force(self, Motor, Pos_des: float, Vel_des, i_des):
|
||
"""
|
||
control the motor in EMIT control mode 电机力位混合模式
|
||
:param Pos_des: desired position rad 期望位置 单位为rad
|
||
:param Vel_des: desired velocity rad/s 期望速度 为放大100倍
|
||
:param i_des: desired current rang 0-10000 期望电流标幺值放大10000倍
|
||
电流标幺值:实际电流值除以最大电流值,最大电流见上电打印
|
||
"""
|
||
if Motor.SlaveID not in self.motors_map:
|
||
print("control_pos_vel ERROR : Motor ID not found")
|
||
return
|
||
motorid = 0x300 + Motor.SlaveID
|
||
data_buf = np.array([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], np.uint8)
|
||
Pos_desired_uint8s = float_to_uint8s(Pos_des)
|
||
data_buf[0:4] = Pos_desired_uint8s
|
||
Vel_uint = np.uint16(Vel_des)
|
||
ides_uint = np.uint16(i_des)
|
||
data_buf[4] = Vel_uint & 0xff
|
||
data_buf[5] = Vel_uint >> 8
|
||
data_buf[6] = ides_uint & 0xff
|
||
data_buf[7] = ides_uint >> 8
|
||
self.__send_data(motorid, data_buf)
|
||
self.recv() # receive the data from serial port
|
||
|
||
def enable(self, Motor):
|
||
"""
|
||
enable motor 使能电机
|
||
最好在上电后几秒后再使能电机
|
||
:param Motor: Motor object 电机对象
|
||
"""
|
||
self.__control_cmd(Motor, np.uint8(0xFC))
|
||
sleep(0.1)
|
||
self.recv() # receive the data from serial port
|
||
|
||
def enable_old(self, Motor ,ControlMode):
|
||
"""
|
||
enable motor old firmware 使能电机旧版本固件,这个是为了旧版本电机固件的兼容性
|
||
可恶的旧版本固件使能需要加上偏移量
|
||
最好在上电后几秒后再使能电机
|
||
:param Motor: Motor object 电机对象
|
||
"""
|
||
data_buf = np.array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc], np.uint8)
|
||
enable_id = ((int(ControlMode)-1) << 2) + Motor.SlaveID
|
||
self.__send_data(enable_id, data_buf)
|
||
sleep(0.1)
|
||
self.recv() # receive the data from serial port
|
||
|
||
def disable(self, Motor):
|
||
"""
|
||
disable motor 失能电机
|
||
:param Motor: Motor object 电机对象
|
||
"""
|
||
self.__control_cmd(Motor, np.uint8(0xFD))
|
||
sleep(0.01)
|
||
|
||
def set_zero_position(self, Motor):
|
||
"""
|
||
set the zero position of the motor 设置电机0位
|
||
:param Motor: Motor object 电机对象
|
||
"""
|
||
self.__control_cmd(Motor, np.uint8(0xFE))
|
||
sleep(0.1)
|
||
self.recv() # receive the data from serial port
|
||
|
||
def recv(self):
|
||
# 把上次没有解析完的剩下的也放进来
|
||
data_recv = b''.join([self.data_save, self.serial_.read_all()])
|
||
packets = self.__extract_packets(data_recv)
|
||
for packet in packets:
|
||
data = packet[7:15]
|
||
CANID = (packet[6] << 24) | (packet[5] << 16) | (packet[4] << 8) | packet[3]
|
||
CMD = packet[1]
|
||
self.__process_packet(data, CANID, CMD)
|
||
|
||
def recv_set_param_data(self):
|
||
data_recv = self.serial_.read_all()
|
||
packets = self.__extract_packets(data_recv)
|
||
for packet in packets:
|
||
data = packet[7:15]
|
||
CANID = (packet[6] << 24) | (packet[5] << 16) | (packet[4] << 8) | packet[3]
|
||
CMD = packet[1]
|
||
self.__process_set_param_packet(data, CANID, CMD)
|
||
|
||
def __process_packet(self, data, CANID, CMD):
|
||
if CMD == 0x11:
|
||
if CANID != 0x00:
|
||
if CANID in self.motors_map:
|
||
q_uint = np.uint16((np.uint16(data[1]) << 8) | data[2])
|
||
dq_uint = np.uint16((np.uint16(data[3]) << 4) | (data[4] >> 4))
|
||
tau_uint = np.uint16(((data[4] & 0xf) << 8) | data[5])
|
||
MotorType_recv = self.motors_map[CANID].MotorType
|
||
Q_MAX = self.Limit_Param[MotorType_recv][0]
|
||
DQ_MAX = self.Limit_Param[MotorType_recv][1]
|
||
TAU_MAX = self.Limit_Param[MotorType_recv][2]
|
||
recv_q = uint_to_float(q_uint, -Q_MAX, Q_MAX, 16)
|
||
recv_dq = uint_to_float(dq_uint, -DQ_MAX, DQ_MAX, 12)
|
||
recv_tau = uint_to_float(tau_uint, -TAU_MAX, TAU_MAX, 12)
|
||
self.motors_map[CANID].recv_data(recv_q, recv_dq, recv_tau)
|
||
else:
|
||
MasterID=data[0] & 0x0f
|
||
if MasterID in self.motors_map:
|
||
q_uint = np.uint16((np.uint16(data[1]) << 8) | data[2])
|
||
dq_uint = np.uint16((np.uint16(data[3]) << 4) | (data[4] >> 4))
|
||
tau_uint = np.uint16(((data[4] & 0xf) << 8) | data[5])
|
||
MotorType_recv = self.motors_map[MasterID].MotorType
|
||
Q_MAX = self.Limit_Param[MotorType_recv][0]
|
||
DQ_MAX = self.Limit_Param[MotorType_recv][1]
|
||
TAU_MAX = self.Limit_Param[MotorType_recv][2]
|
||
recv_q = uint_to_float(q_uint, -Q_MAX, Q_MAX, 16)
|
||
recv_dq = uint_to_float(dq_uint, -DQ_MAX, DQ_MAX, 12)
|
||
recv_tau = uint_to_float(tau_uint, -TAU_MAX, TAU_MAX, 12)
|
||
self.motors_map[MasterID].recv_data(recv_q, recv_dq, recv_tau)
|
||
|
||
|
||
def __process_set_param_packet(self, data, CANID, CMD):
|
||
if CMD == 0x11 and (data[2] == 0x33 or data[2] == 0x55):
|
||
masterid=CANID
|
||
slaveId = ((data[1] << 8) | data[0])
|
||
if CANID==0x00: #防止有人把MasterID设为0稳一手
|
||
masterid=slaveId
|
||
|
||
if masterid not in self.motors_map:
|
||
if slaveId not in self.motors_map:
|
||
return
|
||
else:
|
||
masterid=slaveId
|
||
|
||
RID = data[3]
|
||
# 读取参数得到的数据
|
||
if is_in_ranges(RID):
|
||
#uint32类型
|
||
num = uint8s_to_uint32(data[4], data[5], data[6], data[7])
|
||
self.motors_map[masterid].temp_param_dict[RID] = num
|
||
|
||
else:
|
||
#float类型
|
||
num = uint8s_to_float(data[4], data[5], data[6], data[7])
|
||
self.motors_map[masterid].temp_param_dict[RID] = num
|
||
|
||
|
||
def addMotor(self, Motor):
|
||
"""
|
||
add motor to the motor control object 添加电机到电机控制对象
|
||
:param Motor: Motor object 电机对象
|
||
"""
|
||
self.motors_map[Motor.SlaveID] = Motor
|
||
if Motor.MasterID != 0:
|
||
self.motors_map[Motor.MasterID] = Motor
|
||
return True
|
||
|
||
def __control_cmd(self, Motor, cmd: np.uint8):
|
||
data_buf = np.array([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, cmd], np.uint8)
|
||
self.__send_data(Motor.SlaveID, data_buf)
|
||
|
||
def __send_data(self, motor_id, data):
|
||
"""
|
||
send data to the motor 发送数据到电机
|
||
:param motor_id:
|
||
:param data:
|
||
:return:
|
||
"""
|
||
self.send_data_frame[13] = motor_id & 0xff
|
||
self.send_data_frame[14] = (motor_id >> 8)& 0xff #id high 8 bits
|
||
self.send_data_frame[21:29] = data
|
||
self.serial_.write(bytes(self.send_data_frame.T))
|
||
|
||
def __read_RID_param(self, Motor, RID):
|
||
can_id_l = Motor.SlaveID & 0xff #id low 8 bits
|
||
can_id_h = (Motor.SlaveID >> 8)& 0xff #id high 8 bits
|
||
data_buf = np.array([np.uint8(can_id_l), np.uint8(can_id_h), 0x33, np.uint8(RID), 0x00, 0x00, 0x00, 0x00], np.uint8)
|
||
self.__send_data(0x7FF, data_buf)
|
||
|
||
def __write_motor_param(self, Motor, RID, data):
|
||
can_id_l = Motor.SlaveID & 0xff #id low 8 bits
|
||
can_id_h = (Motor.SlaveID >> 8)& 0xff #id high 8 bits
|
||
data_buf = np.array([np.uint8(can_id_l), np.uint8(can_id_h), 0x55, np.uint8(RID), 0x00, 0x00, 0x00, 0x00], np.uint8)
|
||
if not is_in_ranges(RID):
|
||
# data is float
|
||
data_buf[4:8] = float_to_uint8s(data)
|
||
else:
|
||
# data is int
|
||
data_buf[4:8] = data_to_uint8s(int(data))
|
||
self.__send_data(0x7FF, data_buf)
|
||
|
||
def switchControlMode(self, Motor, ControlMode):
|
||
"""
|
||
switch the control mode of the motor 切换电机控制模式
|
||
:param Motor: Motor object 电机对象
|
||
:param ControlMode: Control_Type 电机控制模式 example:MIT:Control_Type.MIT MIT模式
|
||
"""
|
||
max_retries = 10
|
||
retry_interval = 0.05 #retry times
|
||
RID = 10
|
||
self.__write_motor_param(Motor, RID, np.uint8(ControlMode))
|
||
for _ in range(max_retries):
|
||
sleep(retry_interval)
|
||
self.recv_set_param_data()
|
||
if Motor.SlaveID in self.motors_map:
|
||
if RID in self.motors_map[Motor.SlaveID].temp_param_dict:
|
||
if self.motors_map[Motor.SlaveID].temp_param_dict[RID] == ControlMode:
|
||
return True
|
||
else:
|
||
return False
|
||
return False
|
||
|
||
def save_motor_param(self, Motor):
|
||
"""
|
||
save the all parameter to flash 保存所有电机参数
|
||
:param Motor: Motor object 电机对象
|
||
:return:
|
||
"""
|
||
can_id_l = Motor.SlaveID & 0xff #id low 8 bits
|
||
can_id_h = (Motor.SlaveID >> 8)& 0xff #id high 8 bits
|
||
data_buf = np.array([np.uint8(can_id_l), np.uint8(can_id_h), 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00], np.uint8)
|
||
self.disable(Motor) # before save disable the motor
|
||
self.__send_data(0x7FF, data_buf)
|
||
sleep(0.001)
|
||
|
||
def change_limit_param(self, Motor_Type, PMAX, VMAX, TMAX):
|
||
"""
|
||
change the PMAX VMAX TMAX of the motor 改变电机的PMAX VMAX TMAX
|
||
:param Motor_Type:
|
||
:param PMAX: 电机的PMAX
|
||
:param VMAX: 电机的VMAX
|
||
:param TMAX: 电机的TMAX
|
||
:return:
|
||
"""
|
||
self.Limit_Param[Motor_Type][0] = PMAX
|
||
self.Limit_Param[Motor_Type][1] = VMAX
|
||
self.Limit_Param[Motor_Type][2] = TMAX
|
||
|
||
def refresh_motor_status(self, Motor):
|
||
"""
|
||
get the motor status 获得电机状态
|
||
"""
|
||
can_id_l = Motor.SlaveID & 0xff #id low 8 bits
|
||
can_id_h = (Motor.SlaveID >> 8) & 0xff #id high 8 bits
|
||
data_buf = np.array([np.uint8(can_id_l), np.uint8(can_id_h), 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00], np.uint8)
|
||
self.__send_data(0x7FF, data_buf)
|
||
self.recv() # receive the data from serial port
|
||
|
||
def change_motor_param(self, Motor, RID, data):
|
||
"""
|
||
change the RID of the motor 改变电机的参数
|
||
:param Motor: Motor object 电机对象
|
||
:param RID: DM_variable 电机参数
|
||
:param data: 电机参数的值
|
||
:return: True or False ,True means success, False means fail
|
||
"""
|
||
max_retries = 20
|
||
retry_interval = 0.05 #retry times
|
||
|
||
self.__write_motor_param(Motor, RID, data)
|
||
for _ in range(max_retries):
|
||
self.recv_set_param_data()
|
||
if Motor.SlaveID in self.motors_map and RID in self.motors_map[Motor.SlaveID].temp_param_dict:
|
||
if abs(self.motors_map[Motor.SlaveID].temp_param_dict[RID] - data) < 0.1:
|
||
return True
|
||
else:
|
||
return False
|
||
sleep(retry_interval)
|
||
return False
|
||
|
||
def read_motor_param(self, Motor, RID):
|
||
"""
|
||
read only the RID of the motor 读取电机的内部信息例如 版本号等
|
||
:param Motor: Motor object 电机对象
|
||
:param RID: DM_variable 电机参数
|
||
:return: 电机参数的值
|
||
"""
|
||
max_retries = 20
|
||
retry_interval = 0.05 #retry times
|
||
self.__read_RID_param(Motor, RID)
|
||
for _ in range(max_retries):
|
||
sleep(retry_interval)
|
||
self.recv_set_param_data()
|
||
if Motor.SlaveID in self.motors_map:
|
||
if RID in self.motors_map[Motor.SlaveID].temp_param_dict:
|
||
return self.motors_map[Motor.SlaveID].temp_param_dict[RID]
|
||
else:
|
||
return None
|
||
return None
|
||
|
||
# -------------------------------------------------
|
||
# Extract packets from the serial data
|
||
def __extract_packets(self, data):
|
||
frames = []
|
||
header = 0xAA
|
||
tail = 0x55
|
||
frame_length = 16
|
||
i = 0
|
||
remainder_pos = 0
|
||
|
||
while i <= len(data) - frame_length:
|
||
if data[i] == header and data[i + frame_length - 1] == tail:
|
||
frame = data[i:i + frame_length]
|
||
frames.append(frame)
|
||
i += frame_length
|
||
remainder_pos = i
|
||
else:
|
||
i += 1
|
||
self.data_save = data[remainder_pos:]
|
||
return frames
|
||
|
||
|
||
def LIMIT_MIN_MAX(x, min, max):
|
||
if x <= min:
|
||
x = min
|
||
elif x > max:
|
||
x = max
|
||
|
||
|
||
def float_to_uint(x: float, x_min: float, x_max: float, bits):
|
||
LIMIT_MIN_MAX(x, x_min, x_max)
|
||
span = x_max - x_min
|
||
data_norm = (x - x_min) / span
|
||
return np.uint16(data_norm * ((1 << bits) - 1))
|
||
|
||
|
||
def uint_to_float(x: np.uint16, min: float, max: float, bits):
|
||
span = max - min
|
||
data_norm = float(x) / ((1 << bits) - 1)
|
||
temp = data_norm * span + min
|
||
return np.float32(temp)
|
||
|
||
|
||
def float_to_uint8s(value):
|
||
# Pack the float into 4 bytes
|
||
packed = pack('f', value)
|
||
# Unpack the bytes into four uint8 values
|
||
return unpack('4B', packed)
|
||
|
||
|
||
def data_to_uint8s(value):
|
||
# Check if the value is within the range of uint32
|
||
if isinstance(value, int) and (0 <= value <= 0xFFFFFFFF):
|
||
# Pack the uint32 into 4 bytes
|
||
packed = pack('I', value)
|
||
else:
|
||
raise ValueError("Value must be an integer within the range of uint32")
|
||
|
||
# Unpack the bytes into four uint8 values
|
||
return unpack('4B', packed)
|
||
|
||
|
||
def is_in_ranges(number):
|
||
"""
|
||
check if the number is in the range of uint32
|
||
:param number:
|
||
:return:
|
||
"""
|
||
if (7 <= number <= 10) or (13 <= number <= 16) or (35 <= number <= 36):
|
||
return True
|
||
return False
|
||
|
||
|
||
def uint8s_to_uint32(byte1, byte2, byte3, byte4):
|
||
# Pack the four uint8 values into a single uint32 value in little-endian order
|
||
packed = pack('<4B', byte1, byte2, byte3, byte4)
|
||
# Unpack the packed bytes into a uint32 value
|
||
return unpack('<I', packed)[0]
|
||
|
||
|
||
def uint8s_to_float(byte1, byte2, byte3, byte4):
|
||
# Pack the four uint8 values into a single float value in little-endian order
|
||
packed = pack('<4B', byte1, byte2, byte3, byte4)
|
||
# Unpack the packed bytes into a float value
|
||
return unpack('<f', packed)[0]
|
||
|
||
|
||
def print_hex(data):
|
||
hex_values = [f'{byte:02X}' for byte in data]
|
||
print(' '.join(hex_values))
|
||
|
||
|
||
def get_enum_by_index(index, enum_class):
|
||
try:
|
||
return enum_class(index)
|
||
except ValueError:
|
||
return None
|
||
|
||
|
||
class DM_Motor_Type(IntEnum):
|
||
DM4310 = 0
|
||
DM4310_48V = 1
|
||
DM4340 = 2
|
||
DM4340_48V = 3
|
||
DM6006 = 4
|
||
DM8006 = 5
|
||
DM8009 = 6
|
||
DM10010L = 7
|
||
DM10010 = 8
|
||
DMH3510 = 9
|
||
DMH6215 = 10
|
||
DMG6220 = 11
|
||
|
||
|
||
class DM_variable(IntEnum):
|
||
UV_Value = 0
|
||
KT_Value = 1
|
||
OT_Value = 2
|
||
OC_Value = 3
|
||
ACC = 4
|
||
DEC = 5
|
||
MAX_SPD = 6
|
||
MST_ID = 7
|
||
ESC_ID = 8
|
||
TIMEOUT = 9
|
||
CTRL_MODE = 10
|
||
Damp = 11
|
||
Inertia = 12
|
||
hw_ver = 13
|
||
sw_ver = 14
|
||
SN = 15
|
||
NPP = 16
|
||
Rs = 17
|
||
LS = 18
|
||
Flux = 19
|
||
Gr = 20 # 齿轮比
|
||
PMAX = 21
|
||
VMAX = 22
|
||
TMAX = 23
|
||
I_BW = 24
|
||
KP_ASR = 25
|
||
KI_ASR = 26
|
||
KP_APR = 27
|
||
KI_APR = 28
|
||
OV_Value = 29
|
||
GREF = 30
|
||
Deta = 31
|
||
V_BW = 32
|
||
IQ_c1 = 33
|
||
VL_c1 = 34
|
||
can_br = 35
|
||
sub_ver = 36 # 固件版本号
|
||
u_off = 50
|
||
v_off = 51
|
||
k1 = 52
|
||
k2 = 53
|
||
m_off = 54
|
||
dir = 55
|
||
p_m = 80
|
||
xout = 81
|
||
|
||
|
||
class Control_Type(IntEnum):
|
||
MIT = 1
|
||
POS_VEL = 2
|
||
VEL = 3
|
||
Torque_Pos = 4
|