修改传送带电机、舵机、达妙电机等相关接口

This commit is contained in:
2026-02-26 15:42:22 +08:00
parent 5c9946dfc7
commit 8d2e91b8b3
10 changed files with 1642 additions and 331 deletions

View File

@ -22,7 +22,7 @@ class DMMotorController:
"""
初始化电机控制器
:param slave_id: 从机ID默认0x01
:param master_id: 主机ID默认0x11不要设为0x00
:param master_id: 主机ID默认0x11
:param port: 串口端口默认COM6
:param baudrate: 波特率默认921600
"""
@ -40,7 +40,6 @@ class DMMotorController:
# 初始化电机和串口
self.init_motor()
def init_motor(self):
"""初始化电机和串口"""
try:
@ -112,8 +111,8 @@ class DMMotorController:
:param v_desired: 目标速度rad/s, 范围[-30, 30]
"""
try:
# 归零 + 发送运动指令
self.motor_control.set_zero_position(self.motor)
# 发送运动指令
# self.motor_control.set_zero_position(self.motor)
self.motor_control.control_Pos_Vel(self.motor, p_desired, v_desired)
time.sleep(0.1)
print(f"✅ 位置-速度控制:位置={p_desired}rad | 速度={v_desired}rad/s")
@ -135,7 +134,10 @@ class DMMotorController:
return False
def _get_mode_name(self, control_type):
"""获取模式名称"""
"""
获取模式名称
:param control_type: 控制模式Control_Type.POS_VEl/VEL/MIT
"""
# 1.定义[枚举值--中文名称]的映射字典
mode_map = {
Control_Type.POS_VEL: "位置-速度模式",
@ -145,15 +147,55 @@ class DMMotorController:
# 2.根据控制模式值获取中文名称 字典方法
return mode_map.get(control_type, "未知模式") # “未知模式”默认值
def get_position(self):
self.refresh()
return self.motor.getPosition()
def save_param(self):
"""保存所有电机参数"""
try:
if self.motor is None:
raise ValueError("电机实例为None无法保存参数")
def refresh(self):
self.motor_control.refresh_motor_status(self.motor)
self.motor_control.save_motor_param(self.motor)
print("电机参数保存成功")
except Exception as e:
print(f"❌ 电机参数保存失败:{str(e)}")
def refresh_motor_status(self):
"""获得电机状态"""
try:
if self.motor is None:
raise ValueError("电机实例为None无法保存参数")
self.motor_control.refresh_motor_status(self.motor)
print("电机状态刷新成功")
except Exception as e:
print(f"❌ 电机状态刷新失败:{str(e)}")
def get_position(self):
"""获取电机位置"""
try:
if self.motor is None:
raise ValueError("电机实例为None无法保存参数")
position = self.motor.getPosition()
print(f"获取电机位置成功,当前位置: {position}")
return position
except Exception as e:
print(f"获取电机位置失败: {str(e)}")
def change_limit_param(self, motor_type, pmax, vmax, tmax):
self.motor_control.change_limit_param(motor_type, pmax, vmax, tmax)
"""
改变电机的PMAX VMAX TMAX
:param motor_type: 电机的类型
:param pmax: 电机的PMAX
:param vmax: 电机的VMAX
:param tmax: 电机的TAMX
"""
try:
self.motor_control.change_limit_param(motor_type, pmax, vmax, tmax)
print(
f"电机限位参数修改成功 | 类型: {motor_type} | PMAX: {pmax} | VMAX: {vmax} | TMAX: {tmax}"
)
except Exception as e:
print(f"修改电机限位参数失败: {str(e)}")
def __del__(self):
"""析构函数:确保程序退出时失能电机、关闭串口"""
@ -168,7 +210,6 @@ class DMMotorController:
except Exception as e:
print(f" 析构函数执行警告:{str(e)}")
if __name__ == '__main__':
# 1.创建电机控制器实例
motor_controller = DMMotorController(

247
DM/DM_Motor_controller.py Normal file
View File

@ -0,0 +1,247 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
# @Time : 2026/1/6 13:55
# @Author : reenrr
# @File : DM_Motor_test.py
# @Desc : 达妙电机测试
'''
from DM_CAN import *
from DM_Motor import DMMotorController
import time
# -------------------------- 电机参数配置 --------------------------
SLAVE_ID = 0x01
MASTER_ID = 0x11
PORT = 'COM10'
BAUDRATE = 921600
ORI_P_DESIRED = 0.0 # 吸附位置
DROP_P_DESIRED = 0.0 # 放置位置
V_DESIRED = 30
P_DESIRED_MIN = -300
P_DESIRED_MAX = 300
V_DESIRED_MIN = -30
V_DESIRED_MAX = 30
ORIGIN_POSITION = 0.0 # 电机原点位置
POSITION_TOLERANCE = 0.1 # 位置误差阈值
class DMMotorInterface:
def __init__(self):
"""初始化电机控制器,切换模式并使能电机"""
self.motor_controller = DMMotorController(
slave_id=SLAVE_ID,
master_id=MASTER_ID,
port=PORT,
baudrate=BAUDRATE
)
try:
# 切换到位置-速度模式
self.motor_controller.switch_control_mode(Control_Type.POS_VEL)
# 使能电机
self.motor_controller.enable_motor()
except Exception as e:
raise RuntimeError(f"电机初始化失败:{str(e)}") from e
# 全局变量
_DMMotor = DMMotorInterface()
def set_dm_motor_speed(value: int) -> bool:
"""
设置达妙电机速度
:param value: 速度值
:return: 是否设置成功
"""
global V_DESIRED_MIN, V_DESIRED_MAX, V_DESIRED
try:
_min = V_DESIRED_MIN
_max = V_DESIRED_MAX
except NameError as e:
err_msg = f"速度限位常量未定义:{str(e)}请检查V_DESIRED_MIN/V_DESIRED_MAX的定义"
print(f"错误:{err_msg}")
raise Exception(err_msg) from e
if not (_min <= value <= _max):
err_msg = f"速度值超出合法范围:{value},合法范围[{_min}, {_max}]"
print(f"错误:{err_msg}")
# 可选若需要上层感知超限改为抛ValueError替代return False
# raise ValueError(err_msg)
return False
try:
old_value = V_DESIRED
V_DESIRED = value
print(f"成功:电机速度已更新,旧值={old_value},新值={value}(范围[{_min}, {_max}]")
return True
except Exception as e:
# 5. 异常处理:保留原始异常链,加详细日志
err_msg = f"设置电机速度失败:{str(e)}(尝试设置的值:{value}"
print(f"异常:{err_msg}")
# 保留原始异常链,便于上层定位根因
raise Exception(err_msg) from e
def set_ori_position(value: float) ->bool:
"""
设置吸附位置
:param value: 设置吸附位置值
"""
global ORI_P_DESIRED, P_DESIRED_MIN, P_DESIRED_MAX
try:
_min = P_DESIRED_MIN
_max = P_DESIRED_MAX
except NameError as e:
err_msg = f"位置限位常量未定义:{str(e)}请检查P_DESIRED_MIN/P_DESIRED_MAX的定义"
print(f"错误:{err_msg}")
raise Exception(err_msg) from e
if not (_min <= value <= _max):
err_msg = f"位置值超出合法范围:{value},合法范围[{_min}, {_max}]"
print(f"错误:{err_msg}")
# 可选若需要上层感知超限改为抛ValueError替代return False
# raise ValueError(err_msg)
return False
try:
old_value = ORI_P_DESIRED
ORI_P_DESIRED = value
print(f"成功:电机速度已更新,旧值={old_value},新值={value}(范围[{_min}, {_max}]")
return True
except Exception as e:
err_msg = f"设置电机速度失败:{str(e)}(尝试设置的值:{value}"
print(f"异常:{err_msg}")
# 保留原始异常链,便于上层定位根因
raise Exception(err_msg) from e
def set_drop_position(value: float) -> bool:
"""
设置放置位置
:param value: 设置放置位置
"""
global DROP_P_DESIRED, P_DESIRED_MIN, P_DESIRED_MAX
try:
_min = P_DESIRED_MIN
_max = P_DESIRED_MAX
except NameError as e:
err_msg = f"位置限位常量未定义:{str(e)}请检查P_DESIRED_MIN/P_DESIRED_MAX的定义"
print(f"错误:{err_msg}")
raise Exception(err_msg) from e
if not (_min <= value <= _max):
err_msg = f"位置值超出合法范围:{value},合法范围[{_min}, {_max}]"
print(f"错误:{err_msg}")
# 可选若需要上层感知超限改为抛ValueError替代return False
# raise ValueError(err_msg)
return False
try:
old_value = DROP_P_DESIRED
DROP_P_DESIRED = value
print(f"成功:电机速度已更新,旧值={old_value},新值={value}(范围[{_min}, {_max}]")
return True
except Exception as e:
# 5. 异常处理:保留原始异常链,加详细日志
err_msg = f"设置电机速度失败:{str(e)}(尝试设置的值:{value}"
print(f"异常:{err_msg}")
# 保留原始异常链,便于上层定位根因
raise Exception(err_msg) from e
def move_to_ori_position():
"""
移动到吸附位置
"""
try:
print(f"开始执行--移动到吸附位置:目标位置={ORI_P_DESIRED},速度={V_DESIRED}")
_DMMotor.motor_controller.control_pos_vel(ORI_P_DESIRED, V_DESIRED)
time.sleep(5) # 等待电机移动完成
print(f"吸附位置移动指令已发送")
except Exception as e:
# 封装异常信息,保留原始异常链
err_msg = f"移动到吸附位置失败:{str(e)}(目标位置={ORI_P_DESIRED},速度={V_DESIRED}"
print(f"❌ 异常:{err_msg}")
raise RuntimeError(err_msg) from e
def move_to_drop_position():
"""
移动到放置位置
"""
try:
print(f"开始执行--移动到放置位置:目标位置={DROP_P_DESIRED},速度={V_DESIRED}")
_DMMotor.motor_controller.control_pos_vel(DROP_P_DESIRED, V_DESIRED)
time.sleep(5) # 等待电机移动完成
print(f"放置位置移动指令已发送")
except Exception as e:
# 封装异常信息,保留原始异常链
err_msg = f"移动到放置位置失败:{str(e)}(目标位置={DROP_P_DESIRED},速度={V_DESIRED}"
print(f"❌ 异常:{err_msg}")
raise RuntimeError(err_msg) from e
def set_zero_position() -> bool:
"""
电机零点标定将当前物理位置设置为软件0位
注意:调用前需确保电机处于稳定的物理零点位置
"""
try:
print("🔍 开始执行电机零点标定...")
result = _DMMotor.motor_controller.motor_control.set_zero_position(_DMMotor.motor_controller.motor)
if result:
# 保存标定参数(关键:否则断电后零点丢失)
_DMMotor.motor_controller.save_param()
print("✅ 零点标定成功当前位置已设为0位参数已保存")
return True
else:
print("❌ 零点标定失败!")
return False
except Exception as e:
err_msg = f"零点标定异常:{str(e)}"
print(f"{err_msg}")
raise RuntimeError(err_msg) from e
def reset_motor():
"""复位达妙电机,防止断电"""
try:
# 读取断电后的当前位置
print("开始电机复位流程:读取当前位置...")
current_pos = _DMMotor.motor_controller.get_position()
print(f"✅ 读取当前位置成功:{current_pos}")
# 计算需要移动的偏移量(核心逻辑)
if abs(current_pos) <= POSITION_TOLERANCE:
print(f" 当前位置已在原点附近(误差={abs(current_pos)}{POSITION_TOLERANCE}),无需复位")
return True
reset_target_p = -current_pos # 重点修改p_desired = -当前位置
print(f"📌 复位路径计算:当前位置={current_pos} → 需设置p_desired={reset_target_p} → 回到0位")
print(f"🚀 开始复位移动p_desired={reset_target_p},速度={V_DESIRED} rpm")
_DMMotor.motor_controller.control_pos_vel(p_desired=reset_target_p, v_desired=V_DESIRED)
time.sleep(5) # 等待电机复位
except Exception as e:
err_msg = f"电机复位失败:{str(e)}"
print(f"❌ 错误:{err_msg}")
raise RuntimeError(err_msg) from e
# ---------调试接口----------
if __name__ == '__main__':
# 首先在吸附位置处进行 设置零点位置
set_zero_position()
set_dm_motor_speed(30)
set_ori_position(282.6)
move_to_ori_position()

View File

@ -1,257 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
# @Time : 2026/1/6 13:55
# @Author : reenrr
# @File : DM_Motor_test.py
# @Desc : 达妙电机测试
'''
from DM_CAN import *
import serial
import time
# -------------------------- 电机参数配置 --------------------------
SLAVE_ID = 0x01
MASTER_ID = 0x11
PORT = 'COM10'
BAUDRATE = 921600
class DMMotorController:
"""达妙电机控制器类"""
def __init__(self, slave_id=None, master_id=None, port=None, baudrate=None):
"""
初始化电机控制器
:param slave_id: 从机ID默认0x01
:param master_id: 主机ID默认0x11
:param port: 串口端口默认COM6
:param baudrate: 波特率默认921600
"""
# 初始化参数
self.slave_id = slave_id if slave_id is not None else SLAVE_ID
self.master_id = master_id if master_id is not None else MASTER_ID
self.port = port if port is not None else PORT
self.baudrate = baudrate if baudrate is not None else BAUDRATE
# 核心属性初始化
self.serial_device = None # 串口设备
self.motor = None # 电机实例
self.motor_control = None # 电机控制器实例
# 初始化电机和串口
self.init_motor()
def init_motor(self):
"""初始化电机和串口"""
try:
# 1.初始化串口
self.serial_device = serial.Serial(
port=self.port,
baudrate=self.baudrate,
timeout=0.5
)
# 2.创建电机实例
self.motor = Motor(DM_Motor_Type.DM4310, self.slave_id, self.master_id)
# 3.创建电机控制器实例
self.motor_control = MotorControl(self.serial_device)
# 4.添加电机
self.motor_control.addMotor(self.motor)
print(f"✅ 电机初始化成功")
print(f" - 串口:{self.port} | 波特率:{self.baudrate}")
print(f" - 从机ID{hex(self.slave_id)} | 主机ID{hex(self.master_id)}")
except Exception as e:
raise RuntimeError(f"❌ 电机初始化失败:{e}")
def switch_control_mode(self, control_type):
"""
切换电机控制模式
:param control_type: 控制模式Control_Type.POS_VEl/VEL/MIT
:return: 切换成功返回True否则返回False
"""
try:
result = self.motor_control.switchControlMode(self.motor, control_type)
mode_name = self._get_mode_name(control_type)
if result:
print(f"✅ 切换到{mode_name}模式成功")
# 切换模式后保存参数
self.motor_control.save_motor_param(self.motor)
else:
print(f"❌ 切换到{mode_name}模式失败")
return result
except Exception as e:
print(f"❌ 切换模式出错:{str(e)}")
return False
def enable_motor(self):
"""使能电机"""
try:
self.motor_control.enable(self.motor)
print("✅ 电机使能成功")
return True
except Exception as e:
print(f"❌ 电机使能失败:{str(e)}")
return False
def disable_motor(self):
"""失能电机"""
try:
self.motor_control.disable(self.motor)
print("✅ 电机失能成功")
return True
except Exception as e:
print(f"❌ 电机失能失败:{str(e)}")
return False
def control_pos_vel(self, p_desired, v_desired):
"""
位置-速度模式控制
:param p_desired: 目标位置rad, 范围[-300, 300]
:param v_desired: 目标速度rad/s, 范围[-30, 30]
"""
try:
# 发送运动指令
# self.motor_control.set_zero_position(self.motor)
self.motor_control.control_Pos_Vel(self.motor, p_desired, v_desired)
time.sleep(0.1)
print(f"✅ 位置-速度控制:位置={p_desired}rad | 速度={v_desired}rad/s")
return True
except Exception as e:
print(f"❌ 位置-速度控制出错:{str(e)}")
return False
def close_serial(self):
"""关闭串口"""
try:
if self.serial_device and self.serial_device.is_open:
self.serial_device.close()
print("✅ 串口关闭成功")
return True
except Exception as e:
print(f"❌ 串口关闭失败:{str(e)}")
return False
def _get_mode_name(self, control_type):
"""
获取模式名称
:param control_type: 控制模式Control_Type.POS_VEl/VEL/MIT
"""
# 1.定义[枚举值--中文名称]的映射字典
mode_map = {
Control_Type.POS_VEL: "位置-速度模式",
Control_Type.VEL: "速度模式",
Control_Type.MIT: "MIT模式"
}
# 2.根据控制模式值获取中文名称 字典方法
return mode_map.get(control_type, "未知模式") # “未知模式”默认值
def save_param(self):
"""保存所有电机参数"""
try:
if self.motor is None:
raise ValueError("电机实例为None无法保存参数")
self.motor_control.save_motor_param(self.motor)
print("电机参数保存成功")
except Exception as e:
print(f"❌ 电机参数保存失败:{str(e)}")
def refresh_motor_status(self):
"""获得电机状态"""
try:
if self.motor is None:
raise ValueError("电机实例为None无法保存参数")
self.motor_control.refresh_motor_status(self.motor)
print("电机状态刷新成功")
except Exception as e:
print(f"❌ 电机状态刷新失败:{str(e)}")
def get_position(self):
"""获取电机位置"""
try:
if self.motor is None:
raise ValueError("电机实例为None无法保存参数")
position = self.motor.getPosition()
print(f"获取电机位置成功,当前位置: {position}")
return position
except Exception as e:
print(f"获取电机位置失败: {str(e)}")
def change_limit_param(self, motor_type, pmax, vmax, tmax):
"""
改变电机的PMAX VMAX TMAX
:param motor_type: 电机的类型
:param pmax: 电机的PMAX
:param vmax: 电机的VMAX
:param tmax: 电机的TAMX
"""
try:
self.motor_control.change_limit_param(motor_type, pmax, vmax, tmax)
print(
f"电机限位参数修改成功 | 类型: {motor_type} | PMAX: {pmax} | VMAX: {vmax} | TMAX: {tmax}"
)
except Exception as e:
print(f"修改电机限位参数失败: {str(e)}")
def __del__(self):
"""析构函数:确保程序退出时失能电机、关闭串口"""
try:
# 先检查串口是否打开,避免重复操作
if self.serial_device and self.serial_device.is_open:
self.disable_motor()
self.close_serial()
else:
# 串口已关闭,无需重复操作,仅打印日志
print(" 串口已关闭,析构函数无需重复释放资源")
except Exception as e:
print(f" 析构函数执行警告:{str(e)}")
def dm_motor_control():
# 1.创建电机控制器实例
motor_controller = DMMotorController(
slave_id=SLAVE_ID,
master_id=MASTER_ID,
port=PORT,
baudrate=BAUDRATE
)
try:
# 切换到位置-速度模式
motor_controller.switch_control_mode(Control_Type.POS_VEL)
# 使能电机
motor_controller.enable_motor()
# 循环控制电机
while True:
print("运动前的位置", motor_controller.get_position()) # 需要测试断电后是否能读取得到
motor_controller.control_pos_vel(p_desired=282.6, v_desired=30) # 450mm 665-215
time.sleep(20)
motor_controller.refresh_motor_status()
print("运动1的位置", motor_controller.get_position()) # 刷新的比较慢,可以等位置不变一段时间之后,再获取位置
motor_controller.refresh_motor_status()
motor_controller.control_pos_vel(p_desired=-282.6, v_desired=30)
time.sleep(20)
except KeyboardInterrupt:
print("\n⚠️ 用户手动停止程序")
except Exception as e:
print(f"\n❌ 程序运行出错:{str(e)}")
finally:
# 5. 无论是否出错,最终都要失能电机、关闭串口
motor_controller.disable_motor()
motor_controller.close_serial()
print("✅ 程序正常退出")
# ---------调试接口----------
if __name__ == '__main__':
dm_motor_control()