一,设计思路

设计思路通过分层抽象工厂模式构建“硬件与软件结合” 的架构,目标是实现 “更换运动控制硬件时,下层软件无需修改”

物料搬运实现  ← 最上层:实现具体的物料搬运业务流程(如 “取料→转移→

      放料” 的循环逻辑),只关心 “做什么”,不关心 “硬件如何做”

▼ ,              只依赖HAL 完全不接触底层运动卡的具体实现

硬件抽象层          抽象层,提供统一的硬件操作接口,HAL 的接口和逻辑

           轴映射是 “与硬件无关的抽象”,更换运动卡时,只需确保

        新卡的物理轴能通过映射对应到逻辑轴,HAL 的代码无需改动

运动卡管理类  ← 实例管理层,管理类只认 “运动卡基类” 的接口,无论新增 /

               更换哪种卡(只要继承基类),管理类的 “管理逻辑”

                   如批量初始化、切换卡)都无需改变

运动卡基类                      ← 抽象接口层,被具体运动卡实现继承

    

┌────────────────┐

                  ▼

运动卡A实现  运动卡B实现              ← 具体实现层,并列关系,继承自基类

└────────┬───── ─┘

运动卡工厂类      实例创建层,负责创建运动卡A/B的实例(返回基类指针)

运动

实现

MaterialHandlingSystem

物料搬运流程(取料 / 传递 / 放料)

依赖HardwareAbstraction的接口

硬件

抽象

HardwareAbstraction

逻辑轴→物理轴转换,屏蔽硬件差异

依赖CMotionControllerManager

理层

CMotionControllerManager

管理多个控制器(创建 / 切换 / 初始化)

依赖CMotionControllerBase及其派生类

控制

器层

派生类(固高,研控等)

具体硬件的运动控制(固高 / 研控 / 模拟)

继承CMotionControllerBase接口

工厂层

CMotionControllerFactory

创建控制器实例,统一管理生命周期

依赖所有控制器派生类

二,设计过程

我们已经有运动控制管理器、工厂类和基类,现在需要实现一个物料搬运系统,使用状态机和任务队列的混合方案。
由于我们已经有管理类,我们可以直接使用它来管理多个控制卡。但是注意,题目要求使用一个卡完成控制,但切换卡后另一张也能支持控制。
因此,我们需要构建一个硬件抽象层,将具体的轴映射到逻辑轴,这样无论底层使用哪个控制卡,我们都可以用相同的逻辑轴编号来控制。

步骤:

设计硬件抽象层,将逻辑轴映射到物理轴(控制卡号+轴号)。

设计物料搬运系统,使用状态机和任务队列。

在对话框中集成物料搬运系统,并处理控制卡切换。

物料搬运系统

├── 运动控制器管理层 (MotionControllerManager)

│   ├── 左臂控制卡 (卡0)

│   └── 右臂控制卡 (卡0)

├── 状态机引擎

│   ├── 取料状态

│   ├── 传递状态  

│   └── 放料状态

└── 运动执行层

    ├── 6个核心运动函数

    └── 同步协调机制

三,使用方法,各层解释

状态机是一种 “用状态描述行为、用规则控制转换” 的模型,通过抽象复杂逻辑,让系统行为更可控、可维护。它的核心思想是:“在什么状态下,发生什么事件,会转到什么新状态,以及执行什么动作

状态(State):对象在某一时刻的稳定形态,是行为的基础。 例如:电梯的 “停止”“上升”“下降”;交通信号灯的 “红灯”“黄灯”“绿灯”。(注意:状态是 “有限的”—— 数量固定且可枚举)0

1事件(Event):触发状态转换的外部或内部条件。例如:电梯收到 “5 楼按钮信号”(外部事件);交通信号灯的 “30 秒计时结束”(内部事件)。

转换(Transition):当某个事件发生时,从当前状态切换到另一个状态的过程。例如:交通信号灯 “绿灯” 时,若 “30 秒计时结束”(事件),则转换到 “黄灯”(新状态)。

动作(Action):状态转换时或处于某状态时执行的操作。例如:电梯从 “停止” 转换到 “上升” 时,启动电机(动作);处于 “红灯” 状态时,禁止车辆通行(持续动作)。

任务队列模式是一种用于管理和调度任务执行的设计模式,核心思想是将待执行的任务(工作单元)存储在一个 “队列” 中,由专门的 “消费者” 按顺序或规则从队列中取出任务并执行,从而实现任务的异步处理、解耦生产者与消费者、平衡系统负载。

任务(Task):需要执行的具体工作单元,可包含执行逻辑、参数、优先级等信息(例如 “打印文件”“发送邮件”“控制机械臂移动到坐标 X”)。

任务队列(Queue):存储任务的数据结构(通常是先进先出 FIFO,也可支持优先级排序),作为生产者和消费者之间的 “缓冲层”。

生产者(Producer):创建任务并将其加入队列的角色(例如用户点击 “打印” 按钮、传感器触发 “采集数据” 指令)。

消费者(Consumer):从队列中取出任务并执行的角色(可以是单个线程、多个线程池,甚至分布式节点)。

工作流程

生产任务:生产者根据业务需求创建任务(如解析用户请求、检测到设备状态变化),并将任务添加到队列中。

存储任务:队列按规则(如 FIFO、优先级)暂存任务,等待被消费。

消费任务:消费者持续从队列中获取任务(通常是 “取一个执行一个” 的循环),执行任务逻辑(如调用函数、运行脚本、控制硬件)。

完成 / 反馈:任务执行完成后,可能返回结果(如执行状态、输出数据),或通过回调、日志等方式通知生产者。

硬件抽象层和运动卡管理类有什么

维度

硬件抽象层(HAL)

运动卡管理类

范围

覆盖所有硬件(运动卡、传感器、执行器等)

仅针对运动卡一种硬件

核心目标

统一接口,屏蔽不同硬件的差异

封装特定运动卡的操作,实现其功能

抽象程度

高(只定义 “做什么”,不涉及硬件细节)

低(需了解运动卡的协议、驱动细节)

依赖关系

依赖底层硬件的管理类(包括运动卡管理类)

依赖具体运动卡的驱动或协议

HardwareAbstraction(硬件抽象层)的完整实现,是连接上层业务逻辑(如物料搬运系统)与底层运动控制器的 “桥梁”。它通过逻辑轴与物理轴的映射、统一的硬件操作接口和错误处理

构造函数:绑定运动控制器管理器

HardwareAbstraction::HardwareAbstraction(CMotionControllerManager& manager)

: m_motionManager(manager){}

功能:通过初始化列表绑定 m_motionManager(运动控制器管理器的引用),获取底层运动控制器的管理能力。

设计意义:采用 “依赖注入” 模式,HAL 不直接创建控制器,而是依赖外部传入的管理器,确保层间解耦

MaterialHandlingSystem(物料搬运系统)

定位:最上层,实现业务逻辑(取料、传递、放料流程)。

职责:通过控制逻辑轴的运动,完成物料搬运的完整流程(多轴协同、阶段切换、超时检测等)。

依赖:通过构造函数接收HardwareAbstraction的引用(m_hardware),依赖其提供的轴操作接口。

CMotionControllerManager(运动控制器管理器)

定位:最底层,直接管理各类运动控制器(固高、研控、模拟)。

职责:创建 / 删除控制器、初始化 / 关闭控制器、切换当前控制器、统一执行急停 / 使能等操作。

持有对象:内部维护多个CMotionControllerBase(运动控制器基类)的派生实例(CGTSMotionController、CYKMotionController等)。

数据的传递(引用+成员变量)

初始化时的关联

在CmachinemotionDlg(对话框类)中,三者的创建顺序是:CMotionControllerManager m_motionManager(先创建)→HardwareAbstraction m_hardware(m_motionManager)(通过构造函数传入管理器引用)→MaterialHandlingSystem m_materialSystem(m_hardware)(通过构造函数传入硬件抽象层引用)。

最终形成:m_materialSystem → m_hardware → m_motionManager的传递

运行时的数据传递

上层(物料系统)需要控制轴运动时,通过m_hardware调用硬件抽象层的方法(MoveAxis等),传递 “逻辑轴号” 和 “目标位置”。

硬件抽象层将 “逻辑轴号” 转换为 “物理轴号” 后,通过m_motionManager获取当前控制器(GetCurrentController),调用控制器的具体运动方法(如AbsoluteMove)。

控制器执行后,状态(如当前位置、运动是否完成)通过硬件抽象层回传给物料系统(如GetAxisPosition、IsMotionComplete)。

核心函数(按层级划分)

1. CMotionControllerManager(底层控制器管理)

CreateController

创建指定类型的控制器(固高 / 研控 / 模拟),存入内部容器m_controllers。

InitializeSystem

初始化所有已创建的控制器(调用每个控制器的Initialize)。

GetCurrentController

获取当前激活的控制器实例(m_pCurrentController),供上层调用。

EmergencyStopAll

对所有控制器执行急停(调用每个控制器的EmergencyStop)。

SwitchController

切换当前控制器(用于多卡场景)。

2. HardwareAbstraction(中层硬件抽象)

MoveAxis

移动单个逻辑轴(转换为物理轴后调用控制器的AbsoluteMove)。

MoveAxes

同时移动多个逻辑轴(批量转换后调用控制器的运动方法)。

GetAxisPosition

获取逻辑轴当前位置(转换为物理轴后调用控制器的GetCurrentPosition)。

LogicalToPhysical

逻辑轴→物理轴映射(核心转换逻辑,如左 Y 轴 0→物理轴 0)。

WaitForMotionComplete

等待逻辑轴运动完成(轮询控制器的IsMotionComplete)。

3. MaterialHandlingSystem(上层业务逻辑)

StartProcess

启动物料搬运流程(创建工作线程WorkingThread)。

RunProcess

流程主循环(按状态机切换取料 / 传递 / 放料阶段)。

ExecuteLoadPhase/ExecuteTransferPhase/ExecuteUnloadPhase

取料 / 传递 / 放料阶段的具体实现(调用硬件抽象层控制轴运动)。

EmergencyStop

紧急停止(调用硬件抽象层的EmergencyStop,终止所有运动)。

卡关系

CMotionControllerFactory、CGTSMotionController、CYKMotionController)是运动控制器的核心实现,通过 “工厂模式 + 多态” 实现了不同硬件控制卡(固高、研控)的统一管理和操作

一、类之间的关系:工厂模式 + 继承多态

三者通过 “基类抽象 + 派生类实现 + 工厂创建” 的模式协作,核心是 “屏蔽硬件差异,提供统一接口”。

工厂模式(Factory )是一种创建型设计模式,核心作用是封装对象的创建过程,通过专门的 “工厂类” 来负责对象的实例化,而不是让上层代码直接使用new关键字创建对象。

核心结构

1.产品接口定义所有具体产品的通用接口(抽象类或纯虚类),规定了产品必须实现的方法。如:运动控制器的基类CMotionControllerBase,定义了Initialize、AbsoluteMove等接口。

2.具体产品实现产品接口的具体类,对应不同的 “产品实例”。例如:CGTSMotionController(固高控制器)、CYKMotionController(研控控制器),它们都继承自CMotionControllerBase。

3.工厂类提供创建产品的方法(静态),根据输入参数(如类型)创建对应的具体产品实例,并返回产品接口的指针。例如:CMotionControllerFactory,通过CreateController方法根据MotionControllerType创建固高或研控控制器。

1. 继承关系:基类定义接口,派生类实现具体硬件逻辑

基类CMotionControllerBase(未直接提供代码,但从上下文可知):定义了所有运动控制器的通用接口(纯虚函数),如Initialize(初始化)、AbsoluteMove(绝对运动)、EnableAxis(使能轴)等,是所有具体控制器的 “标准模板”。

派生类CGTSMotionController和CYKMotionController:分别继承自CMotionControllerBase,实现了基类的所有纯虚函数,针对 “固高控制卡” 和 “研控控制卡” 的硬件特性编写具体逻辑(如固高的GT_XXX函数、研控的YK_XXX函数)。例如:CGTSMotionController::AbsoluteMove实现固高卡的绝对运动,CYKMotionController::AbsoluteMove实现研控卡的绝对运动,但对外接口完全一致。

2. 依赖关系:工厂类负责创建具体控制器实例

CMotionControllerFactory(工厂类):依赖CGTSMotionController和CYKMotionController,通过CreateController方法根据类型(MotionControllerType)创建对应的控制器实例,并返回基类指针(CMotionControllerBase*)。作用:封装控制器的创建过程,上层代码无需直接new具体控制器,只需调用工厂方法,降低耦合。

从创建到操作的完整步骤

  1. 运动卡管理类通过调用工厂的CreateController方法,传入控制器类型和卡号,获取基类指针

管理类使用

CMotionControllerBase* pController = CMotionControllerFactory::CreateController(MC_GTS, 0); // 创建固高卡(卡号0)

工厂内部创建

case MC_GTS:

return new CGTSMotionController(cardNo); // 传入卡号0

  1. 初始化控制器

通过基类指针调用Initialize方法,初始化硬件(不同控制器的初始化逻辑不同,但接口一致)

管理器中的使用

pController->Initialize();

  1. 操作控制器(使能轴、运动控制等)

通过基类指针调用通用接口,实际执行的是派生类的具体实现(多态特性)

轴使能

pController->EnableAxis(0);

轴运动

pController->AbsoluteMove(0, 50.0);

  1. 查询状态(如当前位置、是否使能)

通过基类指针获取控制器状态,内部由派生类实现具体的查询逻辑

// 获取轴0当前位置

double pos = pController->GetCurrentPosition(0);

// 检查轴0是否使能

BOOL isEnabled = pController->IsAxisEnabled(0);

  1. 销毁控制器

通过工厂的DestroyController方法释放资源(避免上层直接调用delete,统一管理)

CMotionControllerFactory::DestroyController(pController);

四,整体框架解释

以 “物料系统执行取料阶段,控制左 Y 轴(逻辑轴 0)移动到取料位置” 为例

1:运动系统发起流程

MaterialHandlingSystem通过工作线程启动取料流程,调用ExecuteLoadPhase:

// MaterialHandlingSystem::StartProcess() 启动线程

CWinThread* pThread = AfxBeginThread(WorkingThread, this);

// 线程函数调用RunProcess,根据状态执行取料阶段

void MaterialHandlingSystem::RunProcess() {

if (m_currentState == SystemState::LOADING) {

ExecuteLoadPhase(); // 执行取料

}}

然后在ExecuteLoadPhase中,调用硬件抽象层中的MoveAxis,传递轴号和位置

if (!m_hardware.MoveAxis(0, m_systemPositions.load_left_y))

return FALSE;

 2:抽象层转换轴号并调用管理器

HardwareAbstraction::MoveAxis接收逻辑轴号,转换为物理轴号,再通过管理器获取当前控制器:

BOOL HardwareAbstraction::MoveAxis(int logical_axis, double position) {

    // 1. 逻辑轴→物理轴转换(核心:解耦业务与硬件轴号)

    int physical_axis = LogicalToPhysical(logical_axis);

    // 例如:逻辑轴0(左Y轴)→ 物理轴m_axisMapping.left_y_axis(如0)

    // 2. 通过管理器获取当前激活的控制器

    CMotionControllerBase* pController = m_motionManager.GetCurrentController();

    if (!pController) return FALSE;

    // 3. 调用控制器的绝对运动方法(传递物理轴和位置)

    return pController->AbsoluteMove(physical_axis, position); }

具体转换逻辑

int HardwareAbstraction::LogicalToPhysical(int logical_axis) {

    switch (logical_axis) {

    case 0: return m_axisMapping.left_y_axis; // 左Y轴→物理轴(如0)

    case 1: return m_axisMapping.left_z_axis; // 左Z轴→物理轴(如1)

    }}

3:管理层提供控制器实例

CMotionControllerManager管理多个控制器,GetCurrentController返回当前激活的控制器:

CMotionControllerBase* CMotionControllerManager::GetCurrentController() {

    return m_pCurrentController; // 指向当前选中的控制器(如固高卡)}

控制器的创建由管理器通过工厂完成(初始化时)

BOOL CMotionControllerManager::CreateController(MotionControllerType type, int cardNo) {

    // 调用工厂创建控制器实例

tionControllerBase*pController =CMotionControllerFactory::CreateController(type, cardNo);

    if (pController) {

        m_controllers[cardNo] = pController; // 存入map管理

        m_pCurrentController = pController; // 设置为当前控制器

        return TRUE;

    }}

 4:控制器层执行硬件操作

CGTSMotionController实现AbsoluteMove,执行固高卡的绝对运动逻辑:

BOOL CGTSMotionController::AbsoluteMove(int axis, double position)

5:状态回传(从控制器到业务层)

物料系统等待运动完成,调用WaitForMotionComplete,逐层查询状态:

// MaterialHandlingSystem::WaitForMotionCompletewhile (true) {

    for (int axis : axes) {

        if (!m_hardware.IsMotionComplete(axis)) { // 调用抽象层

            all_complete = FALSE; break;

        }

    }

    if (all_complete) return TRUE;

    // ...超时检测}

抽象层查询控制器状态:

BOOL HardwareAbstraction::IsMotionComplete(int logical_axis) {

    int physical_axis = LogicalToPhysical(logical_axis);

    auto pController = m_motionManager.GetCurrentController();

    return pController ? pController->IsMotionComplete(physical_axis) : FALSE;}

控制器返回运动状态(以固高为例)

BOOL CGTSMotionController::IsMotionComplete(int axis)

五,总结

数据传递:

运动系统(逻辑轴、位置)→ 抽象层(转物理轴)→ 管理器(获取控制器)→ 控制器(执行硬件操作)→ 状态沿原路返回。

核心函数:

运动系统层:StartProcess/ExecuteLoadPhase(发起流程)。

抽象层:MoveAxis/LogicalToPhysical(转换与转发)。

管理层:CreateController/GetCurrentController(管理实例)。

控制器:AbsoluteMove/IsMotionComplete(硬件操作与状态查询)。

简单工厂模式:控制器创建的“统一入口”

应用:多控制器派生类的实例化(固高、研控、模拟)

核心:上层(管理层)无需直接new具体控制器,只需调用工厂方法并传入类型,新增控制器时仅需修改工厂类,符合“开闭原则”

体现:CMotionControllerFactory::CreateController()通过switch-case匹配类型,返回对应实例

多态:实现的具体差异

应用:不同控制器的统一调用(如AbsoluteMove)

核心:管理层通过CMotionControllerBase*指针调用接口,实际执行派生类的具体实现,无需区分硬件类型

体现:pController->AbsoluteMove(...),指针指向固高则执行CGTS的实现,指向研控则执行CYK的实现

分层思想:分层控制,方便管理

每层仅关注自身职责,修改某一层不影响其他层:

修改物料搬运流程(业务层),无需改动硬件操作代码

新增运动控制卡品牌(控制器层),仅需新增派生类并扩展工厂,上层无感知

调整逻辑轴映射规则(抽象层),业务层无需修改调用方式

维护使用:

可扩展性:新增控制卡时,仅需:① 新增继承基类的派生类;② 在工厂类中添加case分支,上层代码无改动

可维护性:硬件相关代码集中在控制器层,业务逻辑集中在业务层,定位问题时可快速锁定层级

实用性:通过模拟控制器(CSimulationMotionController)支持离线调试,降低硬件依赖,提升开发效率

六,待优化和思考问题

待优化与思考

1.目前工厂类为简单工厂,新增控制器需修改工厂代码,可升级为工厂方法模式进一步优化

2.线程安全:工作线程与UI线程的交互未做同步处理,实际应用中需通过临界区或信号量优化

3.错误处理:可引入日志系统,将m_lastOperation的操作记录持久化,便于问题追溯

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐