#!/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()