Kvaser CANlib库+python+QML,实现巡检机器人电机上位机开发

输电线路巡检机器人电机上位机开发(第一版)

目录

输电线路巡检机器人电机上位机开发(第一版)

项目概述

核心功能

技术架构

项目应用的具体对象

PyQt5框架

代码中的PyQt使用

1. 信号与槽机制

2. QObject基类

3. 属性系统

Qt信号机制实现实时数据更新

1.信号定义

2.私有属性与属性访问器

3.Qt属性定义

4. 实时数据更新流程

5.CAN消息接收和处理

6.信号与QML界面的集成

7.核心机制总结

线程的概念及主要特点

CAN消息接收需要多线程的理由

代码中的多线程实现

1. 线程的创建和启动

2. 线程函数实现

3. 线程间通信:PyQt信号机制

4. 线程终止

多线程实现的技术要点

1. 线程同步与资源竞争

2. 守护线程的使用

3. 异常处理和健壮性

4. 与QML界面集成

键盘过滤器

1.Python端的键盘过滤器实现

2.安装事件过滤器

3.QML端的键盘事件处理;

(1)全局快捷键

(2)焦点项的键盘事件处理

4.三层处理机制的优势

5.事件处理流程

上位机最终实际应用效果

项目完整代码展示

main.py

main.qml

Dianji_1.qml

Motor_Status_Chart.qml

项目代码存在的不足之处:

1. 代码重复严重

 2. 缺乏面向对象设计

3. 配置硬编码

4. 错误处理不完善

改进建议

1. 重构代码结构

2. 实现面向对象设计

创建电机基类和派生类:

封装CAN通信:

使用配置文件

改进UI组件复用

1. 创建可复用的电机控制面板组件:

2. 创建可复用的状态图表:

3.进一步改进想法

实现观察者模式监控电机状态

使用工厂模式创建电机对象

QML组件化和数据绑定优化

创建电机状态模型:

项目概述

这是一个基于Python和QML开发的综合性机器人电机控制系统,旨在通过CAN总线协议实现对多电机系统的精确控制和监控。该系统支持多达10个不同类型电机的同时控制,并提供了实时状态监测、数据可视化和紧急停止等功能,适用于各类巡检机器人和工业自动化设备。

核心功能

1. 多电机控制与管理:

   支持同时控制和监控10个不同型号、不同工作模式的电机;

   每个电机可独立配置工作模式(速度模式、位置模式、力矩模式、PWM模式);

   实时调整电机参数(速度、位置、电流、PWM占空比)。

2. 实时参数监测:

   监控电机速度、电流、位置等关键参数;

   数据实时更新和显示;

   异常状态检测和警报。

3. 位置保护系统:

   可配置的位置保护范围,防止电机超出安全运行范围;

   自动紧急停止功能,确保系统安全;

   位置超出范围时视觉警报提示。

4. 直观用户界面:

   采用QML开发的现代化图形界面;

   每个电机独立控制面板,支持标签页切换;

   实时数据图表可视化。

5. 手动控制功能:

   支持自定义CAN指令发送;

   紧急停止按钮(快捷键支持);

   电机使能/失能控制。

6. 数据可视化:

   电机参数实时曲线图;

   可缩放、拖动的图表界面;

   历史数据趋势分析。

技术架构

1. 前端界面:

   基于Qt/QML构建的响应式用户界面;

   独立的电机控制面板和状态显示;

   实时数据可视化组件。

2. 后端控制:

   Python基础架构,使用PyQt5框架;

   基于信号-槽机制的事件处理;

   多线程设计确保UI响应和数据采集同时进行。

3. 通信协议:

   基于CAN总线协议与电机驱动器通信;

   使用Kvaser CANlib库进行CAN通信;

   支持多种型号电机的特定通信指令。

4. 安全机制:

   位置限位保护;

   通信异常检测和恢复;

   一键急停功能(支持Ctrl键快捷触发)。

项目应用的具体对象

PyQt5框架

一个创建GUI应用程序的Python绑定库,它封装了Qt框架(C++库)。PyQt允许Python开发者使用Qt的全部功能创建桌面应用程序。(GUI 应用程序是指图形用户界面(Graphical User Interface)应用程序,它是一种通过视觉元素(如窗口、按钮、菜单、图标等)与用户交互的软件程序)

代码中的PyQt使用

1. 信号与槽机制

# 信号定义

current1Changed = pyqtSignal(int)  # 定义一个发送整数的信号

canMessageReceived = pyqtSignal(str, str)  # 定义带两个字符串参数的信号



# 槽函数定义

@pyqtSlot(int)

def enable_motor(self, motor_id: int) -> bool:

    # 实现槽函数

信号(Signal)是在特定事件发生时发出的通知,槽(Slot)是响应这些信号的函数。这种机制让GUI组件可以松散耦合。

2. QObject基类

class CanController(QObject):

# 类实现

QObject是PyQt中大多数类的基类,提供了信号与槽机制的支持。

3. 属性系统

# 定义属性

@pyqtProperty(int, notify=motor10SpeedChanged)

def motor10Speed(self):

    return self._motor10Speed

PyQt的属性系统允许将类属性暴露给Qt的元对象系统,可以在QML中使用,实现数据绑定。

Qt信号机制实现实时数据更新

Qt的信号机制是观察者模式的一种实现,CanController类利用此机制实现实时数据更新的流程如下:

1.信号定义

current1Changed = pyqtSignal(int)

motorSpeedChanged = pyqtSignal(int, int)  # 参数:(motor_id, speed)

motorPositionChanged = pyqtSignal(int, int)# 参数:(motor_id, position)

每个信号代表一种可能发生变化的数据,括号内的类型表示信号传递的参数类型。

2.私有属性与属性访问器

# 私有属性

self._current1 = 0

self._motorPosition = {}



# 属性访问器(getter和setter)

def get_current1(self):

    return self._current1



def set_current1(self, value):

    if self._current1 != value:

        self._current1 = value

        self.current1Changed.emit(value)

这里体现了数据变化触发信号发射的模式:私有变量存储实际数据;setter方法在数据变化时发射信号

3.Qt属性定义

current1 = pyqtProperty(int, get_current1, set_current1, notify=current1Changed)

motorPosition = pyqtProperty(int, lambda self: self._motorPosition.get(3, 0),  notify=motorPositionChanged)

pyqtProperty定义了Qt属性,它有几个关键参数:

类型:属性的数据类型

getter:读取属性值的函数

setter:设置属性值的函数(可选)

notify:属性值变化时发射的信号

这使得属性可以在QML中被绑定,当属性值变化时UI会自动更新。

4. 实时数据更新流程

以读取电机位置为例,整个数据流程是:

@pyqtSlot(int)

def read_motor_position(self, motor_id: int) -> int:

    # 省略CAN通信代码...

    

    # 当收到响应时,解析位置数据

    position = int.from_bytes(response.data[4:8], byteorder='little', signed=True)

    

    # 存储位置值

    self._motorPosition[motor_id] = position

    

    # 发射信号,通知UI组件位置已更新

    self.motorPositionChanged.emit(motor_id, position)

    

    # 更新特定电机的专用属性

    if motor_id == 4:

        self._motor4Position = position

        self.motor4PositionChanged.emit(motor_id, position)

这个流程展示了:从硬件获取数据、更新内部数据模型、发射信号通知UI更新

5.CAN消息接收和处理

def _receive_messages(self):

    while self.running:

        try:

            msg = self.ch.read(timeout=100)

            if msg:

                # 通知消息处理器

                for handler in self._message_handlers[:]:

                    handler(msg)

                

                # 发送原始CAN消息信号

                can_id = f"0x{msg.id:03X}"

                data = ' '.join([f"{x:02X}" for x in msg.data[:msg.dlc]])

                self.canMessageReceived.emit(can_id, data)

这个接收线程持续监听CAN总线,当收到消息时:通知所有已注册的消息处理器、发射信号将原始CAN消息传递给UI

6.信号与QML界面的集成

def updateMessage(self, can_id: str, data: str):

    # 使用QMetaObject在主线程中调用QML方法

    QMetaObject.invokeMethod(

        self.root_object,

        "addMessage",

        Qt.ConnectionType.QueuedConnection,

        Q_ARG(str, current_time),

        Q_ARG(str, can_id),

        Q_ARG(str, data)

    )

这个方法展示了如何从Python向QML发送数据,实现Python后端和QML前端的交互。

7.核心机制总结

CanController作为核心控制类实现实时数据更新的机制可以总结为:

信号定义:为每种可能变化的数据定义对应的信号

数据封装:使用私有变量存储数据,通过getter/setter控制访问

属性绑定:使用pyqtProperty将数据与信号关联,使QML能够绑定

数据获取:通过CAN通信从硬件获取最新数据

状态更新:数据变化时更新内部状态并发射信号

UI通知:信号被QML界面捕获,触发UI更新

这种设计使得数据流动是单向的、可预测的:硬件 → CanController → UI,同时UI响应是自动的,无需手动刷新

线程的概念及主要特点

线程是程序执行的最小单元,是操作系统能够进行运算调度的最小单位。一个进程可以包含多个线程,它们共享进程的资源(如内存空间),但有各自独立的执行路径。

线程的主要特点:

1.并发执行:多个线程可以同时执行不同的代码段;

2.共享资源:同一进程内的线程共享内存和文件句柄等资源;

3.轻量级:线程的创建和销毁比进程更轻量级;

4.独立的调度单位:操作系统可以独立调度每个线程。

CAN消息接收需要多线程的理由

在GUI应用程序中,主线程(又称UI线程)负责处理用户交互和界面更新。如果在主线程中执行耗时的I/O操作(如等待CAN消息),会导致界面卡顿,影响用户体验。

CAN通信的特点:

1.CAN消息接收是阻塞操作,需要等待消息到达;

2.CAN总线上的消息到达时间不确定;

3.需要连续监听CAN总线以捕获所有消息。

因此,将CAN消息接收放入单独的线程是一种解决方案。这样主线程可以继续处理UI事件,而接收线程可以专注于监听CAN总线。

代码中的多线程实现

1. 线程的创建和启动

@pyqtSlot()

def start_receiving(self):

    """启动CAN消息接收"""

    if not self.ch:

        print("CAN通道未初始化,无法启动接收线程")

        return



    if self._receive_thread and self._receive_thread.is_alive():

        print("接收线程已经在运行")

        return



    print("准备启动接收线程...")  # 添加调试信息

    import threading

    self.running = True

    self._receive_thread = threading.Thread(target=self._receive_messages)

    self._receive_thread.daemon = True

    self._receive_thread.start()

    print("CAN消息接收线程已启动")

关键步骤解析:

(1)创建线程对象:使用threading.Thread创建线程对象,并指定目标函数_receive_messages;

(2)设置守护线程:daemon=True表示这是一个守护线程,当主线程结束时,守护线程会自动终止;

(3)启动线程:start()方法启动线程,此时新线程开始执行_receive_messages函数;

2. 线程函数实现

def _receive_messages(self):

    """接收CAN消息的线程函数"""

    print("接收线程开始运行")

    while self.running:

        try:

            msg = self.ch.read(timeout=100)

            if msg:

                # 通知所有消息处理器

                for handler in self._message_handlers[:]:

                    try:

                        handler(msg)

                    except Exception as e:

                        print(f"消息处理器错误: {e}")



                # 处理并发送消息

                can_id = f"0x{msg.id:03X}"

                data_bytes = [f"{x:02X}" for x in msg.data[:msg.dlc]]

                data = ' '.join(data_bytes)

                self.canMessageReceived.emit(can_id, data)



        except canlib.CanNoMsg:

            continue

        except Exception as e:

            print(f"接收消息错误: {e}")

            import traceback

            print(traceback.format_exc())

            time.sleep(0.1)

关键步骤解析:

1.循环监听:使用while self.running循环持续监听CAN消息;

2.非阻塞读取:ch.read(timeout=100)设置100毫秒超时,防止完全阻塞;

3.消息处理:收到消息后,首先通知已注册的处理器,然后格式化消息内容;

4.信号发射:使用canMessageReceived.emit()将消息发送到主线程.

5.异常处理:

canlib.CanNoMsg异常表示暂时没有消息,继续循环;其他异常记录日志并短暂暂停,避免CPU占用过高

3. 线程间通信:PyQt信号机制

当接收线程收到CAN消息后,需要将数据传递给主线程处理。这里使用了PyQt的信号机制实现线程间通信:

# 信号定义

canMessageReceived = pyqtSignal(str, str)  # 参数:(can_id, data)



# 信号发射(在接收线程中)

self.canMessageReceived.emit(can_id, data)



# 信号处理(在主线程中)

def on_can_message(can_id, data):

    print(f"Python收到CAN消息: ID={can_id}, Data={data}")



controller.canMessageReceived.connect(on_can_message)

PyQt信号机制的特点:

1.线程安全:PyQt信号是线程安全的,允许从任何线程发射信号;

2.队列处理:信号会被放入队列中,由接收端线程(通常是主线程)处理;

3.解耦合:发送方不需要知道接收方是谁,实现了代码解耦。

4. 线程终止

def cleanup(self):

    self.running = False

    if self._receive_thread:

        self._receive_thread.join(timeout=1.0)

    if self.ch:

        self.ch.busOff()

        self.ch.close()

        print("CAN通道已关闭")

关键步骤解析:

1.设置标志:设置self.running = False使接收线程跳出循环;

2.等待终止:join(timeout=1.0)等待线程最多1秒钟终止;

3.资源释放:关闭CAN通道,释放资源。

多线程实现的技术要点

1. 线程同步与资源竞争

当多个线程访问共享资源时,需要注意线程同步问题。在代码中:使用切片复制消息处理器列表,避免迭代时修改:for handler in self._message_handlers[:]

使用PyQt信号机制传递数据,避免直接操作UI元素

2. 守护线程的使用

self._receive_thread.daemon = True

守护线程的特点是当主线程结束时自动终止。这确保了即使接收线程卡在某个位置,也不会阻止程序退出。

3. 异常处理和健壮性

代码中包含了多层异常处理:

1.捕获特定的canlib.CanNoMsg异常,区分正常无消息和异常情况;

2.捕获并记录消息处理器的异常,防止一个处理器失败影响整体功能;

3.捕获一般异常并记录堆栈跟踪,方便调试。

4. 与QML界面集成

接收线程收到消息后,通过canMessageReceived信号将数据传递给主线程,然后在主线程中使用QMetaObject.invokeMethod调用QML方法:

QMetaObject.invokeMethod(

    self.root_object,

    "addMessage",

    Qt.ConnectionType.QueuedConnection,

    Q_ARG(str, current_time),

    Q_ARG(str, can_id),

    Q_ARG(str, data)

)

这确保了QML操作在主线程中执行,避免了多线程访问UI的问题。

键盘过滤器

键盘过滤器是PyQt和QML中处理键盘输入的重要机制,在这个机器人控制系统中,它主要用于捕获Ctrl键作为紧急停止功能。该系统实现了三层键盘事件处理机制,提供了冗余保障,确保关键的紧急停止功能能够被可靠触发。

1.Python端的键盘过滤器实现

在Python端,键盘过滤器通过继承QObject并实现eventFilter方法来创建:

class KeyFilter(QObject):

    def __init__(self, controller):

        super().__init__()

        self.controller = controller



    def eventFilter(self, obj, event):

        if event.type() == event.KeyPress:

            if event.key() == Qt.Key_Control:

                print("Ctrl key pressed through event filter")

                self.controller.emergency_stop()

                return True

        return False

这个过滤器的关键组成部分包括:

1.继承QObject:所有事件过滤器都必须继承QObject

2.初始化:保存对控制器对象的引用,以便调用其方法

3.eventFilter方法:接收两个参数:被监听的对象和事件;检查事件类型是否为KeyPress;检查按键是否为Ctrl键;如果满足条件,调用紧急停止功能并返回True表示事件已被处理;否则返回False让事件继续传播

2.安装事件过滤器

在Python端,事件过滤器需要被安装到窗口和应用程序对象上才能生效:

key_filter = KeyFilter(controller)

window.installEventFilter(key_filter)

app.installEventFilter(key_filter)

这里使用了两层安装:

1.安装到窗口对象:捕获窗口内的按键事件;

2.安装到应用程序对象:捕获应用程序范围内的按键事件,即使窗口没有焦点

3.QML端的键盘事件处理;

在QML端,实现了两种不同的键盘事件处理机制:

(1)全局快捷键
Shortcut {

    sequences: [StandardKey.Cancel, "Ctrl"]  // 同时监听Cancel和Ctrl键

    context: Qt.ApplicationShortcut  // 设置为应用程序级快捷键

    onActivated: {

        console.log("Ctrl key pressed - Emergency Stop triggered")

        controller.emergency_stop()

    }

}

Shortcut是QML中处理快捷键的高级组件:sequences定义了触发快捷键的按键序列

context设置为应用程序级别,使其在整个应用中都有效

onActivated处理快捷键被触发时的动作

2焦点项的键盘事件处理
Item {

    focus: true

    Keys.onPressed: function(event) {

        if (event.key === Qt.Key_Control) {

            console.log("Control key pressed via Keys handler")

            controller.emergency_stop();

            event.accepted = true;

        }

    }

}

这种方式使用了QML的Item对象和Keys附加属性:

focus: true确保该Item可以接收键盘焦点;Keys.onPressed定义按键按下时的处理函数;检查是否为Ctrl键,并相应地调用紧急停止功能;event.accepted = true表示事件已被处理,防止传播

4.三层处理机制的优势

这个系统实现了三层键盘事件处理:

1.Python端的事件过滤器(窗口级别);

2.Python端的事件过滤器(应用程序级别);

3.QML端的两种不同机制(Shortcut和Keys处理)。

这种冗余设计确保了:

1.无论用户界面处于什么状态,紧急停止功能都能被触发;

2.即使某一层处理机制失效,其他层仍能捕获关键事件;

3.适应不同的操作系统和窗口管理器行为差异。

5.事件处理流程

当用户按下Ctrl键时,事件处理的流程如下:

1.事件首先进入应用程序的事件循环;

2.应用程序级别的事件过滤器获得处理机会;

3.如果应用程序级别没有处理,窗口级别的事件过滤器获得处理机会;

4.如果窗口级别没有处理,QML的Shortcut组件检查是否匹配;

5.最后,如果事件仍未被处理,且焦点Item可见,则Keys.onPressed获得处理机会。

这种多层次的事件处理确保了关键安全功能的可靠性,无论界面处于什么状态,紧急停止功能都可以被触发,保障机器人系统的安全运行

上位机最终实际应用效果

项目完整代码展示

main.py

from PyQt5.QtCore import QUrl, pyqtSlot, QObject, pyqtProperty, pyqtSignal, QMetaObject, Qt, Q_ARG, QTimer
from PyQt5.QtWidgets import QApplication
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QShortcut
from canlib import canlib
import sys
import os
import time
from PyQt5.QtQml import QQmlApplicationEngine


class CanController(QObject):
    # 添加信号定义
    current1Changed = pyqtSignal(int)
    current2Changed = pyqtSignal(int)
    canMessageReceived = pyqtSignal(str, str)  # 参数:(can_id, data)
    workModeChanged = pyqtSignal(str)  # 参数:(work_mode)
    averageSpeed1Changed = pyqtSignal(int)
    averageSpeed2Changed = pyqtSignal(int)
    speedError1Changed = pyqtSignal(int)
    speedError2Changed = pyqtSignal(int)
    setSpeed1Changed = pyqtSignal(int)
    setSpeed2Changed = pyqtSignal(int)
    positionErrorChanged = pyqtSignal(int)
    currentPositionChanged = pyqtSignal(int)
    workMode1Changed = pyqtSignal(str)  # 电机1工作模式信号
    workMode2Changed = pyqtSignal(str)  # 电机2工作模式信号
    # 添加新的信号
    motorSpeedChanged = pyqtSignal(int, int)  # 参数:(motor_id, speed)
    motorPwmChanged = pyqtSignal(int, int)    # 参数:(motor_id, pwm)
    motorCurrentChanged = pyqtSignal(int, int) # 参数:(motor_id, current)
    motorPositionChanged = pyqtSignal(int, int)# 参数:(motor_id, position)

    # 为电机4、5、6添加信号
    motor4SpeedChanged = pyqtSignal(int, int)
    motor4PwmChanged = pyqtSignal(int, int)
    motor4CurrentChanged = pyqtSignal(int, int)
    motor4PositionChanged = pyqtSignal(int, int)

    motor5SpeedChanged = pyqtSignal(int, int)
    motor5PwmChanged = pyqtSignal(int, int)
    motor5CurrentChanged = pyqtSignal(int, int)
    motor5PositionChanged = pyqtSignal(int, int)

    motor6SpeedChanged = pyqtSignal(int, int)
    motor6PwmChanged = pyqtSignal(int, int)
    motor6CurrentChanged = pyqtSignal(int, int)
    motor6PositionChanged = pyqtSignal(int, int)

    # 添加区分的信号
    positionError1Changed = pyqtSignal(int)
    positionError2Changed = pyqtSignal(int)
    currentPosition1Changed = pyqtSignal(int)
    currentPosition2Changed = pyqtSignal(int)

    # 添加新的信号
    motorSpeedModeStatusChanged = pyqtSignal(int, bool)  # 电机ID, 是否为速度模式
    motorEnableStatusChanged = pyqtSignal(int, bool)     # 电机ID, 是否使能

    # 添加力矩模式相关信号
    motorTorqueModeStatusChanged = pyqtSignal(int, bool)  # 电机ID, 是否为力矩模式
    motorMaxSpeedChanged = pyqtSignal(int, int)           # 电机ID, 最大速度值
    motorTargetCurrentChanged = pyqtSignal(int, int)      # 电机ID, 目标电流值

    motor7SpeedChanged = pyqtSignal(int, int)
    motor7CurrentChanged = pyqtSignal(int, int)
    motor7PositionChanged = pyqtSignal(int, int)

    # 1. 添加电机8的信号
    motor8SpeedChanged = pyqtSignal(int, int)
    motor8CurrentChanged = pyqtSignal(int, int)
    motor8PositionChanged = pyqtSignal(int, int)

    # 2. 添加电机9的信号
    motor9SpeedChanged = pyqtSignal(int, int)
    motor9CurrentChanged = pyqtSignal(int, int)
    motor9PositionChanged = pyqtSignal(int, int)

    # 3. 添加电机10的信号
    motor10SpeedChanged = pyqtSignal(int, int)
    motor10CurrentChanged = pyqtSignal(int, int)
    motor10PositionChanged = pyqtSignal(int, int)

    # 添加新的信号
    positionOutOfRangeError = pyqtSignal(int, int)  # 参数:(motor_id, current_position)

    def __init__(self):
        super().__init__()
        self.ch = None
        # 添加电流值属性的私有变量
        self._current1 = 0
        self._current2 = 0
        # 定义电机CAN ID字典
        self.MOTOR_IDS = {
            1: 0x88,  # 电机1的CAN ID
            2: 0x99,  # 电机2的CAN ID
            3: 0x655,  # 电机3的CAN ID
            4: 0x644,  # 电机4的CAN ID
            5: 0x666,  # 电机5的CAN ID
            6: 0x611,  # 电机6的CAN ID
            7: 0x656,  # 电机7的CAN ID
            8: 0x661,  # 电机8的CAN ID
            9: 0x680,  # 电机9的CAN ID
            10: 0x648,  # 电机10的CAN ID
        }
        self.running = False  # 用于控制接收线程
        self._receive_thread = None
        print("CanController 初始化完成")  # 添加调试信息
        # 添加新的属性
        self._average_speed = 0
        self._speed_error = 0
        self._set_speed = 0
        # 添加新的属性定义
        self._averageSpeed1 = 0
        self._averageSpeed2 = 0
        self._speedError1 = 0
        self._speedError2 = 0
        self._setSpeed1 = 0
        self._setSpeed2 = 0
        self._positionError = 0
        self._currentPosition = 0
        self._message_handlers = []  # 添加消息处理器列表
        self._workMode1 = "未初始化"
        self._workMode2 = "未初始化"
        # 添加新的属性
        self._motorSpeed = {}
        self._motorPwm = {}
        self._motorCurrent = {}
        self._motorPosition = {}

        # 添加新的属性
        self._motor4Speed = 0
        self._motor4Pwm = 0
        self._motor4Current = 0
        self._motor4Position = 0

        self._motor5Speed = 0
        self._motor5Pwm = 0
        self._motor5Current = 0
        self._motor5Position = 0

        self._motor6Speed = 0
        self._motor6Pwm = 0
        self._motor6Current = 0
        self._motor6Position = 0

        # 添加区分的属性
        self._positionError1 = 0
        self._positionError2 = 0
        self._currentPosition1 = 0
        self._currentPosition2 = 0

        # 添加属性初始化
        self._motor7Speed = 0
        self._motor7Current = 0
        self._motor7Position = 0

        # 3. 添加电机8的属性
        self._motor8Speed = 0
        self._motor8Current = 0
        self._motor8Position = 0

        # 4. 添加电机9的属性
        self._motor9Speed = 0
        self._motor9Current = 0
        self._motor9Position = 0

        # 5. 添加电机10的属性
        self._motor10Speed = 0
        self._motor10Current = 0
        self._motor10Position = 0

        # 添加位置保护范围常量
        self.POSITION_MIN = 150000
        self.POSITION_MAX = 350000
        
        # 添加位置保护标志
        self._position_protection_enabled = True
        
        # 添加位置监控定时器
        self._position_monitor_timer = QTimer(self)
        self._position_monitor_timer.setInterval(100)  # 100ms检查一次
        self._position_monitor_timer.timeout.connect(self._check_motors_position)
        self._position_monitor_timer.start()
        
        self._monitoring_enabled = True  # 添加监控状态标志
    
    # 添加属性的 getter 和 setter
    def get_current1(self):
        return self._current1

    def set_current1(self, value):
        if self._current1 != value:
            self._current1 = value
            self.current1Changed.emit(value)

    def get_current2(self):
        return self._current2

    def set_current2(self, value):
        if self._current2 != value:
            self._current2 = value
            self.current2Changed.emit(value)

    # 添加 Property 定义
    current1 = pyqtProperty(int, get_current1, set_current1, notify=current1Changed)
    current2 = pyqtProperty(int, get_current2, set_current2, notify=current2Changed)
    averageSpeed1 = pyqtProperty(int, lambda self: self._averageSpeed1, notify=averageSpeed1Changed)
    averageSpeed2 = pyqtProperty(int, lambda self: self._averageSpeed2, notify=averageSpeed2Changed)
    speedError1 = pyqtProperty(int, lambda self: self._speedError1, notify=speedError1Changed)
    speedError2 = pyqtProperty(int, lambda self: self._speedError2, notify=speedError2Changed)
    setSpeed1 = pyqtProperty(int, lambda self: self._setSpeed1, notify=setSpeed1Changed)
    setSpeed2 = pyqtProperty(int, lambda self: self._setSpeed2, notify=setSpeed2Changed)
    positionError = pyqtProperty(int, lambda self: self._positionError, notify=positionErrorChanged)
    currentPosition = pyqtProperty(int, lambda self: self._currentPosition, notify=currentPositionChanged)
    @pyqtProperty(str, notify=workMode1Changed)
    def workMode1(self):
        return self._workMode1

    @pyqtProperty(str, notify=workMode2Changed)
    def workMode2(self):
        return self._workMode2

    # 添加属性方法
    @pyqtProperty(int, notify=motorSpeedChanged)
    def motorSpeed(self):
        return self._motorSpeed.get(3, 0)  # 默认返回电机3的速度

    @pyqtProperty(int, notify=motorPwmChanged)
    def motorPwm(self):
        return self._motorPwm.get(3, 0)    # 默认返回电机3的PWM

    @pyqtProperty(int, notify=motorCurrentChanged)
    def motorCurrent(self):
        return self._motorCurrent.get(3, 0) # 默认返回电机3的电流

    @pyqtProperty(int, notify=motorPositionChanged)
    def motorPosition(self):
        return self._motorPosition.get(3, 0) # 默认返回电机3的位置

    # 电机4的属性访问器
    @pyqtProperty(int, notify=motor4SpeedChanged)
    def motor4Speed(self):
        return self._motor4Speed

    @pyqtProperty(int, notify=motor4PwmChanged)
    def motor4Pwm(self):
        return self._motor4Pwm

    @pyqtProperty(int, notify=motor4CurrentChanged)
    def motor4Current(self):
        return self._motor4Current

    @pyqtProperty(int, notify=motor4PositionChanged)
    def motor4Position(self):
        return self._motor4Position

    # 电机5的属性访问器
    @pyqtProperty(int, notify=motor5SpeedChanged)
    def motor5Speed(self):
        return self._motor5Speed

    @pyqtProperty(int, notify=motor5PwmChanged)
    def motor5Pwm(self):
        return self._motor5Pwm

    @pyqtProperty(int, notify=motor5CurrentChanged)
    def motor5Current(self):
        return self._motor5Current

    @pyqtProperty(int, notify=motor5PositionChanged)
    def motor5Position(self):
        return self._motor5Position

    # 电机6的属性访问器
    @pyqtProperty(int, notify=motor6SpeedChanged)
    def motor6Speed(self):
        return self._motor6Speed

    @pyqtProperty(int, notify=motor6PwmChanged)
    def motor6Pwm(self):
        return self._motor6Pwm

    @pyqtProperty(int, notify=motor6CurrentChanged)
    def motor6Current(self):
        return self._motor6Current

    @pyqtProperty(int, notify=motor6PositionChanged)
    def motor6Position(self):
        return self._motor6Position

    # 添加区分的属性访问器
    @pyqtProperty(int, notify=positionError1Changed)
    def positionError1(self):
        return self._positionError1

    @pyqtProperty(int, notify=positionError2Changed)
    def positionError2(self):
        return self._positionError2

    @pyqtProperty(int, notify=currentPosition1Changed)
    def currentPosition1(self):
        return self._currentPosition1

    @pyqtProperty(int, notify=currentPosition2Changed)
    def currentPosition2(self):
        return self._currentPosition2

    @pyqtProperty(int, notify=motor7SpeedChanged)
    def motor7Speed(self):
        return self._motor7Speed

    @pyqtProperty(int, notify=motor7CurrentChanged)
    def motor7Current(self):
        return self._motor7Current

    @pyqtProperty(int, notify=motor7PositionChanged)
    def motor7Position(self):
        return self._motor7Position

    # 4. 添加电机8的属性访问器
    @pyqtProperty(int, notify=motor8SpeedChanged)
    def motor8Speed(self):
        return self._motor8Speed

    @pyqtProperty(int, notify=motor8CurrentChanged)
    def motor8Current(self):
        return self._motor8Current

    @pyqtProperty(int, notify=motor8PositionChanged)
    def motor8Position(self):
        return self._motor8Position

    # 4. 添加电机9的属性访问器
    @pyqtProperty(int, notify=motor9SpeedChanged)
    def motor9Speed(self):
        return self._motor9Speed
    
    @pyqtProperty(int, notify=motor9CurrentChanged)
    def motor9Current(self):
        return self._motor9Current
    
    @pyqtProperty(int, notify=motor9PositionChanged)
    def motor9Position(self):
        return self._motor9Position
    
    # 5. 添加电机10的属性访问器
    @pyqtProperty(int, notify=motor10SpeedChanged)
    def motor10Speed(self):
        return self._motor10Speed
    
    @pyqtProperty(int, notify=motor10CurrentChanged)
    def motor10Current(self):
        return self._motor10Current
    
    @pyqtProperty(int, notify=motor10PositionChanged)
    def motor10Position(self):
        return self._motor10Position    
    
    @pyqtSlot()
    def initialize_can(self):
        """初始化CAN通道"""
        try:
            # 获取可用的CAN通道数量
            num_channels = canlib.getNumberOfChannels()
            print(f"发现 {num_channels} 个CAN通道")

            # 打开通道0
            self.ch = canlib.openChannel(channel=0)
            # 设置比特率为1M
            self.ch.setBusParams(canlib.canBITRATE_1M)
            # 启动CAN通道
            self.ch.busOn()

            print("CAN通道已初始化成功")

            # 发送一个测试信号
            self.canMessageReceived.emit("测试", "测试数据")

            # 启动接收线程
            self.start_receiving()

            # 初始化后立即读取电机1和电机2的工作模式
            print("正在读取电机工作模式...")
            self.read_work_mode(1)  # 读取电机1工作模式
            self.read_work_mode(2)  # 读取电机2工作模式

            return True
        except Exception as e:
            print(f"初始化错误: {e}")
            return False

    @pyqtSlot()
    def start_receiving(self):
        """启动CAN消息接收"""
        if not self.ch:
            print("CAN通道未初始化,无法启动接收线程")
            return

        if self._receive_thread and self._receive_thread.is_alive():
            print("接收线程已经在运行")
            return

        print("准备启动接收线程...")  # 添加调试信息
        import threading
        self.running = True
        self._receive_thread = threading.Thread(target=self._receive_messages)
        self._receive_thread.daemon = True
        self._receive_thread.start()
        print("CAN消息接收线程已启动")

    def _receive_messages(self):
        """接收CAN消息的线程函数"""
        print("接收线程开始运行")
        while self.running:
            try:
                msg = self.ch.read(timeout=100)
                if msg:
                    # 通知所有消息处理器
                    for handler in self._message_handlers[:]:  # 使用切片复制避免迭代时修改
                        try:
                            handler(msg)
                        except Exception as e:
                            print(f"消息处理器错误: {e}")

                    # 原有的消息处理逻辑
                    can_id = f"0x{msg.id:03X}"
                    data_bytes = [f"{x:02X}" for x in msg.data[:msg.dlc]]
                    data = ' '.join(data_bytes)

                    print(f"收到原始CAN消息 - ID: {can_id}, DLC: {msg.dlc}, Raw Data: {[hex(x) for x in msg.data]}")
                    print(f"格式化后的消息 - ID: {can_id}, Data: {data}")

                    # 对于 PyQt5,直接使用信号发送更简单
                    self.canMessageReceived.emit(can_id, data)

                    print(f"CAN消息已发送 - ID: {can_id}, Data: {data}")

            except canlib.CanNoMsg:
                continue
            except Exception as e:
                print(f"接收消息错误: {e}")
                import traceback
                print(traceback.format_exc())
                time.sleep(0.1)

    @pyqtSlot(str, str)
    def updateMessage(self, can_id: str, data: str):
        """在主线程中更新消息"""
        try:
            print(f"准备发送信号到QML - ID: {can_id}, Data: {data}")
            # 添加时间戳
            current_time = time.strftime("%H:%M:%S", time.localtime())
            # 使用 QMetaObject 在主线程中调用 QML 方法
            QMetaObject.invokeMethod(
                self.root_object,  # 需要添加 root_object 属性
                "addMessage",
                Qt.ConnectionType.QueuedConnection,
                Q_ARG(str, current_time),
                Q_ARG(str, can_id),
                Q_ARG(str, data)
            )
            print(f"信号已发送到QML")
        except Exception as e:
            print(f"发送信号错误: {e}")
            import traceback
            print(traceback.format_exc())

    def set_root_object(self, root):
        """设置 QML root object"""
        self.root_object = root



    #电机1和2相关底层python配置——开始
    @pyqtSlot(int, int)
    def set_work_mode(self, motor_id: int, mode: int) -> bool:
        """
        设置电机工作模式
        Args:
            motor_id: 电机ID
            mode: 工作模式 (0:速度模式, 1:位置模式, 2:力矩模式)
        """
        if not self.ch:
            print("CAN通道未初始化")
            return False
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x08, 0x88, 0x2A, 0x00, 0x00, mode, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            
            mode_names = {0: "速度", 1: "位置", 2: "力矩"}
            print(f"电机{motor_id}已设置为{mode_names.get(mode, '未知')}模式")
            return True
            
        except Exception as e:
            print(f"设置工作模式失败: {e}")
            return False
    
    def _set_motor_current(self, motor_id: int, current_ma: int) -> bool:
        """通用的电机电流设置方法"""
        if not self.ch:
            print("CAN通道未初始化")
            return False

        if motor_id not in self.MOTOR_IDS:
            print(f"无效的电机ID: {motor_id}")
            return False

        try:
            can_id = self.MOTOR_IDS[motor_id]

            # 将电流值转换为CAN数据格式
            if current_ma >= 0:
                # 正电流值处理
                high_byte = current_ma // 256
                low_byte = current_ma % 256
                data = [0x08, 0x88, 0x96, 0x00, low_byte, high_byte, 0x00, 0x00]
            else:
                # 负电流值处理
                abs_current = abs(current_ma)
                high_byte = 0xFF - (abs_current - 1) // 256
                remainder = abs_current - (0xFF - high_byte) * 256
                low_byte = 256 - remainder
                data = [0x08, 0x88, 0x96, 0x00, low_byte, high_byte, 0xFF, 0xFF]

            # 发送CAN指令
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"行走轮{motor_id}电流设置为: {current_ma}mA")

            # 打印十六进制数据用于调试
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")

            return True

        except canlib.CanError as e:
            print(f"发送消息失败: {e}")
            return False

    @pyqtSlot(int)
    def set_wheel_current(self, current_ma):
        """设置电机1的电流"""
        self._set_motor_current(1, current_ma)

    @pyqtSlot(int)
    def set_wheel2_current(self, current_ma):
        """设置电机2的电流"""
        self._set_motor_current(2, current_ma)

    def _read_motor_current(self, motor_id: int) -> int:
        """
        读取指定电机的实时电流值
        """
        if not self.ch:
            print("CAN通道未初始化")
            return 0

        if motor_id not in self.MOTOR_IDS:
            print(f"无效的电机ID: {motor_id}")
            return 0

        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x04, 0x88, 0xD0, 0x00]
            print(f"发送读取电流指令: {[f'0x{x:02X}' for x in data]}")
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=4)

            response_id = 0x01

            timeout_ms = 500
            start_time = time.time()
            while (time.time() - start_time) * 1000 < timeout_ms:
                try:
                    msg = self.ch.read(timeout=10)
                    print(f"收到CAN消息 - ID: 0x{msg.id:X}, 数据: {[f'0x{x:02X}' for x in msg.data]}")

                    if msg.id == response_id:
                        # 解析电流值
                        low_byte = msg.data[4]
                        high_byte = msg.data[5]

                        if high_byte == 0xFF:  # 负值
                            current = -(256 - low_byte)
                        elif high_byte > 0xF0:  # 的负值
                            current = -((0xFF - high_byte) * 256 + (256 - low_byte))
                        else:  # 正值
                            current = low_byte + high_byte * 256

                        print(f"电机{motor_id}当前电流: {current}mA")
                        return current
                except canlib.CanNoMsg:
                    continue

            print(f"读取电机{motor_id}电流时 - 未收到响应")
            return 0

        except canlib.CanError as e:
            print(f"读取电流失败: {e}")
            return 0

    @pyqtSlot(int, result=int)
    def read_wheel_current(self, motor_id):
        """读取指定电机的电流值,供QML调用"""
        current = self._read_motor_current(motor_id)
        # 更新对应的属性
        if motor_id == 1:
            self.set_current1(current)
        elif motor_id == 2:
            self.set_current2(current)
        return current

    @pyqtSlot(int, str, result=bool)
    def send_custom_can_command(self, can_id: int, hex_string: str) -> bool:
        """
        发送自定义CAN指令
        """
        if not self.ch:
            print("CAN通道未初始化")
            return False

        try:
            # 解析十六进制字符串
            hex_values = hex_string.strip().split()
            if len(hex_values) > 8:
                print("数据长度超过8字节")
                return False

            # 转换为字节数组
            data = []
            for hex_val in hex_values:
                try:
                    data.append(int(hex_val, 16))
                except ValueError:
                    print(f"无效的十六进制值: {hex_val}")
                    return False

            # 获取实际数据长度
            dlc = len(data)

            # 发送CAN指令
            self.ch.write_raw(id_=can_id, msg=data, dlc=dlc)

            # 打印调试信息
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送自定义CAN指令 ID: 0x{can_id:X}, DLC: {dlc}, 数据: {hex_data}")
            return True

        except canlib.CanError as e:
            print(f"发送消息失败: {e}")
            return False


    @pyqtSlot(int)
    def read_work_mode(self, motor_id: int) -> str:
        """
        读取电机驱动器的工作模式和信号源
        """
        if not self.ch:
            print("CAN通道未初始化")
            return "未初始化"

        if motor_id not in self.MOTOR_IDS:
            print(f"无效的电机ID: {motor_id}")
            return "无效电机ID"

        try:
            can_id = self.MOTOR_IDS[motor_id]
            # 发送读取工作模式指令
            data = [0x04, 0x88, 0x2B, 0x00]
            print(f"发送读取工作模式指令: {[f'0x{x:02X}' for x in data]}")
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=4)

            # 等待响应
            timeout_ms = 500
            start_time = time.time()
            while (time.time() - start_time) * 1000 < timeout_ms:
                try:
                    msg = self.ch.read(timeout=10)
                    print(f"收到CAN消息 - ID: 0x{msg.id:X}, 数据: {[f'0x{x:02X}' for x in msg.data]}")

                    if msg.id == 0x01:  # 假设响应ID为0x01,需要根据实际情况调整
                        # 解析信号源(第5字节)
                        source_byte = msg.data[4]
                        source = "数字指令" if source_byte == 0x00 else f"未知信号源(0x{source_byte:02X})"
                        
                        # 解析工作模式(第6字节)
                        mode_byte = msg.data[5]
                        modes = {
                            0x00: "速度控制模式",
                            0x01: "位置控制模式",
                            0x02: "电流控制模式"
                        }
                        mode = modes.get(mode_byte, f"未知模式(0x{mode_byte:02X})")
                        
                        # 在返回结果时添加电机编号
                        result = f"电机{motor_id} - {mode}, 信号源: {source}"
                        print(f"电机{motor_id} - {result}")
                        if motor_id == 1:
                            self._workMode1 = result
                            self.workMode1Changed.emit(result)
                        else:
                            self._workMode2 = result
                            self.workMode2Changed.emit(result)
                        return result

                except canlib.CanNoMsg:
                    continue

            print(f"读取电机{motor_id}工作模式超时")
            return "读取超时"

        except canlib.CanError as e:
            print(f"读取工作模式失败: {e}")
            return f"读取错误: {str(e)}"
    
    @pyqtSlot(int, int)
    def set_motor_speed(self, motor_id: int, speed: int) -> bool:
        """设置电机速度"""
        if not self.ch:
            print("CAN通道未初始化")
            return False

        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            # 将速度值转换为CAN数据格式
            if speed >= 0:
                # 正速度值处理
                high_byte = speed // 256
                low_byte = speed % 256
                data = [0x08, 0x88, 0x90, 0x00, low_byte, high_byte, 0x00, 0x00]
            else:
                # 负速度值处理
                abs_speed = abs(speed)
                high_byte = 0xFF - (abs_speed - 1) // 256
                remainder = abs_speed - (0xFF - high_byte) * 256
                low_byte = 256 - remainder
                data = [0x08, 0x88, 0x90, 0x00, low_byte, high_byte, 0xFF, 0xFF]
            
            # 发送CAN指令
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}速度设置为: {speed}")
            
            # 打印十六进制数据用于调试
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            
            return True
        except canlib.CanError as e:
            print(f"设置速度失败: {e}")
            return False

    @pyqtSlot(int)
    def read_average_speed(self, motor_id: int) -> int:
        """读取平均速度"""
        if not self.ch:
            print("CAN通道未初始化")
            return 0
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x04, 0x88, 0x91, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=4)
            
            response = self._wait_for_response()
            if response:
                # 修改速度值的解析逻辑
                low_byte = response.data[4]
                high_byte = response.data[5]
                
                # 处理负值的情况
                if high_byte > 0x7F:  # 最高位为1表示负数
                    speed = -((0xFF - high_byte) * 256 + (256 - low_byte))
                else:
                    speed = low_byte + (high_byte << 8)
                    
                if motor_id == 1:
                    self._averageSpeed1 = speed
                    self.averageSpeed1Changed.emit(speed)
                else:
                    self._averageSpeed2 = speed
                    self.averageSpeed2Changed.emit(speed)
                return speed
            return 0
        except canlib.CanError as e:
            print(f"读取平均速度失败: {e}")
            return 0

    @pyqtSlot(int)
    def read_speed_error(self, motor_id: int) -> int:
        """读取速度误差"""
        if not self.ch:
            print("CAN通道未初始化")
            return 0
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x04, 0x88, 0x92, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=4)
            
            response = self._wait_for_response()
            if response:
                # 修改误差值的解析逻辑
                low_byte = response.data[4]
                high_byte = response.data[5]
                
                # 处理负值的情况
                if high_byte > 0x7F:  # 最高位为1表示负数
                    error = -((0xFF - high_byte) * 256 + (256 - low_byte))
                else:
                    error = low_byte + (high_byte << 8)
                    
                if motor_id == 1:
                    self._speedError1 = error
                    self.speedError1Changed.emit(error)
                else:
                    self._speedError2 = error
                    self.speedError2Changed.emit(error)
                return error
            return 0
        except canlib.CanError as e:
            print(f"读取速度误差失败: {e}")
            return 0

    @pyqtSlot(int)
    def set_absolute_position_origin(self, motor_id: int) -> bool:
        """设置当前位置为绝对位置原点"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x08, 0x88, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}设置绝对位置原点")
            return True
        except canlib.CanError as e:
            print(f"设置绝对位置原点失败: {e}")
            return False

    @pyqtSlot(int, int)
    def move_to_absolute_position(self, motor_id: int, position: int) -> bool:
        """设置电机向绝对位置运动"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            if position >= 0:
                # 正数:直接转换为32位值,注意字节顺序
                byte3 = 0x00                          # 最高字节始终为0
                byte2 = (position >> 16) & 0xFF       # 次高字节
                byte1 = (position >> 8) & 0xFF        # 次低字节
                byte0 = position & 0xFF               # 最低字节
            else:
                # 负数:特殊处理方式
                abs_val = abs(position)
                
                # 计算补码(修正后的转换规则)
                byte0 = (~abs_val + 1) & 0xFF               # 最低字节
                byte1 = ((~abs_val + 1) >> 8) & 0xFF        # 次低字节
                byte2 = ((~abs_val + 1) >> 16) & 0xFF       # 次高字节
                byte3 = ((~abs_val + 1) >> 24) & 0xFF       # 最高字节
            
            # 组装CAN消息数据
            data = [0x08, 0x88, 0x9A, 0x00, byte0, byte1, byte2, byte3]
            
            # 发送CAN消息
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}移动到绝对位置: {position}")
            
            # 调试信息:打印十六进制数据
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            
            return True
        except canlib.CanError as e:
            print(f"移动到绝对位置失败: {e}")
            return False

    @pyqtSlot(int, int)
    def move_by_relative_position(self, motor_id: int, position: int) -> bool:
        """设置电机移动相对位置"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            if position >= 0:
                # 正数:直接转换为32位值,注意字节顺序
                byte3 = 0x00                          # 最高字节始终为0
                byte2 = (position >> 16) & 0xFF       # 次高字节
                byte1 = (position >> 8) & 0xFF        # 次低字节
                byte0 = position & 0xFF               # 最低字节
            else:
                # 负数:特殊处理方式
                abs_val = abs(position)
                
                # 计算补码(修正后的转换规则)
                byte0 = (~abs_val + 1) & 0xFF               # 最低字节
                byte1 = ((~abs_val + 1) >> 8) & 0xFF        # 次低字节
                byte2 = ((~abs_val + 1) >> 16) & 0xFF       # 次高字节
                byte3 = ((~abs_val + 1) >> 24) & 0xFF       # 最高字节
            
            # 组装CAN消息数据
            data = [0x08, 0x88, 0x9A, 0x00, byte0, byte1, byte2, byte3]
            
            # 发送CAN消息
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}移动相对位置: {position}")
            
            # 调试信息:打印十六进制数据
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            
            return True
        except canlib.CanError as e:
            print(f"移动相对位置失败: {e}")
            return False
    
    @pyqtSlot(int)
    def read_current_position(self, motor_id: int) -> int:
        """读取电机实际位置"""
        if not self.ch:
            print("CAN通道未初始化")
            return 0
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x04, 0x88, 0x9B, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=4)
            
            response = self._wait_for_response()
            if response:
                # 使用小端序读取4个字节计算位置
                value = (response.data[4] + 
                        (response.data[5] << 8) + 
                        (response.data[6] << 16) + 
                        (response.data[7] << 24))
                
                # 检查最高位是否为1(负数)
                if value & 0x80000000:
                    # 负数:将补码转换回原码
                    # 1. 取反
                    # 2. 加1
                    # 3. 加负号
                    position = -((~value + 1) & 0xFFFFFFFF)
                else:
                    # 正数:直接使用
                    position = value
                
                # 根据电机ID更新相应的属性
                if motor_id == 1:
                    self._currentPosition1 = position
                    self.currentPosition1Changed.emit(position)
                elif motor_id == 2:
                    self._currentPosition2 = position
                    self.currentPosition2Changed.emit(position)
                
                return position
            return 0
        except canlib.CanError as e:
            print(f"读取实际位置失败: {e}")
            return 0

    @pyqtSlot(int)
    def read_position_error(self, motor_id: int) -> int:
        """读取实时位置误差"""
        if not self.ch:
            print("CAN通道未初始化")
            return 0
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x04, 0x88, 0x9F, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=4)
            
            response = self._wait_for_response()
            if response:
                # 使用小端序读取4个字节计算误差
                value = (response.data[4] + 
                        (response.data[5] << 8) + 
                        (response.data[6] << 16) + 
                        (response.data[7] << 24))
                
                # 检查最高位是否为1(负数)
                if value & 0x80000000:
                    # 负数:将补码转换回原码
                    # 1. 取反
                    # 2. 加1
                    # 3. 加负号
                    error = -((~value + 1) & 0xFFFFFFFF)
                else:
                    # 正数:直接使用
                    error = value
                
                # 根据电机ID更新相应的属性
                if motor_id == 1:
                    self._positionError1 = error
                    self.positionError1Changed.emit(error)
                elif motor_id == 2:
                    self._positionError2 = error
                    self.positionError2Changed.emit(error)
                
                return error
            return 0
        except canlib.CanError as e:
            print(f"读取位置误差失败: {e}")
            
            return 0
    #电机1和2相关底层python配置——结束
    
    

    #电机3、4、5和6相关底层python配置——开始
    @pyqtSlot(int)
    def set_pwm_mode(self, motor_id: int) -> bool:
        """设置电机为PWM模式"""
        if not self.ch:
            print("CAN通道未初始化")
            return False

        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x2F, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}已设置为PWM模式")
            return True
        except Exception as e:
            print(f"设置PWM模式失败: {e}")
            return False

    
    @pyqtSlot(int, float)
    def set_pwm_duty(self, motor_id: int, duty_cycle: float) -> bool:
        """
        设置电机PWM占空比
        :param motor_id: 电机ID
        :param duty_cycle: 占空比值 (-100.0 到 100.0)
        """
        if not self.ch:
            print("CAN通道未初始化")
            return False

        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            # 将占空比转换为实际值(乘以0.1)
            actual_duty = int(duty_cycle * 10)  # 例如:98.5 * 10 = 985
            
            # 根据正负值构造数据
            if actual_duty >= 0:
                # 正值处理
                low_byte = actual_duty & 0xFF
                high_byte = (actual_duty >> 8) & 0xFF
                data = [0x2B, 0x01, 0x20, 0x00, low_byte, high_byte, 0x00, 0x00]
            else:
                # 负值处理:使用二进制补码
                actual_duty = -actual_duty  # 先取绝对值
                # 取补码:取反加一
                actual_duty = ((~actual_duty + 1) & 0xFFFF)  
                low_byte = actual_duty & 0xFF
                high_byte = (actual_duty >> 8) & 0xFF
                data = [0x2B, 0x01, 0x20, 0x00, low_byte, high_byte, 0xFF, 0xFF]

            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}设置PWM占空比: {duty_cycle}%")
            
            # 打印十六进制数据用于调试
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            
            return True
        except Exception as e:
            print(f"设置PWM占空比失败: {e}")
            return False

    
    @pyqtSlot(int)
    def read_motor_speed(self, motor_id: int) -> int:
        """读取电机实时转速"""
        if not self.ch:
            print("CAN通道未初始化")
            return 0
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x40, 0x0A, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            
            response = self._wait_for_response()
            if response:
                # 修改速度值的解析逻辑
                low_byte = response.data[4]
                high_byte = response.data[5]
                
                # 处理负值的情况
                if high_byte > 0x7F:  # 最高位为1表示负数
                    speed = -((0xFF - high_byte) * 256 + (256 - low_byte))
                else:
                    speed = low_byte + (high_byte << 8)
                
                # 存储并发送信号
                self._motorSpeed[motor_id] = speed
                self.motorSpeedChanged.emit(motor_id, speed)

                # 更新电机4的属性和发送信号
                if motor_id == 4:
                    self._motor4Speed = speed
                    self.motor4SpeedChanged.emit(motor_id, speed)
                    # 更新电机4的属性和发送信号
                if motor_id == 5:
                    self._motor5Speed = speed
                    self.motor5SpeedChanged.emit(motor_id, speed)
                # 更新电机6的属性和发送信号
                if motor_id == 6:
                    self._motor6Speed = speed
                    self.motor6SpeedChanged.emit(motor_id, speed)
    
                return speed
            return 0
        except canlib.CanError as e:
            print(f"读取实时转速失败: {e}")
            return 0

    @pyqtSlot(int)
    def read_motor_pwm(self, motor_id: int) -> int:
        """读取电机实时PWM"""
        if not self.ch:
            print("CAN通道未初始化")
            return 0
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x40, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            
            response = self._wait_for_response()
            if response:
                # 修改PWM值的解析逻辑
                low_byte = response.data[4]
                high_byte = response.data[5]
                
                # 处理负值的情况
                if high_byte > 0x7F:  # 最高位为1表示负数
                    pwm = -((0xFF - high_byte) * 256 + (256 - low_byte))
                else:
                    pwm = low_byte + (high_byte << 8)
                
                # 存储并发送信号
                self._motorPwm[motor_id] = pwm
                self.motorPwmChanged.emit(motor_id, pwm)
                return pwm
            return 0
        except canlib.CanError as e:
            print(f"读取实时PWM失败: {e}")
            return 0

    @pyqtSlot(int)
    def read_motor_current(self, motor_id: int) -> int:
        """读取电机实时电流"""
        if not self.ch:
            print("CAN通道未初始化")
            return 0
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x40, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)

            response = self._wait_for_response()
            if response:
                # 修改电流值的解析逻辑
                low_byte = response.data[4]
                high_byte = response.data[5]
                
                # 处理负值的情况
                if high_byte > 0x7F:  # 最高位为1表示负数
                    current = -((0xFF - high_byte) * 256 + (256 - low_byte))
                else:
                    current = low_byte + (high_byte << 8)
                
                # 存储并发送信号
                self._motorCurrent[motor_id] = current
                self.motorCurrentChanged.emit(motor_id, current)

                # 更新电机4的属性和发送信号
                if motor_id == 4:
                    self._motor4Current = current
                    self.motor4CurrentChanged.emit(motor_id, current)
                # 更新电机5的属性和发送信号
                if motor_id == 5:
                    self._motor5Current = current
                    self.motor5CurrentChanged.emit(motor_id, current)
                # 更新电机6的属性和发送信号
                if motor_id == 6:
                    self._motor6Current = current
                    self.motor6CurrentChanged.emit(motor_id, current)

                return current
            return 0
        except canlib.CanError as e:
            print(f"读取实时电流失败: {e}")
            return 0
    

    @pyqtSlot(int)
    def read_motor_position(self, motor_id: int) -> int:
        """读取电机实时位置"""
        if not self.ch:
            print("CAN通道未初始化")
            return 0
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            # 使用单条指令读取位置
            data = [0x40, 0x05, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)

            response = self._wait_for_response()
            if response:
                # 解析32位位置值
                position = int.from_bytes(response.data[4:8], byteorder='little', signed=True)
                self._motorPosition[motor_id] = position
                self.motorPositionChanged.emit(motor_id, position)

                # 更新电机4的属性和发送信号
                if motor_id == 4:
                    self._motor4Position = position
                    self.motor4PositionChanged.emit(motor_id, position)
                # 更新电机5的属性和发送信号
                if motor_id == 5:
                    self._motor5Position = position
                    self.motor5PositionChanged.emit(motor_id, position)
                # 更新电机6的属性和发送信号
                if motor_id == 6:
                    self._motor6Position = position
                    self.motor6PositionChanged.emit(motor_id, position)

                return position
            return 0
        except Exception as e:
            print(f"读取实时位置失败: {e}")
            return 0

    @pyqtSlot(int)
    def set_speed_mode(self, motor_id: int) -> bool:
        """设置电机为闭环调速模式"""
        if not self.ch:
            print("CAN通道未初始化")
            return False

        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x2F, 0x00, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}已设置为闭环调速模式")
            return True
        except Exception as e:
            print(f"设置闭环调速模式失败: {e}")
            return False

    @pyqtSlot(int, int)
    def set_motor_speed_rpm(self, motor_id: int, speed_rpm: int) -> bool:
        """
        设置电机转速
        :param motor_id: 电机ID
        :param speed_rpm: 目标转速(RPM)
        """
        if not self.ch:
            print("CAN通道未初始化")
            return False

        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            if speed_rpm >= 0:
                # 正速度值处理
                high_byte = speed_rpm // 256
                low_byte = speed_rpm % 256
                data = [0x2B, 0x01, 0x20, 0x00, low_byte, high_byte, 0x00, 0x00]
            else:
                # 负速度值处理
                abs_speed = abs(speed_rpm)
                high_byte = 0xFF - (abs_speed - 1) // 256
                remainder = abs_speed - (0xFF - high_byte) * 256
                low_byte = 256 - remainder
                data = [0x2B, 0x01, 0x20, 0x00, low_byte, high_byte, 0xFF, 0xFF]
            
            # 发送CAN指令
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}转速设置为: {speed_rpm} RPM")
            
            # 打印十六进制数据用于调试
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            
            return True
        except Exception as e:
            print(f"设置转速失败: {e}")
            return False
    
    @pyqtSlot(int)
    def set_3456_current_mode(self, motor_id: int) -> bool:
        """设置电机为力矩模式"""
        if not self.ch:
            print("CAN通道未初始化")
            return False

        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x2F, 0x00, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}已设置为力矩模式")
            return True
        except Exception as e:
            print(f"设置力矩模式失败: {e}")
            return False

    @pyqtSlot(int, int)
    def set_motor3456_current_mA(self, motor_id: int, current_mA: int) -> bool:
        """
        设置电机转矩
        :param motor_id: 电机ID
        :param current_mA: 目标电流(mA)
        """
        if not self.ch:
            print("CAN通道未初始化")
            return False

        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            if current_mA >= 0:
                # 正速度值处理
                high_byte = current_mA // 256
                low_byte = current_mA % 256
                data = [0x2B, 0x01, 0x20, 0x00, low_byte, high_byte, 0x00, 0x00]
            else:
                # 负速度值处理
                abs_current = abs(current_mA)
                high_byte = 0xFF - (abs_current - 1) // 256
                remainder = abs_current - (0xFF - high_byte) * 256
                low_byte = 256 - remainder
                data = [0x2B, 0x01, 0x20, 0x00, low_byte, high_byte, 0xFF, 0xFF]
            
            # 发送CAN指令
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}转矩设置为: {current_mA} mA")
            
            # 打印十六进制数据用于调试
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            
            return True
        except Exception as e:
            print(f"设置转矩失败: {e}")
            return False
    
    @pyqtSlot(int)
    def set_position_mode(self, motor_id: int) -> bool:
        """设置电机为位置控制模式"""
        if not self.ch:
            print("CAN通道未初始化")
            return False

        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x2F, 0x00, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}已设置为位置控制模式")
            return True
        except Exception as e:
            print(f"设置位置控制模式失败: {e}")
            return False

    @pyqtSlot(int)
    def set_absolute_position_mode(self, motor_id: int) -> bool:
        """设置为绝对位置模式"""
        if not self.ch:
            print("CAN通道未初始化")
            return False

        try:
            can_id = self.MOTOR_IDS[motor_id]
            # 新的绝对位置模式指令
            data = [0x2F, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}已设置为绝对位置模式")
            return True
        except Exception as e:
            print(f"设置绝对位置模式失败: {e}")
            return False

    @pyqtSlot(int)
    def set_relative_position_mode(self, motor_id: int) -> bool:
        """设置为相对位置模式"""
        if not self.ch:
            print("CAN通道未初始化")
            return False

        try:
            can_id = self.MOTOR_IDS[motor_id]
            # 新的相对位置模式指令
            data = [0x2F, 0x02, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}已设置为相对位置模式")
            return True
        except Exception as e:
            print(f"设置相对位置模式失败: {e}")
            return False

    @pyqtSlot(int, int)
    def set_target_position(self, motor_id: int, position: int) -> bool:
        """设置目标位置"""
        if not self.ch:
            print("CAN通道未初始化")
            return False

        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            # 新的目标位置设置格式:一次性发送32位位置值
            data = [0x23, 0x03, 0x20, 0x00,
                    position & 0xFF,                # 最低字节
                    (position >> 8) & 0xFF,         # 次低字节
                    (position >> 16) & 0xFF,        # 次高字节
                    (position >> 24) & 0xFF]        # 最高字节
            
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            
            print(f"电机{motor_id}目标位置设置为: {position}")
            print(f"发送的数据: {[f'0x{x:02X}' for x in data]}")
            return True
        except Exception as e:
            print(f"设置目标位置失败: {e}")
            return False
    #电机3、4、5和6相关底层python配置——结束
    
    

    #电机7、8、9和10相关底层python配置——开始
    @pyqtSlot(int)
    def set_speed_control_mode(self, motor_id: int) -> bool:
        """设置电机为速度控制模式"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            # 1. 设置控制模式为速度控制
            data = [0x00, 0x4E, 0x00, 0x00, 0x00, 0x02]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}设置速度控制模式")
            time.sleep(0.1)
            
            # 2. 设置控制源为不使用
            data = [0x01, 0x12, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}设置控制源为不使用")
            time.sleep(0.1)
            
            # 3. 设置模拟量类型为内部使用
            data = [0x01, 0xFD, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}设置模拟量类型为内部使用")

            self.motorSpeedModeStatusChanged.emit(motor_id, True)
            return True
            
        except Exception as e:
            print(f"设置速度控制模式失败: {e}")
            return False

    @pyqtSlot(int)  
    def enable_motor(self, motor_id: int) -> bool:
        """电机使能"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x01, 0x00, 0x00, 0x00, 0x00, 0x01]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}已使能")
            
            self.motorEnableStatusChanged.emit(motor_id, True)
            return True
            
        except Exception as e:
            print(f"电机使能失败: {e}")
            return False
    
    @pyqtSlot(int, int)
    def set_target_speed(self, motor_id: int, speed: int) -> bool:
        """设置目标速度值"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            if speed >= 0:  # 处理正数情况
                if speed <= 65535:  # 处理小于等于0xFFFF的值
                    data = [0x01, 0xFE, 0x00, 0x00,
                            (speed >> 8) & 0xFF,
                            speed & 0xFF]
                else:  # 处理大于0xFFFF的值
                    data = [0x01, 0xFE, 0x00,
                            (speed >> 16) & 0xFF,
                            (speed >> 8) & 0xFF,
                            speed & 0xFF]
            else:  # 处理负数情况
                # 对于负数,前三位固定为 01 FE FF
                # 后三位使用补码表示
                neg_value = abs(speed)
                data = [0x01, 0xFE, 0xFF,
                        ~((neg_value >> 16) & 0xFF) & 0xFF,
                        ~((neg_value >> 8) & 0xFF) & 0xFF,
                        (~neg_value & 0xFF) + 1]
            
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}目标速度设置为: {speed} count/s")
            
            # 打印调试信息
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            return True
            
        except Exception as e:
            print(f"设置目标速度失败: {e}")
            return False

    @pyqtSlot(int)
    def set_torque_mode(self, motor_id: int) -> bool:
        """设置电机为力矩控制模式"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            # 1. 设置控制模式为力矩控制
            data = [0x00, 0x4E, 0x00, 0x00, 0x00, 0x01]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}设置力矩控制模式")
            time.sleep(0.1)
            
            # 2. 设置控制源为不使用
            data = [0x01, 0x12, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}设置控制源为不使用")
            time.sleep(0.1)

            # 3. 设置模拟量类型为内部使用
            data = [0x01, 0xFD, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}设置模拟量类型为内部使用")
            
            # 发送信号通知UI
            self.motorTorqueModeStatusChanged.emit(motor_id, True)
            return True
            
        except Exception as e:
            print(f"设置力矩控制模式失败: {e}")
            return False

    @pyqtSlot(int, int)
    def set_max_speed(self, motor_id: int, max_speed: int) -> bool:
        """设置最大速度限制"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            if max_speed >= 0:  # 处理正数情况
                if max_speed <= 65535:  # 处理小于等于0xFFFF的值
                    data = [0x02, 0x04, 0x00, 0x00,
                            (max_speed >> 8) & 0xFF,
                            max_speed & 0xFF]
                else:  # 处理大于0xFFFF的值
                    data = [0x02, 0x04, 0x00,
                            (max_speed >> 16) & 0xFF,
                            (max_speed >> 8) & 0xFF,
                            max_speed & 0xFF]
            else:  # 处理负数情况
                # 对于负数,前三位固定为 02 04 FF
                neg_value = abs(max_speed)
                data = [0x02, 0x04, 0xFF,
                        ~((neg_value >> 16) & 0xFF) & 0xFF,
                        ~((neg_value >> 8) & 0xFF) & 0xFF,
                        (~neg_value & 0xFF) + 1]
            
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}最大速度限制设置为: {max_speed} count/s")
            
            # 打印调试信息
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            
            # 发送信号通知UI
            self.motorMaxSpeedChanged.emit(motor_id, max_speed)
            return True
            
        except Exception as e:
            print(f"设置最大速度限制失败: {e}")
            return False

    @pyqtSlot(int, int)
    def set_target_current(self, motor_id: int, current: int) -> bool:
        """设置目标电流值"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            if current >= 0:  # 处理正数情况
                data = [0x01, 0xFE, 0x00, 0x00,
                        (current >> 8) & 0xFF,
                        current & 0xFF]
            else:  # 处理负数情况
                # 对于负数,前四位固定为 01 FE FF FF
                neg_value = abs(current)
                data = [0x01, 0xFE, 0xFF, 0xFF,
                        ~((neg_value >> 8) & 0xFF) & 0xFF,
                        (~neg_value & 0xFF) + 1]
            
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}目标电流设置为: {current} mA")
            
            # 打印调试信息
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            
            # 发送信号通知UI
            self.motorTargetCurrentChanged.emit(motor_id, current)
            return True
            
        except Exception as e:
            print(f"设置目标电流失败: {e}")
            return False

    @pyqtSlot(int)
    def disable_motor(self, motor_id: int) -> bool:
        """电机失能"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}已失能")
            return True
            
        except Exception as e:
            print(f"电机失能失败: {e}")
            return False
    
    @pyqtSlot(int)
    def read_extended_motor_speed(self, motor_id: int) -> int:
        """读取扩展电机的实际速度"""
        if not self.ch:
            print("CAN通道未初始化")
            return 0
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x00, 0x05, 0x00, 0x01]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=4)
            
            response = self._wait_for_response()
            if response:
                speed_bytes = response.data[0:4]
                if len(speed_bytes) == 4:
                    speed = int.from_bytes(speed_bytes, byteorder='big', signed=True)
                    # 根据电机ID更新对应的属性
                    if motor_id == 7:
                        self._motor7Speed = speed
                        self.motor7SpeedChanged.emit(motor_id, speed)
                    elif motor_id == 8:
                        self._motor8Speed = speed
                        self.motor8SpeedChanged.emit(motor_id, speed)
                    elif motor_id == 9:
                        self._motor9Speed = speed
                        self.motor9SpeedChanged.emit(motor_id, speed)
                    elif motor_id == 10:
                        self._motor10Speed = speed
                        self.motor10SpeedChanged.emit(motor_id, speed)
                    print(f"电机{motor_id}实际速度: {speed}")
                    return speed
            return 0
        except Exception as e:
            print(f"读取电机{motor_id}实际速度失败: {e}")
            return 0

    @pyqtSlot(int)
    def read_extended_motor_current(self, motor_id: int) -> int:
        """读取扩展电机的实际电流"""
        if not self.ch:
            print("CAN通道未初始化")
            return 0
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x00, 0x08]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=2)
            
            response = self._wait_for_response()
            if response:
                current_bytes = response.data[0:4]
                if len(current_bytes) == 4:
                    current = int.from_bytes(current_bytes, byteorder='big', signed=True)
                    if motor_id == 7:
                        self._motor7Current = current
                        self.motor7CurrentChanged.emit(motor_id, current)
                    elif motor_id == 8:
                        self._motor8Current = current
                        self.motor8CurrentChanged.emit(motor_id, current)
                    elif motor_id == 9:
                        self._motor9Current = current
                        self.motor9CurrentChanged.emit(motor_id, current)
                    elif motor_id == 10:
                        self._motor10Current = current
                        self.motor10CurrentChanged.emit(motor_id, current)
                    print(f"电机{motor_id}实际电流: {current}mA")
                    return current
            return 0
        except Exception as e:
            print(f"读取电机{motor_id}实际电流失败: {e}")
            return 0

    @pyqtSlot(int)
    def read_extended_motor_position(self, motor_id: int) -> int:
        """读取扩展电机的实际位置"""
        if not self.ch:
            print("CAN通道未初始化")
            return 0
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x00, 0x02]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=2)
            
            response = self._wait_for_response()
            if response:
                position_bytes = response.data[0:4]
                if len(position_bytes) == 4:
                    position = int.from_bytes(position_bytes, byteorder='big', signed=True)
                         
                    if motor_id == 7:
                        self._motor7Position = position
                        self.motor7PositionChanged.emit(motor_id, position)
                    elif motor_id == 8:
                        self._motor8Position = position
                        self.motor8PositionChanged.emit(motor_id, position)
                    elif motor_id == 9:
                        self._motor9Position = position
                        self.motor9PositionChanged.emit(motor_id, position)
                    elif motor_id == 10:
                        self._motor10Position = position
                        self.motor10PositionChanged.emit(motor_id, position)
                    
                    return position
            return 0
        except Exception as e:
            print(f"读取电机{motor_id}实际位置失败: {e}")
            return 0

    @pyqtProperty(bool)
    def position_protection_enabled(self):
        return self._position_protection_enabled
    
    @position_protection_enabled.setter
    def position_protection_enabled(self, value):
        self._position_protection_enabled = value
    
    def check_position_limits(self, motor_id: int, position: int) -> bool:
        """检查位置是否在允许范围内"""
        if not self._position_protection_enabled:
            return True
            
        if motor_id in [7, 8, 9, 10]:
            if position < self.POSITION_MIN or position > self.POSITION_MAX:
                print(f"电机{motor_id}位置{position}超出允许范围({self.POSITION_MIN}-{self.POSITION_MAX})")
                self.positionOutOfRangeError.emit(motor_id, position)
                self.emergency_stop()  # 触发紧急停止
                return False
        return True
    
    def _check_motors_position(self):
        """定时检查电机7-10的位置"""
        if not self.ch or not self._position_protection_enabled or not self._monitoring_enabled:
            return
            
        try:
            for motor_id in [7, 8, 9, 10]:
                # 使用现有的读取方法,但不更新UI
                position = self._read_position_without_ui_update(motor_id)
                
                # 只进行位置检查
                if position != 0:  # 0表示读取失败
                    if position < self.POSITION_MIN or position > self.POSITION_MAX:
                        print(f"位置监控:电机{motor_id}位置{position}超出允许范围")
                        self.positionOutOfRangeError.emit(motor_id, position)
                        self.emergency_stop()
                        return
                
                # 添加小延时,避免CAN总线负载过高
                time.sleep(0.01)
                
        except Exception as e:
            print(f"位置监控检查失败: {e}")
    
    def _read_position_without_ui_update(self, motor_id: int) -> int:
        """读取位置但不更新UI(供监控使用)"""
        if not self.ch:
            return 0
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x00, 0x02]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=2)
            
            response = self._wait_for_response()
            if response:
                position_bytes = response.data[0:4]
                if len(position_bytes) == 4:
                    return int.from_bytes(position_bytes, byteorder='big', signed=True)
            return 0
        except Exception as e:
            print(f"读取电机{motor_id}位置失败: {e}")
            return 0
    
    @pyqtSlot()
    def reset_protection(self):
        """重置保护状态,重新启用监控"""
        self._monitoring_enabled = True
    
    @pyqtSlot(int, int)
    def set_acceleration(self, motor_id: int, acceleration: int) -> bool:
        """设置加速度"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            if acceleration <= 65535:  # 处理小于等于0xFFFF的值
                # 例如30000 (0x7530)
                data = [0x00, 0x88, 0x00, 0x00,
                        (acceleration >> 8) & 0xFF,   # 0x75
                        acceleration & 0xFF]          # 0x30
            else:  # 处理大于0xFFFF的值
                # 例如200000 (0x30D40)
                data = [0x00, 0x88, 0x00,
                        (acceleration >> 16) & 0xFF,  # 0x03
                        (acceleration >> 8) & 0xFF,   # 0x0D
                        acceleration & 0xFF]          # 0x40
            
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            
            # 打印调试信息
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"电机{motor_id}加速度设置为: {acceleration} count/s²")
            print(f"发送的CAN数据: {hex_data}")
            
            return True
            
        except Exception as e:
            print(f"设置加速度失败: {e}")
            return False

    @pyqtSlot(int, int)
    def set_deceleration(self, motor_id: int, deceleration: int) -> bool:
        """设置减速度"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            if deceleration <= 65535:  # 处理小于等于0xFFFF的值
                # 例如30000 (0x7530)
                data = [0x00, 0x89, 0x00, 0x00,
                        (deceleration >> 8) & 0xFF,   # 0x75
                        deceleration & 0xFF]          # 0x30
            else:  # 处理大于0xFFFF的值
                # 例如200000 (0x30D40)
                data = [0x00, 0x89, 0x00,
                        (deceleration >> 16) & 0xFF,  # 0x03
                        (deceleration >> 8) & 0xFF,   # 0x0D
                        deceleration & 0xFF]          # 0x40
            
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}减速度设置为: {deceleration} count/s²")
            
            # 打印调试信息
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            return True
            
        except Exception as e:
            print(f"设置减速度失败: {e}")
            return False

    @pyqtSlot(int, int)
    def set_position_speed(self, motor_id: int, speed: int) -> bool:
        """设置位置速度"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            if speed <= 65535:  # 处理小于等于0xFFFF的值
                # 例如30000 (0x7530)
                data = [0x00, 0x8A, 0x00, 0x00,
                        (speed >> 8) & 0xFF,   # 0x75
                        speed & 0xFF]          # 0x30
            else:  # 处理大于0xFFFF的值
                # 例如200000 (0x30D40)
                data = [0x00, 0x8A, 0x00,
                        (speed >> 16) & 0xFF,  # 0x03
                        (speed >> 8) & 0xFF,   # 0x0D
                        speed & 0xFF]          # 0x40
            
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}位置速度设置为: {speed} count/s")
            
            # 打印调试信息
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            return True
            
        except Exception as e:
            print(f"设置位置速度失败: {e}")
            return False
    
    @pyqtSlot(int)
    def set_position_mode(self, motor_id: int) -> bool:
       """设置位置控制模式"""
       if not self.ch:
           print("CAN通道未初始化")
           return False
           
       try:
           can_id = self.MOTOR_IDS[motor_id]
           
           # 1. 设置控制模式为位置控制
           data = [0x00, 0x4E, 0x00, 0x00, 0x00, 0x03]
           self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
           print(f"电机{motor_id}设置为位置控制模式")
           time.sleep(0.1)
           
           # 2. 设置运动模式为目标绝对位置模式
           data = [0x00, 0x8D, 0x00, 0x00, 0x00, 0x01]
           self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
           print(f"电机{motor_id}设置为目标绝对位置模式")
           time.sleep(0.1)
           
           # 3. 设置相对位置为0
           data = [0x00, 0x87, 0x00, 0x00, 0x00, 0x00]
           self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
           print(f"电机{motor_id}相对位置设置为0")
           
           return True
           
       except Exception as e:
           print(f"设置位置控制模式失败: {e}")
           return False
       
    @pyqtSlot(int, int)
    def set_absolute_position(self, motor_id: int, position: int) -> bool:
        """设置目标绝对位置"""
        if not self.ch:
            print("CAN通道未初始化")
            return False            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            if position >= 0:  # 处理正数情况
                if position <= 65535:  # 处理小于等于0xFFFF的值
                    data = [0x00, 0x86, 0x00, 0x00,
                            (position >> 8) & 0xFF,
                            position & 0xFF]
                else:  # 处理大于0xFFFF的值
                    data = [0x00, 0x86, 0x00,
                            (position >> 16) & 0xFF,
                            (position >> 8) & 0xFF,
                            position & 0xFF]
            else:  # 处理负数情况
                # 对于负数,前三位固定为 00 86 FF
                neg_value = abs(position)
                data = [0x00, 0x86, 0xFF,
                        ~((neg_value >> 16) & 0xFF) & 0xFF,
                        ~((neg_value >> 8) & 0xFF) & 0xFF,
                        (~neg_value & 0xFF) + 1]
            
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}目标绝对位置设置为: {position}")
            
            # 打印调试信息
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            return True
            
        except Exception as e:
            print(f"设置目标绝对位置失败: {e}")
            return False
       
    @pyqtSlot(int)
    def start_motion(self, motor_id: int) -> bool:
       """开始运动"""
       if not self.ch:
           print("CAN通道未初始化")
           return False
           
       try:
           can_id = self.MOTOR_IDS[motor_id]
           data = [0x00, 0x83]
           self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=2)
           print(f"电机{motor_id}开始运动")
           return True
           
       except Exception as e:
           print(f"开始运动失败: {e}")
           return False
    
    @pyqtSlot(int, int)
    def set_relative_position(self, motor_id: int, position: int) -> bool:
        """设置目标相对位置"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
        
        try:
            can_id = self.MOTOR_IDS[motor_id]
            
            if position >= 0:  # 处理正数情况
                if position <= 65535:  # 处理小于等于0xFFFF的值
                    data = [0x00, 0x87, 0x00, 0x00,
                            (position >> 8) & 0xFF,
                            position & 0xFF]
                else:  # 处理大于0xFFFF的值
                    data = [0x00, 0x87, 0x00,
                            (position >> 16) & 0xFF,
                            (position >> 8) & 0xFF,
                            position & 0xFF]
            else:  # 处理负数情况
                # 对于负数,前三位固定为 00 87 FF
                neg_value = abs(position)
                data = [0x00, 0x87, 0xFF,
                        ~((neg_value >> 16) & 0xFF) & 0xFF,
                        ~((neg_value >> 8) & 0xFF) & 0xFF,
                        (~neg_value & 0xFF) + 1]
            
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
            print(f"电机{motor_id}目标相对位置设置为: {position}")
            
            # 打印调试信息
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            return True
            
        except Exception as e:
            print(f"设置目标相对位置失败: {e}")
            return False
    #电机7、8、9和10相关底层python配置——结束



    @pyqtSlot()
    def emergency_stop(self) -> bool:
        """所有电机紧急停止"""
        if not self.ch:
            print("CAN通道未初始化")
            try:
                # 尝试重新初始化CAN通道
                self.initialize_can()
            except Exception as e:
                print(f"重新初始化CAN通道失败: {e}")
                return False
            
        try:
            # 禁用位置监控,避免重复触发
            self._monitoring_enabled = False
            
            # 处理电机7、8、9和10
            for motor_id in [7, 8, 9, 10]:
                can_id = self.MOTOR_IDS[motor_id]
                
                # 1. 电机失能
                data = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00]
                self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
                time.sleep(0.001)
                
                # 2. 设置控制模式为速度模式
                data = [0x00, 0x4E, 0x00, 0x00, 0x00, 0x02]
                self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
                time.sleep(0.001)
                
                # 3. 设置控制源为不使用
                data = [0x01, 0x12, 0x00, 0x00, 0x00, 0x00]
                self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
                time.sleep(0.001)
                
                # 4. 设置模拟量为内部使用
                data = [0x01, 0xFD, 0x00, 0x00, 0x00, 0x00]
                self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
                time.sleep(0.001)
                
                # 5. 设置模拟量值
                data = [0x01, 0xFE, 0x00, 0x00, 0x00, 0x00]
                self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=6)
                time.sleep(0.001)
            
            # 处理电机1和2
            for motor_id in [1, 2]:
                can_id = self.MOTOR_IDS[motor_id]
                data = [0x08, 0x88, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00]
                self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
                time.sleep(0.001)
            
            # 处理电机3、4、5和6
            for motor_id in [3, 4, 5, 6]:
                can_id = self.MOTOR_IDS[motor_id]
                data = [0x2F, 0x00, 0x20, 0x00, 0x11, 0x00, 0x00, 0x00]
                self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
                time.sleep(0.001)
            
            print("所有电机已紧急停止")

            # 确保CAN通道保持活跃状态
            try:
                if not self.ch.getBusStatus() & canlib.canSTAT_BUS_ACTIVE:
                    self.ch.busOn()
            except Exception as e:
                print(f"重新激活CAN总线失败: {e}")
                # 尝试重新初始化
                self.initialize_can()

            return True
            
        except Exception as e:
            print(f"紧急停止失败: {e}")
            # 发生错误时尝试重新初始化CAN通道
            try:
                self.ch.busOff()
                time.sleep(0.1)
                self.ch.busOn()
            except:
                self.initialize_can()
            return False
    
    @pyqtSlot(int)
    def release_emergency_stop(self, motor_id: int) -> bool:
        """解除电机急停状态"""
        if not self.ch:
            print("CAN通道未初始化")
            return False
            
        try:
            can_id = self.MOTOR_IDS[motor_id]
            data = [0x08, 0x88, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00]
            self.ch.write_raw(id_=can_id, msg=bytearray(data), dlc=8)
            print(f"电机{motor_id}已解除急停状态")
            
            # 打印调试信息
            hex_data = ' '.join([f'0x{x:02X}' for x in data])
            print(f"发送的CAN数据: {hex_data}")
            return True
            
        except Exception as e:
            print(f"解除急停状态失败: {e}")
            return False
    
    def _wait_for_response(self, expected_id=None, timeout_ms=500):
        """
        等待指定ID的CAN响应
        Args:
            expected_id: 期望的响应ID (如果为None,则接受0x01或0x5D5)
            timeout_ms: 超时时间(毫秒)
        Returns:
            canlib.Frame 或 None
        """
        if not self._receive_thread or not self._receive_thread.is_alive():
            print("接收线程未运行")
            return None

        from threading import Event
        response_event = Event()
        response_data = [None]

        def message_handler(msg):
            # 如果没有指定expected_id,则接受两种ID
            if expected_id is None and msg.id in [0x01, 0x5D5, 0x5C4, 0x5E6, 0x591, 0x5D6, 0x5E1, 0x600, 0x5C8]:
                response_data[0] = msg
                response_event.set()
            # 如果指定了expected_id,则只接受指定ID
            elif expected_id is not None and msg.id == expected_id:
                response_data[0] = msg
                response_event.set()

        # 临时订阅消息
        self._message_handlers.append(message_handler)
        try:
            # 等待响应或超时
            if response_event.wait(timeout_ms / 1000.0):
                return response_data[0]
            return None
        finally:
            # 移除临时订阅
            self._message_handlers.remove(message_handler)

    def cleanup(self):
        self.running = False
        if self._receive_thread:
            self._receive_thread.join(timeout=1.0)
        if self.ch:
            self.ch.busOff()
            self.ch.close()
            print("CAN通道已关闭") 

        # 停止位置监控定时器
        if hasattr(self, '_position_monitor_timer'):
            self._position_monitor_timer.stop()


def main():
    app = QApplication(sys.argv)
    
    # 设置应用程序名称和窗口标题
    app.setApplicationName("巡检机器人控制面板")
    
    controller = CanController()

    # 添加信号测试
    def on_can_message(can_id, data):
        print(f"Python收到CAN消息: ID={can_id}, Data={data}")

    controller.canMessageReceived.connect(on_can_message)

    # 创建 QML 引擎
    engine = QQmlApplicationEngine()
    
    # 在加载 QML 之前设置上下文属性
    engine.rootContext().setContextProperty("controller", controller)
    
    # 加载 QML 文件
    engine.load(QUrl.fromLocalFile("qmls/main.qml"))
    
    if not engine.rootObjects():
        print("QML文件加载失败")
        return -1

    # 获取主窗口
    window = engine.rootObjects()[0]

    # 添加事件过滤器
    class KeyFilter(QObject):
        def __init__(self, controller):
            super().__init__()
            self.controller = controller

        def eventFilter(self, obj, event):
            if event.type() == event.KeyPress:
                if event.key() == Qt.Key_Control:
                    print("Ctrl key pressed through event filter")
                    self.controller.emergency_stop()
                    return True
            return False

    # 安装事件过滤器
    key_filter = KeyFilter(controller)
    window.installEventFilter(key_filter)
    app.installEventFilter(key_filter)

    app.aboutToQuit.connect(controller.cleanup)

    return app.exec_()


if __name__ == "__main__":
    main()

main.qml

import QtCharts 2.15
import QtQuick 2.15
import QtQuick.Controls 2.14

ApplicationWindow {
    id: mainWindow

    visible: true
    width: 900
    height: 715

    // 确保窗口可以接收键盘事件
    flags: Qt.Window | Qt.WindowSystemMenuHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint

    // 添加全局快捷键处理
    Shortcut {
        sequences: [StandardKey.Cancel, "Ctrl"]  // 同时监听 Cancel 和 Ctrl 键
        context: Qt.ApplicationShortcut  // 设置为应用程序级快捷键
        onActivated: {
            console.log("Ctrl key pressed - Emergency Stop triggered")
            controller.emergency_stop()
        }
    }

    // 添加焦点处理
    Item {
        focus: true
        Keys.onPressed: function(event) {
            if (event.key === Qt.Key_Control) {
                console.log("Control key pressed via Keys handler")
                controller.emergency_stop();
                event.accepted = true;
            }
        }
    }

    QtObject {
        id: style

        property color primaryColor: "#AA69B4"
    }

    Column {
        anchors.fill: parent
        spacing: 8

        Row {
            anchors.horizontalCenter: parent.horizontalCenter
            spacing: 8
            height: 30

            Rectangle {
                width: 100
                height: 36
                radius: 5
                color: "#228B55"

                Text {
                    anchors.centerIn: parent
                    text: "初始化 CAN"
                    color: "white"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: controller.initialize_can()
                }

            }

            Rectangle {
                width: 100
                height: 36
                radius: 5
                color: positionProtectionEnabled ? "#228B55" : "#E0E0E0"  // 开启时绿色,关闭时灰色

                property bool positionProtectionEnabled: true  // 默认开启

                Text {
                    anchors.centerIn: parent
                    text: "位置保护"
                    color: "white"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        parent.positionProtectionEnabled = !parent.positionProtectionEnabled
                        controller.position_protection_enabled = parent.positionProtectionEnabled
                    }
                }
            }

            Rectangle {
                width: 60
                height: 36
                radius: 5
                color: sw.currentIndex === 0 ? style.primaryColor : "#E0E0E0"

                Text {
                    anchors.centerIn: parent
                    text: "电机1"
                    color: sw.currentIndex === 0 ? "white" : "black"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: sw.setCurrentIndex(0)
                }

            }

            Rectangle {
                width: 60
                height: 36
                radius: 5
                color: sw.currentIndex === 1 ? style.primaryColor : "#E0E0E0"

                Text {
                    anchors.centerIn: parent
                    text: "电机2"
                    color: sw.currentIndex === 1 ? "white" : "black"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: sw.setCurrentIndex(1)
                }

            }

            Rectangle {
                width: 60
                height: 36
                radius: 5
                color: sw.currentIndex === 2 ? style.primaryColor : "#E0E0E0"

                Text {
                    anchors.centerIn: parent
                    text: "电机3"
                    color: sw.currentIndex === 2 ? "white" : "black"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: sw.setCurrentIndex(2)
                }

            }

            Rectangle {
                width: 60
                height: 36
                radius: 5
                color: sw.currentIndex === 3 ? style.primaryColor : "#E0E0E0"

                Text {
                    anchors.centerIn: parent
                    text: "电机4"
                    color: sw.currentIndex === 3 ? "white" : "black"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: sw.setCurrentIndex(3)
                }
            }

            Rectangle {
                width: 60
                height: 36
                radius: 5
                color: sw.currentIndex === 4 ? style.primaryColor : "#E0E0E0"

                Text {
                    anchors.centerIn: parent
                    text: "电机5"
                    color: sw.currentIndex === 4 ? "white" : "black"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: sw.setCurrentIndex(4)
                }
            }

            Rectangle {
                width: 60
                height: 36
                radius: 5
                color: sw.currentIndex === 5 ? style.primaryColor : "#E0E0E0"

                Text {
                    anchors.centerIn: parent
                    text: "电机6"
                    color: sw.currentIndex === 5 ? "white" : "black"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: sw.setCurrentIndex(5)
                }
            }

            Rectangle {
                width: 60
                height: 36
                radius: 5
                color: sw.currentIndex === 6 ? style.primaryColor : "#E0E0E0"

                Text {
                    anchors.centerIn: parent
                    text: "电机7"
                    color: sw.currentIndex === 6 ? "white" : "black"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: sw.setCurrentIndex(6)
                }
            }

            Rectangle {
                width: 60
                height: 36
                radius: 5
                color: sw.currentIndex === 7 ? style.primaryColor : "#E0E0E0"

                Text {
                    anchors.centerIn: parent
                    text: "电机8"
                    color: sw.currentIndex === 7 ? "white" : "black"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: sw.setCurrentIndex(7)
                }
            }

            Rectangle {
                width: 60
                height: 36
                radius: 5
                color: sw.currentIndex === 8 ? style.primaryColor : "#E0E0E0"

                Text {
                    anchors.centerIn: parent
                    text: "电机9"
                    color: sw.currentIndex === 8 ? "white" : "black"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: sw.setCurrentIndex(8)
                }
            }

            Rectangle {
                width: 60
                height: 36
                radius: 5
                color: sw.currentIndex === 9 ? style.primaryColor : "#E0E0E0"

                Text {
                    anchors.centerIn: parent
                    text: "电机10"
                    color: sw.currentIndex === 9 ? "white" : "black"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: sw.setCurrentIndex(9)
                }
            }   

        }

        // 自定义CAN指令区域
        Rectangle {
            width: parent.width
            height: 100
            color: "#1A2B3C"
            radius: 5

            Column {
                spacing: 8
                anchors {
                    fill: parent
                    margins: 8
                }

                // 标题行
                Row {
                    anchors.horizontalCenter: parent.horizontalCenter
                    spacing: 8

                    Text {
                        text: "自定义 CAN 指令"
                        color: "white"
                        font {
                            pixelSize: 16
                            bold: true
                        }
                    }

                    Item { // 弹性空间
                        width: 100  // 固定间距
                        height: 1
                    }

                    Rectangle {
                        width: 80
                        height: 24
                        radius: 4
                        color: "white"

                        Text {
                            anchors.centerIn: parent
                            text: "重置保护"
                            color: "black"
                            font.pixelSize: 14
                        }

                        MouseArea {
                            anchors.fill: parent
                            onClicked: controller.reset_protection()
                        }
                    }
                }

                Row {
                    width: parent.width
                    spacing: 8

                    Column {
                        width: (parent.width - 16) * 0.2
                        spacing: 8

                        Text {
                            text: "CAN ID (hex)"
                            font.pixelSize: 14
                            color: "white"
                        }

                        Rectangle {
                            width: parent.width - 16
                            height: 36
                            radius: 5 / 2
                            border.color: canIdInput.activeFocus ? style.primaryColor : "#E0E0E0"

                            TextInput {
                                id: canIdInput

                                text: "88"
                                font.pixelSize: 16
                                verticalAlignment: Text.AlignVCenter
                                selectByMouse: true

                                anchors {
                                    fill: parent
                                    margins: 8
                                }

                            }

                        }

                    }

                    Column {
                        width: (parent.width - 16) * 0.6
                        spacing: 8

                        Text {
                            text: "数据 (hex)"
                            font.pixelSize: 14
                            color: "white"
                        }

                        Rectangle {
                            width: parent.width - 16
                            height: 36
                            radius: 5 / 2
                            border.color: canDataInput.activeFocus ? style.primaryColor : "#E0E0E0"

                            TextInput {
                                id: canDataInput

                                text: "08 88 2A 00 00 00 00 00"
                                font.pixelSize: 16
                                verticalAlignment: Text.AlignVCenter
                                selectByMouse: true

                                anchors {
                                    fill: parent
                                    margins: 8
                                }

                            }

                        }

                    }

                    Item {
                        width: 20
                    }

                    Column {
                        width: (parent.width - 32) * 0.2
                        spacing: 8

                        Text {
                            text: " "
                            font.pixelSize: 12
                        }

                        
                        Rectangle {
                            width: parent.width-30
                            height: 36
                            radius: 5 / 2
                            color: "white"

                            Text {
                                anchors.centerIn: parent
                                text: "发送"
                                color: "black"
                                font.pixelSize: 16
                            }

                            MouseArea {
                                id: sendMouseArea

                                anchors.fill: parent
                                onClicked: {
                                    var canId = parseInt(canIdInput.text, 16);
                                    controller.send_custom_can_command(canId, canDataInput.text);
                                }
                            }

                        }

                    }

                }

            }

        }

        // CAN消息显示区域
        Rectangle {
            width: parent.width
            height: 200
            color: "#1A2B3C"
            radius: 5

            Column {
                spacing: 10

                anchors {
                    fill: parent
                    margins: 16
                }

                Row {
                    spacing: 10
                    width: parent.width

                    Text {
                        text: "接收的 CAN 消息"
                        color: "white"

                        font {
                            pixelSize: 16
                            bold: true
                        }

                    }

                    Text {
                        id: messageCount

                        leftPadding: 50 // 添加左边距
                        text: "消息数量: 0"
                        color: "white"
                        font.pixelSize: 12
                    }

                    Item {
                        width: parent.width - 350
                        height: 1
                    }

                    Rectangle {
                        width: 80
                        height: 32
                        radius: 5 / 2
                        color: "white"

                        Text {
                            anchors.centerIn: parent
                            text: "清除"
                            color: "black"
                            font.pixelSize: 16
                        }

                        MouseArea {
                            id: clearMouseArea

                            anchors.fill: parent
                            onClicked: {
                                messageModel.clear();
                                messageCount.text = "消息数量: 0";
                            }
                        }

                    }

                }

                ListView {
                    width: parent.width
                    height: parent.height - 50
                    clip: true

                    model: ListModel {
                        id: messageModel
                    }

                    delegate: Rectangle {
                        width: ListView.view.width
                        height: messageText.height + 16
                        color: index % 2 === 0 ? "#F8F9FA" : "#FFFFFF"

                        Text {
                            id: messageText

                            text: model.time + " - ID: " + model.canId + " Data: " + model.data
                            font.pixelSize: 13
                            wrapMode: Text.Wrap
                            color: "black"

                            anchors {
                                left: parent.left
                                right: parent.right
                                verticalCenter: parent.verticalCenter
                                margins: 8
                            }

                        }

                    }

                }

            }

        }

        SwipeView {
            id: sw

            width: parent.width
            height: parent.height - 50
            interactive: true

            DianJi_1 {
                id: dianJi1
            }

            DianJi_2 {
                id: dianJi2
            }

            DianJi_3 {
                id: dianJi3
            }

            DianJi_4 {
                id: dianJi4
            }

            DianJi_5 {
                id: dianJi5
            }

            DianJi_6 {
                id: dianJi6
            }

            DianJi_7 {
                id: dianJi7
            }
            
            DianJi_8 {
                id: dianJi8
            }
            
            DianJi_9 {
                id: dianJi9
            }

            DianJi_10 {
                id: dianJi10
            }

        }

        // 位置保护错误提示对话框
        Dialog {
            id: positionErrorDialog
            title: "位置保护警告"
            modal: true
            standardButtons: Dialog.Ok
            
            x: (parent.width - width) / 2
            y: (parent.height - height) / 2
            
            property int motorId: 0
            property int position: 0
            
            Text {
                text: "电机" + positionErrorDialog.motorId + 
                      "位置(" + positionErrorDialog.position + 
                      ")超出允许范围(150000-350000)\n已触发紧急停止!"
                color: "red"
                font.pixelSize: 14
            }
        }

    }

    Component.onCompleted: {
        // 连接位置保护错误信号
        controller.positionOutOfRangeError.connect(function(motorId, position) {
            positionErrorDialog.motorId = motorId;
            positionErrorDialog.position = position;
            positionErrorDialog.open();
        });
    }

}

Dianji_1.qml

import QtQuick 2.15
import QtQuick.Controls 2.15

Rectangle {
    id: root
    
    // 添加通用属性
    property int standardMargin: 8
    property int standardSpacing: 10
    property real buttonHeight: 36
    property string primaryColor: "#228B99"
    
    Column {
        spacing: standardMargin
        anchors {
            fill: parent
            margins: standardMargin
        }
        
        // 创建通用的标题文本组件
        component TitleText: Text {
            color: "white"
            font.pixelSize: 16
            font.bold: true
            anchors.horizontalCenter: parent.horizontalCenter
        }
        
        // 创建通用的按钮组件
        component StandardButton: Rectangle {
            height: buttonHeight
            radius: 2.5
            color: "white"
            
            property alias text: buttonText.text
            
            Text {
                id: buttonText
                anchors.centerIn: parent
                color: "black"
                font.pixelSize: 14
            }
        }
        
        // 电机电流控制
        Rectangle {
            width: parent.width
            height: 75
            color: primaryColor
            radius: 5
            
            Column {
                spacing: standardMargin
                
                anchors {
                    fill: parent
                    margins: standardMargin
                }
                
                TitleText {
                    text: "行走轮电机1控制"
                }
                
                Row {
                    anchors.horizontalCenter: parent.horizontalCenter
                    spacing: standardSpacing
                    
                    // 添加按钮以打开电机状态图窗口
                    Rectangle {
                        width: 120
                        height: 36
                        radius: 5
                        color: "white"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "电机1状态图"
                            color: "black"
                            font.pixelSize: 16
                        }
                        
                        MouseArea {
                            anchors.fill: parent
                            onClicked: {
                                var component = Qt.createComponent("Motor_Status_Chart.qml");
                                if (component.status === Component.Ready) {
                                    var window = component.createObject(mainWindow);
                                    window.show();
                                } else {
                                    console.log("Error loading component:", component.errorString());
                                }
                            }
                        }
                        
                    }
                    
                    // 添加力矩模式按钮
                    Rectangle {
                        width: 100
                        height: 36
                        radius: 5
                        color: "white"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "力矩模式"
                            color: "black"
                            font.pixelSize: 16
                        }
                        
                        MouseArea {
                            anchors.fill: parent
                            onClicked: controller.set_work_mode(1, 2)  // 2表示力矩模式
                        }
                    }
                    
                    Rectangle {
                        width: 100
                        height: 36
                        radius: 5 / 2
                        border.color: "#E0E0E0"
                        
                        TextInput {
                            id: current1Input
                            
                            text: "0"
                            verticalAlignment: Text.AlignVCenter
                            selectByMouse: true
                            font.pixelSize: 16
                            
                            anchors {
                                fill: parent
                                margins: standardMargin
                            }
                            
                        }
                        
                    }
                    
                    Rectangle {
                        width: 100
                        height: 36
                        radius: 5 / 2
                        color: "white"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "设置电流"
                            color: "black"
                            font.pixelSize: 16
                        }
                        
                        MouseArea {
                            id: motor1SetCurrentArea
                            
                            anchors.fill: parent
                            onClicked: controller.set_wheel_current(parseInt(current1Input.text))
                        }
                        
                    }
                    
                    Rectangle {
                        width: 180
                        height: 36
                        color: "white"
                        opacity: 0.9
                        radius: 5

                        Text {
                            anchors.centerIn: parent
                            text: "当前电流: " + (controller ? controller.current1 : 0) + "mA"
                            font.pixelSize: 16
                        }
                    }
                    
                    Rectangle {
                        width: 32
                        height: 32
                        radius: 5 / 2
                        color: motor1RefreshArea.pressed ? "#E0E0E0" : "#F5F5F5"
                        border.color: "#E0E0E0"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "↻"
                        }
                        
                        MouseArea {
                            id: motor1RefreshArea
                            
                            anchors.fill: parent
                            onClicked: controller.read_wheel_current(1)
                        }
                        
                    }
                    
                }
                
            }
            
        }
        
        // 电机速度控制
        Rectangle {
            width: parent.width
            height: 75
            color: primaryColor
            radius: 5
            
            Column {
                spacing: standardMargin
                
                anchors {
                    fill: parent
                    margins: standardMargin
                }
                
                TitleText {
                    text: "行走轮电机1速度控制"
                }
                
                Row {
                    anchors.horizontalCenter: parent.horizontalCenter
                    spacing: standardSpacing
                    
                    // 添加速度模式按钮
                    Rectangle {
                        width: 100
                        height: 36
                        radius: 5
                        color: "white"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "速度模式"
                            color: "black"
                            font.pixelSize: 16
                        }
                        
                        MouseArea {
                            anchors.fill: parent
                            onClicked: controller.set_work_mode(1, 0)  // 0表示速度模式
                        }
                    }
                    
                    Rectangle {
                        width: 100
                        height: 36
                        radius: 5 / 2
                        border.color: "#E0E0E0"
                        
                        TextInput {
                            id: speed1Input
                            
                            text: "0"
                            verticalAlignment: Text.AlignVCenter
                            selectByMouse: true
                            font.pixelSize: 16
                            
                            anchors {
                                fill: parent
                                margins: standardMargin
                            }
                            
                        }
                        
                    }
                    
                    Rectangle {
                        width: 100
                        height: 36
                        radius: 5 / 2
                        color: "white"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "设置速度"
                            color: "black"
                            font.pixelSize: 16
                        }
                        
                        MouseArea {
                            id: setSpeed1Area
                            
                            anchors.fill: parent
                            onClicked: controller.set_motor_speed(1, parseInt(speed1Input.text))
                        }
                        
                    }
                    
                    Rectangle {
                        width: 150
                        height: 36
                        color: "white"
                        opacity: 0.9
                        radius: 5

                        Text {
                            anchors.centerIn: parent
                            text: "平均速度: " + (controller ? controller.averageSpeed1 : 0)
                            font.pixelSize: 16
                        }
                    }
                    
                    Rectangle {
                        width: 150
                        height: 36
                        color: "white"
                        opacity: 0.9
                        radius: 5

                        Text {
                            anchors.centerIn: parent
                            text: "速度误差: " + (controller ? controller.speedError1 : 0)
                            font.pixelSize: 16
                        }
                    }

                    Rectangle {
                        width: 32
                        height: 32
                        radius: 5 / 2
                        color: motor1RefreshArea.pressed ? "#E0E0E0" : "#F5F5F5"
                        border.color: "#E0E0E0"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "↻"
                        }
                        
                        MouseArea {
                            id: refreshSpeed1Area
                            
                            anchors.fill: parent
                            onClicked: {
                                controller.read_average_speed(1);
                                controller.read_speed_error(1);
                            }
                        }
                        
                    }
                    
                }
                
            }
            
        }
        
        //位置控制区域
        Rectangle {
            width: parent.width
            height: 120
            anchors.horizontalCenter: parent.horizontalCenter
            color: primaryColor
            radius: 5
            
            Column {
                spacing: standardMargin
                
                anchors {
                    fill: parent
                    margins: standardMargin
                    topMargin: standardMargin // 增加顶部边距,让标题离顶部更远一些
                }
                
                TitleText {
                    text: "行走轮电机1位置控制"
                }
                
                // 位置控制区域的 Row 布局修改(第一行按钮)
                Row {
                    anchors.horizontalCenter: parent.horizontalCenter
                    spacing: standardSpacing
                    
                    // 绝对位置控制
                    Rectangle {
                        width: 120
                        height: buttonHeight
                        radius: 2.5
                        border.color: "#E0E0E0"
                        
                        TextInput {
                            id: absolutePos1Input
                            text: "0"
                            verticalAlignment: Text.AlignVCenter
                            selectByMouse: true
                            font.pixelSize: 16
                            anchors {
                                fill: parent
                                margins: standardMargin
                            }
                            validator: IntValidator {}
                        }
                    }
                    
                    Rectangle {
                        width: 140
                        height: buttonHeight
                        radius: 2.5
                        color: "white"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "移动到绝对位置"
                            color: "black"
                            font.pixelSize: 16
                        }
                        
                        MouseArea {
                            id: moveAbsolute1Area
                            anchors.fill: parent
                            onClicked: controller.move_to_absolute_position(1, parseInt(absolutePos1Input.text))
                        }
                    }
                    
                    // 相对位置控制
                    Rectangle {
                        width: 120
                        height: buttonHeight
                        radius: 2.5
                        border.color: "#E0E0E0"
                        
                        TextInput {
                            id: relativePos1Input
                            text: "0"
                            verticalAlignment: Text.AlignVCenter
                            selectByMouse: true
                            font.pixelSize: 16
                            anchors {
                                fill: parent
                                margins: standardMargin
                            }
                            validator: IntValidator {}
                        }
                    }
                    
                    Rectangle {
                        width: 130
                        height: buttonHeight
                        radius: 2.5
                        color: "white"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "移动相对位置"
                            color: "black"
                            font.pixelSize: 16
                        }
                        
                        MouseArea {
                            id: moveRelative1Area
                            anchors.fill: parent
                            onClicked: controller.move_by_relative_position(1, parseInt(relativePos1Input.text))
                        }
                    }
                    
                    // 设置原点按钮
                    Rectangle {
                        width: 140
                        height: buttonHeight
                        radius: 2.5
                        color: "white"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "设置当前位置为原点"
                            color: "black"
                            font.pixelSize: 14
                        }
                        
                        MouseArea {
                            anchors.fill: parent
                            onClicked: controller.set_absolute_position_origin(1)
                        }
                    }
                }
                
                // 添加新的一行用于显示位置信息
                Row {
                    anchors.horizontalCenter: parent.horizontalCenter
                    spacing: standardSpacing
                    
                    // 添加位置模式按钮
                    Rectangle {
                        width: 100
                        height: 36
                        radius: 5
                        color: "white"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "位置模式"
                            color: "black"
                            font.pixelSize: 16
                        }
                        
                        MouseArea {
                            anchors.fill: parent
                            onClicked: controller.set_work_mode(1, 1)  // 1表示位置模式
                        }
                    }
                    
                    // 读取实时位置误差按钮
                    Rectangle {
                        width: 120
                        height: buttonHeight
                        radius: 2.5
                        color: "white"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "读取位置误差"
                            color: "black"
                            font.pixelSize: 16
                        }
                        
                        MouseArea {
                            anchors.fill: parent
                            onClicked: controller.read_position_error(1)
                        }
                    }
                    
                    // 显示位置误差
                    Rectangle {
                        width: 150
                        height: 36
                        color: "white"
                        opacity: 0.9
                        radius: 5

                        Text {
                            anchors.centerIn: parent
                            text: "位置误差: " + (controller ? controller.positionError1 : 0)
                            font.pixelSize: 16
                        }
                    }
                    
                    // 读取实际位置按钮
                    Rectangle {
                        width: 120
                        height: buttonHeight
                        radius: 2.5
                        color: "white"
                        
                        Text {
                            anchors.centerIn: parent
                            text: "读取实际位置"
                            color: "black"
                            font.pixelSize: 16
                        }
                        
                        MouseArea {
                            anchors.fill: parent
                            onClicked: controller.read_current_position(1)
                        }
                    }
                    
                    // 显示实际位置
                    Rectangle {
                        width: 200
                        height: 36
                        color: "white"
                        opacity: 0.9
                        radius: 5

                        Text {
                            anchors.centerIn: parent
                            text: "实际位置: " + (controller ? controller.currentPosition1 : 0)
                            font.pixelSize: 16
                        }
                    }
                }
            }
        }
        
        // 电机工作模式区域
        Rectangle {
            width: parent.width
            height: 50
            color: primaryColor
            radius: 5
            
            Row {
                anchors.centerIn: parent
                spacing: standardSpacing * 2
                
                // 添加解除急停按钮
                Rectangle {
                    width: 120
                    height: 36
                    radius: 5 / 2
                    color: "white"
                    
                    Text {
                        anchors.centerIn: parent
                        text: "解除急停"
                        color: "black"
                        font.pixelSize: 16
                    }
                    
                    MouseArea {
                        anchors.fill: parent
                        onClicked: controller.release_emergency_stop(1)
                    }
                }
                
                Rectangle {
                    width: 120
                    height: 36
                    radius: 5 / 2
                    color: "white"
                    
                    Text {
                        anchors.centerIn: parent
                        text: "读取电机1模式"
                        color: "black"
                        font.pixelSize: 16
                    }
                    
                    MouseArea {
                        id: readMode1MouseArea
                        anchors.fill: parent
                        onClicked: controller.read_work_mode(1)
                    }
                }
                
                Text {
                    id: workMode1Display
                    anchors.verticalCenter: parent.verticalCenter
                    text: controller ? controller.workMode1 : "电机1 - 未初始化"
                    color: "white"
                    font.pixelSize: 16
                }
            }
        }
        
    }
    
    // 在 QML 中连接信号
    Connections {
        function onCanMessageReceived(canId, data) {
            // 添加消息到 ListView
            messageModel.append({
                "time": new Date().toLocaleTimeString(),
                "canId": canId,
                "data": data
            });
            // 更新消息计数
            messageCount.text = "消息数量: " + messageModel.count;
        }
        
        target: controller
    }
    
}

Motor_Status_Chart.qml

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtCharts 2.15

ApplicationWindow {
    visible: true
    width: 1000
    height: 900
    title: "行走轮电机1状态图"

    Column {
        anchors.fill: parent
        spacing: 10

        // 控制按钮行
        Row {
            anchors.horizontalCenter: parent.horizontalCenter
            spacing: 20  // 增加间距
            height: 40

            Rectangle {
                width: 100
                height: 36
                radius: 5
                color: "#008B8B"

                Text {
                    anchors.centerIn: parent
                    text: "开始采样"
                    color: "white"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: dataTimer.running = true
                }
            }

            Rectangle {
                width: 100
                height: 36
                radius: 5
                color: "#FF6347"

                Text {
                    anchors.centerIn: parent
                    text: "停止采样"
                    color: "white"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: dataTimer.running = false
                }
            }

            Rectangle {
                width: 100
                height: 36
                radius: 5
                color: "#4682B4"

                Text {
                    anchors.centerIn: parent
                    text: "清空图表"
                    color: "white"
                    font.pixelSize: 16
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        // 开始新一轮显示前,清除之前的数据
                        motor1Series.clear()
                        speed1Series.clear()
                        position1Series.clear()
                        // 重置X轴范围
                        axisX.min = 0
                        axisX.max = 200
                    }
                }
            }

        }

        // 图表视图
        ChartView {
            id: chartView
            width: parent.width
            height: parent.height - 50
            antialiasing: true
            
            // 修改缩放相关属性
            animationOptions: ChartView.NoAnimation  // 禁用动画以提高性能
            theme: ChartView.ChartThemeLight        // 使用浅色主题
            
            // 启用缩放功能 - 修正属性名称
            ValueAxis {
                id: axisX
                min: 0
                max: 200  // 这个值将动态调整
                titleText: "采样点"
                tickCount: 21
                minorTickCount: 4
                gridVisible: true
            }

            ValueAxis {
                id: axisYCurrent
                min: -8000
                max: 8000
                titleText: "电流(mA)"
                tickCount: 13
                minorTickCount: 4
                gridVisible: true
            }

            ValueAxis {
                id: axisYSpeed
                min: -8000
                max: 8000
                titleText: "转速(RPM)"
                tickCount: 13
                minorTickCount: 4
                gridVisible: true
            }

            ValueAxis {
                id: axisYPosition
                min: -20000000
                max: 20000000
                titleText: "位置"
                tickCount: 15
                minorTickCount: 4
                gridVisible: true
            }

            // 添加缩放使用说明
            Text {
                anchors {
                    left: parent.left
                    bottom: parent.bottom
                    margins: 10
                }
                text: "使用说明:\n" +
                      "• 鼠标滚轮:放大/缩小\n" +
                      "• 按住左键拖动:平移图表"
                color: "black"
                font.pixelSize: 12
            }

            // 添加十字线
            Rectangle {
                id: vLine
                width: 1
                color: "black"
                opacity: 0.5
                visible: false
                y: 0
                height: parent.height
            }

            Rectangle {
                id: hLine
                height: 1
                color: "black"
                opacity: 0.5
                visible: false
                x: 0
                width: parent.width
            }

            // 数据标签
            Rectangle {
                id: dataLabel
                color: "white"
                border.color: "black"
                border.width: 1
                radius: 5
                opacity: 0.9
                visible: false
                width: dataText.width + 20
                height: dataText.height + 10

                Text {
                    id: dataText
                    anchors.centerIn: parent
                    color: "black"
                    font.pixelSize: 12
                }
            }

            // 图例标签
            Rectangle {
                id: legendBox
                color: "white"
                border.color: "black"
                border.width: 1
                radius: 5
                opacity: 0.9
                x: 10
                y: 10
                width: legendColumn.width + 20
                height: legendColumn.height + 10

                Column {
                    id: legendColumn
                    x: 10
                    y: 5
                    spacing: 5

                    Row {
                        spacing: 5
                        Rectangle {
                            width: 20
                            height: 2
                            color: "blue"
                            anchors.verticalCenter: parent.verticalCenter
                        }
                        Text {
                            text: "电流(mA)"
                            color: "black"
                            font.pixelSize: 12
                        }
                    }

                    Row {
                        spacing: 5
                        Rectangle {
                            width: 20
                            height: 2
                            color: "green"
                            anchors.verticalCenter: parent.verticalCenter
                        }
                        Text {
                            text: "转速(RPM)"
                            color: "black"
                            font.pixelSize: 12
                        }
                    }

                    Row {
                        spacing: 5
                        Rectangle {
                            width: 20
                            height: 2
                            color: "red"
                            anchors.verticalCenter: parent.verticalCenter
                        }
                        Text {
                            text: "位置"
                            color: "black"
                            font.pixelSize: 12
                        }
                    }
                }
            }

            // 合并所有鼠标事件处理一个 MouseArea
            MouseArea {
                anchors.fill: parent
                acceptedButtons: Qt.LeftButton
                hoverEnabled: true
                
                property point lastMousePos
                property bool isDragging: false
                
                // 鼠标滚轮缩放
                onWheel: {
                    var zoomFactor = 1.15
                    var mouseX = wheel.x
                    var mouseY = wheel.y
                    
                    // X轴缩放
                    var centerX = (axisX.max + axisX.min) / 2
                    var rangeX = axisX.max - axisX.min
                    
                    // Y轴缩放
                    var centerYCurrent = (axisYCurrent.max + axisYCurrent.min) / 2
                    var rangeYCurrent = axisYCurrent.max - axisYCurrent.min
                    
                    var centerYSpeed = (axisYSpeed.max + axisYSpeed.min) / 2
                    var rangeYSpeed = axisYSpeed.max - axisYSpeed.min
                    
                    var centerYPosition = (axisYPosition.max + axisYPosition.min) / 2
                    var rangeYPosition = axisYPosition.max - axisYPosition.min
                    
                    if (wheel.angleDelta.y > 0) {
                        // 放大
                        rangeX /= zoomFactor
                        rangeYCurrent /= zoomFactor
                        rangeYSpeed /= zoomFactor
                        rangeYPosition /= zoomFactor
                    } else {
                        // 缩小
                        rangeX *= zoomFactor
                        rangeYCurrent *= zoomFactor
                        rangeYSpeed *= zoomFactor
                        rangeYPosition *= zoomFactor
                    }
                    
                    // 更新X轴范围
                    axisX.min = centerX - rangeX / 2
                    axisX.max = centerX + rangeX / 2
                    
                    // 更新Y轴范围
                    axisYCurrent.min = centerYCurrent - rangeYCurrent / 2
                    axisYCurrent.max = centerYCurrent + rangeYCurrent / 2
                    
                    axisYSpeed.min = centerYSpeed - rangeYSpeed / 2
                    axisYSpeed.max = centerYSpeed + rangeYSpeed / 2
                    
                    axisYPosition.min = centerYPosition - rangeYPosition / 2
                    axisYPosition.max = centerYPosition + rangeYPosition / 2
                    
                    wheel.accepted = true
                }
                
                // 鼠标按下开始拖动
                onPressed: {
                    lastMousePos = Qt.point(mouse.x, mouse.y)
                    isDragging = true
                    cursorShape = Qt.ClosedHandCursor
                }
                
                // 鼠标拖动和数据显示
                onPositionChanged: {
                    if (isDragging) {
                        var dx = mouse.x - lastMousePos.x
                        
                        // 只处理X轴的平移
                        var rangeX = axisX.max - axisX.min
                        var moveX = -dx * rangeX / width
                        
                        // 只更新X轴范围
                        axisX.min += moveX
                        axisX.max += moveX
                        
                        lastMousePos = Qt.point(mouse.x, mouse.y)
                    }
                    
                    // 数据显示逻辑
                    if (containsMouse) {
                        var chartPos = chartView.mapToValue(Qt.point(mouse.x, mouse.y))
                        
                        // 更新十字线位置
                        vLine.x = mouse.x
                        hLine.y = mouse.y
                        vLine.visible = true
                        hLine.visible = true
                        
                        // 查找最近的数据点
                        var index = Math.round(chartPos.x)
                        if (index >= 0 && index < motor1Series.count) {
                            var currentValue = motor1Series.at(index).y
                            var speedValue = speed1Series.at(index).y
                            var positionValue = position1Series.at(index).y
                            
                            // 更新数据标签
                            dataText.text = "采样点: " + index + "\n" +
                                          "电流: " + currentValue.toFixed(2) + " mA\n" +
                                          "转速: " + speedValue.toFixed(2) + " RPM\n" +
                                          "位置: " + positionValue.toFixed(2)
                            
                            dataLabel.x = Math.min(mouse.x + 10, parent.width - dataLabel.width - 10)
                            dataLabel.y = Math.min(mouse.y + 10, parent.height - dataLabel.height - 10)
                            dataLabel.visible = true
                        }
                    }
                }
                
                // 鼠标释放结束拖动
                onReleased: {
                    isDragging = false
                    cursorShape = Qt.ArrowCursor
                }
                
                // 鼠标离开
                onExited: {
                    vLine.visible = false
                    hLine.visible = false
                    dataLabel.visible = false
                }
            }

            // 添加 ToolTip 定义
            ToolTip {
                id: tooltip
                visible: false
                delay: 0
                timeout: 5000
                background: Rectangle {
                    color: "white"
                    border.color: "black"
                    radius: 5
                    opacity: 0.9
                }
                contentItem: Text {
                    color: "black"
                    font.pixelSize: 12
                }
            }

            LineSeries {
                id: motor1Series
                name: "电机1电流"
                color: "blue"
                axisX: axisX
                axisY: axisYCurrent
                onHovered: {
                    if (state) {
                        tooltip.text = `采样点: ${Math.round(point.x)}\n电流: ${Math.round(point.y)} mA`
                        tooltip.x = chartView.mapToPosition(point, motor1Series).x + 10
                        tooltip.y = chartView.mapToPosition(point, motor1Series).y + 10
                        tooltip.visible = true
                    } else {
                        tooltip.visible = false
                    }
                }
            }

            LineSeries {
                id: speed1Series
                name: "电机1转速"
                color: "green"
                axisX: axisX
                axisY: axisYSpeed
                onHovered: {
                    if (state) {
                        tooltip.text = `采样点: ${Math.round(point.x)}\n转速: ${Math.round(point.y)}`
                        tooltip.x = chartView.mapToPosition(point, speed1Series).x + 10
                        tooltip.y = chartView.mapToPosition(point, speed1Series).y + 10
                        tooltip.visible = true
                    } else {
                        tooltip.visible = false
                    }
                }
            }

            // 添加位置数据序列
            LineSeries {
                id: position1Series
                name: "电机1位置"
                color: "red"
                axisX: axisX
                axisY: axisYPosition
                onHovered: {
                    if (state) {
                        tooltip.text = `采样点: ${Math.round(point.x)}\n位置: ${Math.round(point.y)}`
                        tooltip.x = chartView.mapToPosition(point, position1Series).x + 10
                        tooltip.y = chartView.mapToPosition(point, position1Series).y + 10
                        tooltip.visible = true
                    } else {
                        tooltip.visible = false
                    }
                }
            }   
        }
    }

    Timer {
        id: dataTimer
        interval: 300
        running: false
        repeat: true
        onTriggered: {
            // 主动读取电机1的电流值、转速和位置
            controller.read_wheel_current(1)
            controller.read_average_speed(1)
            controller.read_current_position(1)

            // 添加电机1的数据
            motor1Series.append(motor1Series.count, controller.current1)
            speed1Series.append(speed1Series.count, controller.averageSpeed1)
            position1Series.append(position1Series.count, controller.currentPosition1)

            // 动态调整X轴显示范围,始终显示最新的200个数据点
            if (motor1Series.count > axisX.max) {
                axisX.min = motor1Series.count - 200
                axisX.max = motor1Series.count
            }
        }
    }
}

项目代码存在的不足之处:

1. 代码重复严重

项目中存在大量重复代码,特别是在电机控制逻辑中:

(1) 各个电机控制函数高度相似,如`set_wheel_current`和`set_wheel2_current`几乎完全相同,只是电机ID不同;

(2) QML界面中每个电机的控制面板(DianJi_1.qml至DianJi_10.qml)内容高度重复;

(3)电机状态图表文件(Motor_Status_Chart.qml, Motor2_Status_Chart.qml等)代码几乎相同。

 2. 缺乏面向对象设计

(1) `CanController`类过于庞大(2300多行),职责不清晰;

(2)没有为不同类型的电机创建专门的类,而是在一个类中混合处理所有电机;

(3)重复的信号定义(如motor1SpeedChanged到motor10SpeedChanged).

3. 配置硬编码

(1)电机ID和CAN ID的映射硬编码在类的`__init__`方法中;

(2)位置保护范围(POSITION_MIN/POSITION_MAX)硬编码为固定值;

(3)没有集中的配置管理机制。

4. 错误处理不完善

(1)许多函数简单打印错误而不是采用结构化的错误处理方式;

(2)缺少统一的日志系统,调试信息直接使用print输出;

(3) 异常处理不够全面,如CAN通信中断等情况处理不完善。

改进建议

1. 重构代码结构

robotcontrol/
├── config/                 # 配置文件目录
│   └── motor_config.json   # 电机配置
├── models/                 # 数据模型
│   ├── motor_model.py      # 电机模型基类
│   ├── type1_motor.py      # 类型1电机
│   └── type2_motor.py      # 类型2电机
├── controllers/            # 控制器
│   ├── can_controller.py   # CAN通信控制器
│   ├── motor_controller.py # 电机控制基类
│   └── robot_controller.py # 机器人总控制器
├── ui/                     # UI相关
│   ├── components/         # 可复用组件
│   │   ├── motor_panel.qml # 电机面板组件
│   │   └── status_chart.qml# 状态图表组件
│   └── main_window.qml     # 主窗口
├── utils/                  # 工具函数
│   ├── can_utils.py        # CAN通信工具
│   └── logger.py           # 日志工具
└── main.py                 # 主入口

2. 实现面向对象设计

创建电机基类和派生类:
class MotorBase:
    """电机基类,定义共同接口"""
    def __init__(self, motor_id, can_id):
        self.motor_id = motor_id
        self.can_id = can_id
        # 共同属性
        
    def set_current(self, current):
        """设置电流"""
        pass
        
    def read_current(self):
        """读取电流"""
        pass

class Type1Motor(MotorBase):
    """类型1电机实现"""
    def set_current(self, current):
        # 类型1特定实现
        
class Type2Motor(MotorBase):
    """类型2电机实现"""
    def set_current(self, current):
        # 类型2特定实现
封装CAN通信:
class CanCommunicator:
    """处理CAN通信的类"""
    def __init__(self):
        self.ch = None
        
    def initialize(self):
        """初始化CAN通道"""
        pass
        
    def send_message(self, can_id, data, dlc=8):
        """发送CAN消息"""
        pass
        
    def read_message(self, timeout=100):
        """读取CAN消息"""
        pass
使用配置文件

创建JSON配置文件存储电机参数:

{
  "motors": [
    {
      "id": 1,
      "can_id": "0x88",
      "type": "type1",
      "position_limits": [150000, 350000],
      "max_current": 5000
    },
    {
      "id": 2,
      "can_id": "0x99",
      "type": "type1",
      "position_limits": [150000, 350000],
      "max_current": 5000
    }
  ]
}

改进错误处理和日志系统

import logging

# 配置日志系统
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler("robot_control.log"),
        logging.StreamHandler()
    ]
)

logger = logging.getLogger("RobotControl")

# 使用日志而非print
logger.info("CAN通道已初始化成功")
logger.error(f"初始化错误: {e}")
改进UI组件复用
1. 创建可复用的电机控制面板组件:
// MotorPanel.qml
import QtQuick 2.15
import QtQuick.Controls 2.15

Rectangle {
    id: root
    
    // 属性接口
    property int motorId: 1
    property string motorName: "电机" + motorId
    property color panelColor: "#228B99"
    
    // 信号定义
    signal setCurrentRequested(int motorId, int current)
    signal setSpeedRequested(int motorId, int speed)
    signal readCurrentRequested(int motorId)
    
    width: parent.width
    height: 75
    color: panelColor
    radius: 5
    
    // 面板内容...
    
    // 处理事件
    function onSetCurrentClicked() {
        setCurrentRequested(motorId, parseInt(currentInput.text))
    }
}

// 使用组件
MotorPanel {
    motorId: 1
    motorName: "行走轮电机1"
    panelColor: "#228B99"
    
    onSetCurrentRequested: function(motorId, current) {
        controller.set_motor_current(motorId, current)
    }
}
2. 创建可复用的状态图表:
// StatusChart.qml
import QtQuick 2.15
import QtCharts 2.15

ChartView {
    property int motorId: 1
    property string motorName: "电机" + motorId
    
    // 图表实现...
}

3.进一步改进想法

实现观察者模式监控电机状态

class MotorObserver:
    """电机观察者接口"""
    def update(self, motor_id, param_name, value):
        pass

class DataLogger(MotorObserver):
    """数据记录器"""
    def __init__(self, log_file):
        self.log_file = log_file
        
    def update(self, motor_id, param_name, value):
        # 将数据写入日志文件
        with open(self.log_file, 'a') as f:
            f.write(f"{time.time()},{motor_id},{param_name},{value}\n")

class AlarmMonitor(MotorObserver):
    """报警监控器"""
    def __init__(self, alarm_callback):
        self.alarm_callback = alarm_callback
        self.thresholds = {}  # 存储参数阈值
        
    def set_threshold(self, motor_id, param_name, min_val, max_val):
        """设置阈值"""
        self.thresholds[(motor_id, param_name)] = (min_val, max_val)
        
    def update(self, motor_id, param_name, value):
        """检查参数是否超出阈值"""
        key = (motor_id, param_name)
        if key in self.thresholds:
            min_val, max_val = self.thresholds[key]
            if value < min_val or value > max_val:
                self.alarm_callback(motor_id, param_name, value, min_val, max_val)

class MotorSubject:
    """可被观察的电机主题"""
    def __init__(self):
        self.observers = []
        
    def add_observer(self, observer):
        if observer not in self.observers:
            self.observers.append(observer)
            
    def remove_observer(self, observer):
        if observer in self.observers:
            self.observers.remove(observer)
            
    def notify_observers(self, motor_id, param_name, value):
        for observer in self.observers:
            observer.update(motor_id, param_name, value)

使用工厂模式创建电机对象

class MotorFactory:
    """电机工厂类,根据配置创建不同类型的电机"""
    @staticmethod
    def create_motor(config):
        motor_type = config['type']
        motor_id = config['id']
        can_id = config['can_id']
        
        if motor_type == 'type1':
            return Type1Motor(motor_id, can_id)
        elif motor_type == 'type2':
            return Type2Motor(motor_id, can_id)
        elif motor_type == 'type3':
            return Type3Motor(motor_id, can_id)
        else:
            raise ValueError(f"不支持的电机类型: {motor_type}")
            
    @staticmethod
    def create_motors_from_config(config_file):
        """从配置文件创建多个电机"""
        with open(config_file, 'r') as f:
            config = json.load(f)
            
        motors = {}
        for motor_config in config['motors']:
            motor = MotorFactory.create_motor(motor_config)
            motors[motor.motor_id] = motor
            
        return motors

QML组件化和数据绑定优化

创建电机状态模型:
// MotorStates.qml
QtObject {
    id: motorStates
    
    // 创建一个模型来管理所有电机状态
    property var motorModel: ListModel {
        // 为每个电机添加一个初始状态
        ListElement {
            motorId: 1
            current: 0
            speed: 0
            position: 0
            mode: "未初始化"
        }
        // 其他电机...
    }
    
    // 根据ID获取电机状态
    function getMotorState(id) {
        for(var i = 0; i < motorModel.count; i++) {
            if(motorModel.get(i).motorId === id) {
                return motorModel.get(i);
            }
        }
        return null;
    }
    
    // 更新电机状态
    function updateMotorParameter(id, param, value) {
        for(var i = 0; i < motorModel.count; i++) {
            if(motorModel.get(i).motorId === id) {
                motorModel.setProperty(i, param, value);
                return;
            }
        }
    }
}

改进电机控制面板组件:

// MotorControl.qml - 通用电机控制组件
import QtQuick 2.15
import QtQuick.Controls 2.15

Item {
    id: root
    width: parent.width
    height: childrenRect.height
    
    // 导出属性
    property int motorId: 1
    property string motorName: "电机" + motorId
    property string panelColor: "#228B99"
    
    // 绑定到数据模型
    property var motorState: motorStates.getMotorState(motorId)
    
    // 布局包含所有控制组件
    Column {
        width: parent.width
        spacing: 10
        
        // 电流控制面板
        CurrentPanel {
            motorId: root.motorId
            current: motorState.current
            onCurrentChanged: controller.set_motor_current(motorId, current)
        }
        
        // 速度控制面板
        SpeedPanel {
            motorId: root.motorId
            speed: motorState.speed
            onSpeedChanged: controller.set_motor_speed(motorId, speed)
        }
        
        // 位置控制面板
        PositionPanel {
            motorId: root.motorId
            position: motorState.position
            onPositionChanged: controller.set_target_position(motorId, position)
        }
    }
    
    // 监听数据变化
    Connections {
        target: controller
        
        function onMotorParameterChanged(id, param, value) {
            if(id === motorId) {
                motorStates.updateMotorParameter(id, param, value);
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值