当前位置: 首页 > news >正文

自动化设备控制系统 / Qt + 嵌入式设备软件

一个大型项目(例如自动化设备控制系统 / Qt + 嵌入式设备软件)是如何从最初设计 → 实施 → 遇到问题 → 重构 → 最终形成成熟架构的。

整个过程会完全按照真实工程师的思考过程来讲,而不是直接给一个“完美架构”。

假设我们开发一个自动化检测设备软件,设备包含:

  • 电机(移动平台)
  • 相机(拍照检测)
  • 温度传感器
  • TCP通信
  • UI操作界面

一、阶段1:最初期设计(简单实现)

项目刚开始时,需求很简单:

需求:

1 启动设备 2 控制电机移动 3 拍照 4 显示温度

工程师通常会先写一个简单结构

project ├── main.cpp ├── MainWindow.cpp ├── Motor.cpp ├── Camera.cpp └── Sensor.cpp

代码示例

UI直接调用设备:

classMainWindow{public:voidstartMotor(){motor.start();}voidtakePhoto(){camera.capture();}voidshowTemp(){doublet=sensor.read();}private:Motor motor;Camera camera;Sensor sensor;};

设备类:

classMotor{public:voidstart(){writeRegister(0x01,1);}};

优点

开发快
代码简单


问题很快出现

随着需求增加:

1 支持远程控制 2 加入电机速度控制 3 加入自动检测流程 4 加入日志

代码开始变成:

MainWindow{Motor motor;Camera camera;Sensor sensor;TcpServer tcp;}

UI里全是逻辑:

voidMainWindow::onStartClicked(){motor.start();tcp.send("motor started");}

二、阶段2:第一次重构(Controller)

工程师发现问题:

❌ UI代码太复杂
❌ 逻辑到处都是
❌ UI直接控制硬件

于是进行第一次重构

引入:

Controller

新结构

project ├── ui │ └── MainWindow │ ├── controller │ ├── MotorController │ ├── CameraController │ └── SensorController │ └── driver ├── MotorDriver ├── CameraDriver └── SensorDriver

UI变简单

voidMainWindow::onStartClicked(){motorController.start();}

Controller

classMotorController{public:voidstart(){driver.enable();}private:MotorDriver driver;};

Driver

classMotorDriver{public:voidenable(){writeRegister(0x01,1);}};

调用流程

UI ↓ Controller ↓ Driver ↓ Hardware

三、阶段3:增加算法(Algorithm)

项目继续发展:

新需求:

1 电机需要PID控制 2 需要轨迹规划 3 需要图像处理

Controller开始变复杂:

classMotorController{public:voidupdate(){doubleerror=target-pos;doubleoutput=pid.update(error);driver.setPWM(output);}};

工程师发现:

❌ 算法和控制逻辑混在一起

于是进行第二次重构。


引入 Algorithm 层

新结构:

project ├── controller ├── algorithm └── driver

Algorithm

classPID{public:doubleupdate(doubleerror){returnkp*error+ki*sum+kd*diff;}};

Controller

classMotorController{public:voidupdate(){doubleerror=target-pos;doubleout=pid.update(error);driver.setPWM(out);}private:PID pid;MotorDriver driver;};

好处

算法可以独立测试:

PID pid;doubleresult=pid.update(0.5);

不需要设备。


四、阶段4:加入通信系统

新需求:

远程控制设备

需要:

TCP 串口

工程师开始写:

TcpServer SerialPort

但很快发现问题:

❌ 通信代码混乱
❌ 不同协议混在一起


五、第三次重构(Protocol + Media)

通信系统通常拆成两层:

Protocol Media

Media(通信通道)

负责传输:

TCP Serial CAN

示例:

classTcpServer{public:QByteArrayreceive();};

Protocol(协议解析)

解析数据:

SET_SPEED 1000 START STOP
classDeviceProtocol{public:Commandparse(QByteArray data);};

Controller执行命令

Command cmd=protocol.parse(data);if(cmd.type==SET_SPEED){motorController.setSpeed(cmd.value);}

调用流程

TCP ↓ Media ↓ Protocol ↓ Controller

六、阶段5:系统越来越复杂

设备增加:

电机 相机 温度 网络 日志 配置

模块越来越多:

MotorController CameraController SensorController

工程师开始问:

这些模块谁来管理? 谁负责初始化? 谁负责启动?

七、第四次重构(Manager)

于是出现:

Manager

Manager负责:

初始化 生命周期 资源管理

SystemManager

classSystemManager{public:voidinit(){motorController.init();cameraController.init();networkService.init();}};

程序启动

main ↓ SystemManager ↓ 初始化所有模块

八、阶段6:UI越来越复杂

UI需要做很多事情:

控制设备 显示数据 远程操作

如果UI直接调用Controller:

UI → Controller

UI会变复杂。


九、第五次重构(Service)

于是加入:

Service

Service给UI提供接口。


DeviceService

classDeviceService{public:voidstartMotor(){motorController.start();}doublegetTemperature(){returnsensorController.readTemp();}};

UI

voidMainWindow::onStartClicked(){deviceService.startMotor();}

UI不用知道:

MotorController MotorDriver

十、最终成熟架构

经过多次重构后,系统变成:

project ├── ui ├── service ├── manager ├── controller ├── algorithm ├── protocol ├── media ├── driver ├── thread └── tools

系统层级:

UI ↓ Service ↓ Manager ↓ Controller ↓ Algorithm ↓ Driver ↓ Hardware

十一、完整实例流程

用户点击:

开始检测

流程:

UI ↓ DeviceService ↓ InspectionController ↓ MotorController ↓ PID ↓ MotorDriver ↓ Motor

拍照:

UI ↓ DeviceService ↓ CameraController ↓ CameraDriver ↓ Camera

远程命令:

TCP ↓ Media ↓ Protocol ↓ Controller

十二、工程师的真实思维过程

真实开发过程:

第一版 UI直接控制设备

第二版 加入Controller

第三版 加入Algorithm

第四版 加入Protocol

第五版 加入Manager

第六版 加入Service

最终形成完整架构。


十三、一句话总结

大型软件架构其实是不断重构演化出来的

简单代码 ↓ 模块化 ↓ 分层 ↓ 服务化 ↓ 完整架构

http://www.jsqmd.com/news/482767/

相关文章:

  • 虚幻引擎开发者必看:UE5.03中CullDistanceSizePair结构体的替代方案
  • 穷学生福音:2026年性价比最高的降AI工具推荐
  • 从理论到实践:用C语言手把手实现PCM逐次比较型编码器
  • Docker 27镜像签名验证全链路拆解:从cosign配置到Notary v2迁移,手把手落地企业级可信分发
  • 图像复原技术实战:逆滤波与维纳滤波的MATLAB对比与优化
  • 高效窗口置顶工具:让你的工作窗口始终保持焦点的效率解决方案
  • QMCDecode:专业QQ音乐加密格式破解工具,让音频文件重获自由
  • 结合知识图谱:CLIP-GmP-ViT-L-14增强实体图像的语义检索
  • 【技术实践】霍尔效应:从原理到磁场分布的精准测量
  • 立创开源Blheli_s 8S60A电调:基于BLHeli_s固件的大功率无感方波驱动方案解析
  • 利用foobar2000实现音频元数据批量管理:从封面到artist/album的高效操作
  • 3步实现Zepp Life步数自动化同步:从配置到运维的完整指南
  • 系统深度清理:Sunshine游戏串流服务器彻底移除与环境优化指南
  • GLM-OCR开发环境搭建保姆级教程:从Anaconda安装到模型测试
  • RetinaFace保姆级入门:零基础掌握人脸检测框绘制与五点关键点可视化
  • 五万下载!WinClaw 狂飙,每日免费 Token 直接拉到 1000 万
  • Qwen3-ASR-1.7B语音识别入门:qwen-asr SDK本地加载与推理流程详解
  • 虚拟试衣间背后的视觉技术:DAMOYOLO-S实现精准人体关键点与服装检测
  • Llama-3.2V-11B-cot 运维指南:模型服务监控、日志与性能调优
  • Zotero 6.0+双端同步避坑指南:如何解决iPad上‘Linked files not supported’报错
  • Lumafly:破解空洞骑士模组管理难题的智能解决方案
  • DamoFD-0.5G在智能门禁系统中的应用实践
  • 4个维度重构wechat-need-web:让微信网页版无缝访问不再受限
  • MCP状态同步成本黑洞诊断手册:从协议栈到应用层的7层成本归因分析(含Wireshark+Prometheus联合追踪脚本)
  • 集群扩容后任务堆积?Docker 27调度瓶颈定位四步法:从cgroup v2指标到placement constraint日志染色
  • 保姆级教程:IndexTTS2 V23快速上手,打造有情感的AI语音
  • 变频器谐波干扰综合治理方案:从原理到实践
  • Qwen3-TTS-1.7B-Base详细步骤:从零配置CUDA环境到语音合成
  • Z-Image-Turbo-rinaiqiao-huiyewunv 从零部署:Ubuntu服务器环境准备与模型服务启动全记录
  • 3个步骤搞定多平台直播RTMP配置:从基础到进阶的完整指南