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

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

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

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

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

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

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

需求:

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

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

复制代码
project
 ├── main.cpp
 ├── MainWindow.cpp
 ├── Motor.cpp
 ├── Camera.cpp
 └── Sensor.cpp

代码示例

UI直接调用设备:

cpp 复制代码
class MainWindow
{
public:
    void startMotor()
    {
        motor.start();
    }

    void takePhoto()
    {
        camera.capture();
    }

    void showTemp()
    {
        double t = sensor.read();
    }

private:
    Motor motor;
    Camera camera;
    Sensor sensor;
};

设备类:

cpp 复制代码
class Motor
{
public:
    void start()
    {
        writeRegister(0x01,1);
    }
};

优点

开发快

代码简单


问题很快出现

随着需求增加:

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

代码开始变成:

cpp 复制代码
MainWindow
{
    Motor motor;
    Camera camera;
    Sensor sensor;
    TcpServer tcp;
}

UI里全是逻辑:

cpp 复制代码
void MainWindow::onStartClicked()
{
    motor.start();
    tcp.send("motor started");
}

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

工程师发现问题:

❌ UI代码太复杂

❌ 逻辑到处都是

❌ UI直接控制硬件

于是进行第一次重构

引入:

复制代码
Controller

新结构

复制代码
project
 ├── ui
 │   └── MainWindow
 │
 ├── controller
 │   ├── MotorController
 │   ├── CameraController
 │   └── SensorController
 │
 └── driver
     ├── MotorDriver
     ├── CameraDriver
     └── SensorDriver

UI变简单

cpp 复制代码
void MainWindow::onStartClicked()
{
    motorController.start();
}

Controller

cpp 复制代码
class MotorController
{
public:
    void start()
    {
        driver.enable();
    }

private:
    MotorDriver driver;
};

Driver

cpp 复制代码
class MotorDriver
{
public:
    void enable()
    {
        writeRegister(0x01,1);
    }
};

调用流程

复制代码
UI
 ↓
Controller
 ↓
Driver
 ↓
Hardware

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

项目继续发展:

新需求:

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

Controller开始变复杂:

cpp 复制代码
class MotorController
{
public:
    void update()
    {
        double error = target-pos;
        double output = pid.update(error);
        driver.setPWM(output);
    }
};

工程师发现:

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

于是进行第二次重构。


引入 Algorithm 层

新结构:

复制代码
project
 ├── controller
 ├── algorithm
 └── driver

Algorithm

cpp 复制代码
class PID
{
public:
    double update(double error)
    {
        return kp*error + ki*sum + kd*diff;
    }
};

Controller

cpp 复制代码
class MotorController
{
public:
    void update()
    {
        double error = target-pos;
        double out = pid.update(error);
        driver.setPWM(out);
    }

private:
    PID pid;
    MotorDriver driver;
};

好处

算法可以独立测试:

cpp 复制代码
PID pid;

double result = pid.update(0.5);

不需要设备。


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

新需求:

复制代码
远程控制设备

需要:

复制代码
TCP
串口

工程师开始写:

cpp 复制代码
TcpServer
SerialPort

但很快发现问题:

❌ 通信代码混乱

❌ 不同协议混在一起


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

通信系统通常拆成两层:

复制代码
Protocol
Media

Media(通信通道)

负责传输:

复制代码
TCP
Serial
CAN

示例:

cpp 复制代码
class TcpServer
{
public:
    QByteArray receive();
};

Protocol(协议解析)

解析数据:

复制代码
SET_SPEED 1000
START
STOP
cpp 复制代码
class DeviceProtocol
{
public:
    Command parse(QByteArray data);
};

Controller执行命令

cpp 复制代码
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

cpp 复制代码
class SystemManager
{
public:
    void init()
    {
        motorController.init();
        cameraController.init();
        networkService.init();
    }
};

程序启动

复制代码
main
 ↓
SystemManager
 ↓
初始化所有模块

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

UI需要做很多事情:

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

如果UI直接调用Controller:

复制代码
UI → Controller

UI会变复杂。


九、第五次重构(Service)

于是加入:

复制代码
Service

Service给UI提供接口。


DeviceService

cpp 复制代码
class DeviceService
{
public:
    void startMotor()
    {
        motorController.start();
    }

    double getTemperature()
    {
        return sensorController.readTemp();
    }
};

UI

cpp 复制代码
void MainWindow::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

最终形成完整架构。


十三、一句话总结

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

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

相关推荐
papaofdoudou2 小时前
QEMU和KVMTOOL在GPA(IOVA)和HVA映射方面的异同
linux·运维·服务器
Xzq2105092 小时前
部分重要协议或技术(DNS,ICMP,NAT,代理服务器)
运维·服务器·网络
艾莉丝努力练剑3 小时前
文件描述符fd:跨进程共享机制
java·linux·运维·服务器·开发语言·c++
原来是猿3 小时前
Linux-【文件系统下】
linux·运维·数据库
勇闯逆流河3 小时前
【Linux】linux进程概念(冯洛伊曼体系、操作系统、进程详解)
linux·运维·服务器
爱丽_4 小时前
Linux 安装 MySQL 与远程连接排障(yum 方案)
linux·运维·mysql
IT WorryFree4 小时前
OpenClaw的运维命令
运维
落日漫游4 小时前
Zabbix监控实战:Linux主机全流程配置
运维·开发语言·自动化
枕布响丸辣4 小时前
Web 技术基础与 Nginx 网站环境部署超详细教程
运维·前端·nginx