【Servo】一个简单的伺服驱动器嵌入式架构,联想
旋转伺服驱动器的嵌入式软件架构
旋转伺服驱动器的嵌入式软件主要负责 电机控制、数据处理、通信交互、状态监控 等功能。为了确保系统的 实时性、可靠性和模块化,通常将软件划分为以下功能模块:
1. 软件功能模块划分
🔹 核心控制模块
模块名称 | 功能描述 |
---|---|
FOC(磁场定向控制) | 采用 矢量控制算法 计算 电流分量 Id/Iq,优化电机性能。 |
PI 控制器 | 速度、电流、位置闭环控制,实现精确控制目标。 |
SVPWM(空间矢量脉宽调制) | 生成 PWM 信号,驱动 逆变器 控制电机。 |
速度/位置环 | 根据编码器反馈进行 速度、位置闭环控制,确保精度。 |
🔹 传感器 & 数据采集模块
模块名称 | 功能描述 |
---|---|
电流采样(ADC 采样) | 通过 ADC 采样电流 进行电流环控制(一般 3 通道)。 |
电压检测 | 监测 母线电压、三相电压,用于过压/欠压保护。 |
温度检测 | 监测 驱动器温度,防止过热损坏。 |
编码器/位置反馈 | 处理 增量编码器、旋转变压器、绝对值编码器 反馈数据。 |
🔹 运动控制模块
模块名称 | 功能描述 |
---|---|
插补算法 | 计算平滑轨迹,实现高精度运动。 |
加减速规划 | 梯形加速、S 形加速,防止速度突变。 |
目标位置计算 | 根据输入命令计算目标位置。 |
🔹 通信模块
模块名称 | 功能描述 |
---|---|
CANopen/Modbus/EtherCAT | 与 PLC、上位机 进行通信,接收/发送数据。 |
UART/RS485 | 用于调试或与外部设备通信(HMI、PC)。 |
SPI/I2C | 连接 外部传感器、存储器 进行数据交互。 |
🔹 保护与故障诊断模块
模块名称 | 功能描述 |
---|---|
过流保护 | 监测电流,超过阈值时关闭 PWM 以防损坏。 |
过温保护 | 过温时降额运行或停止驱动器。 |
欠压/过压保护 | 低于/高于母线电压阈值时停止驱动器。 |
编码器异常检测 | 检测 编码器丢失、脉冲丢失 等错误。 |
🔹 用户接口 & 参数管理
模块名称 | 功能描述 |
---|---|
参数存储(EEPROM/Flash) | 存储用户配置,如 电机参数、PID 参数。 |
键盘/显示(HMI) | 驱动显示屏和按键,实现 手动操作。 |
诊断和日志 | 记录故障信息,提供调试数据。 |
🔹 任务管理 & RTOS
模块名称 | 功能描述 |
---|---|
任务调度 | 通过 FreeRTOS / RT-Thread 调度各个任务,保证实时性。 |
中断管理 | 处理 PWM 触发、ADC 采样、通信中断 等事件。 |
低功耗管理 | 控制 MCU 进入低功耗模式,节省能耗。 |
2. 软件层级划分
🔹 驱动层(HAL - 硬件抽象层)
组件 | 说明 |
---|---|
GPIO | 控制 LED、继电器、输入/输出信号。 |
ADC/DAC | 采样 电流、电压、温度。 |
PWM | 生成 逆变器控制信号。 |
UART/SPI/I2C | 通信接口,连接外部设备。 |
🔹 中间层(MCU 控制层)
组件 | 说明 |
---|---|
FOC 算法 | 计算 Id/Iq 电流,控制电机。 |
闭环控制 | PID 位置、速度、电流控制。 |
编码器解析 | 处理 增量编码器、旋转变压器 数据。 |
🔹 应用层
组件 | 说明 |
---|---|
上位机通信 | 通过 CANopen/Modbus 控制驱动器。 |
人机交互(HMI) | 处理 按键输入、LCD 显示。 |
故障处理 | 过流、过压、欠压等保护机制。 |
3. 任务优先级 & 调度
🔹 高优先级任务(实时任务)
任务 | 描述 | 运行频率 |
---|---|---|
FOC 算法 | 计算 PWM 输出,控制电机 | 10-20kHz |
电流环控制 | 采样电流,更新 PI 控制器 | 10-20kHz |
PWM 触发 | 控制 MOSFET 开关 | 10-20kHz |
🔹 中等优先级任务
任务 | 描述 | 运行频率 |
---|---|---|
速度环控制 | 计算速度 PI 控制 | 1-5kHz |
位置环控制 | 计算目标位置 | 500Hz-1kHz |
通讯处理 | 解析 CANopen/Modbus 数据 | 1kHz |
🔹 低优先级任务
任务 | 描述 | 运行频率 |
---|---|---|
参数存储 | 保存参数到 EEPROM/Flash | 1Hz-10Hz |
诊断与日志 | 记录报警信息 | 10Hz |
温度监测 | 过热保护 | 1Hz |
4. 小结
-
旋转伺服驱动器的嵌入式软件划分为:
- 核心控制(FOC, PWM, PI)
- 传感器处理(电流采样, 编码器反馈)
- 运动控制(速度环, 位置环, 插补算法)
- 通信(CANopen, Modbus, UART)
- 保护机制(过流, 过温, 过压)
- 用户交互(HMI, 参数存储, 诊断日志)
- 实时任务管理(RTOS调度, 中断处理)
-
软件架构采用分层设计:
- 驱动层(HAL):操作硬件外设
- 中间层(控制算法):核心计算逻辑
- 应用层:用户交互 & 故障处理
旋转伺服驱动器嵌入式软件层级划分
旋转伺服驱动器的嵌入式软件通常采用 分层架构 设计,以提高 可维护性、可扩展性和模块化开发能力。
1. 软件分层架构
🔹 典型的 4 层架构
层级 | 主要功能 | 具体模块 |
---|---|---|
应用层(Application Layer) | 与上位机/用户交互,处理用户命令和系统状态管理 | 上位机协议解析、HMI(人机交互)、参数管理、故障诊断、日志记录 |
控制层(Control Layer) | 伺服控制核心算法,执行位置/速度/电流控制 | FOC 算法、位置环、速度环、电流环、SVPWM、插补算法、滤波器 |
驱动层(Driver Layer) | 直接驱动硬件外设,负责数据采集与控制信号输出 | PWM 生成、电流/电压/位置采样、ADC 采样、编码器解码、GPIO 读写 |
硬件抽象层(HAL - Hardware Abstraction Layer) | 屏蔽底层硬件差异,提供统一接口 | MCU 低级驱动、寄存器操作、RTOS 底层支持、Flash 读写 |
2. 应用层模块(Application Layer)
应用层的主要职责是:
✅ 与上位机(PLC、PC)进行通信
✅ 提供用户交互(HMI/LCD/按键)
✅ 存储和管理参数
✅ 诊断和日志记录
🔹 具体模块
模块 | 功能描述 |
---|---|
通信协议(Protocol Stack) | 解析 CANopen、Modbus、EtherCAT、RS485、UART 等通信协议,实现远程控制 |
HMI(人机交互) | 处理 LCD 显示、按键输入,支持用户手动配置参数 |
参数管理(Parameter Manager) | 读取/存储 伺服电机参数、PID 参数、编码器设定,存储到 EEPROM/Flash |
故障诊断(Fault Diagnosis) | 监测 过流、过压、欠压、过温、编码器故障 等,提供故障代码 |
日志记录(Logging) | 记录故障日志、运行日志,便于调试和维护 |
远程控制 | 处理 上位机发送的运动控制命令,如 启动、停止、复位、模式切换 |
3. 偏向上位机交互的模块
以下模块主要负责 与上位机(PLC、PC)交互,接收/发送指令:
-
通信协议解析
- Modbus:用于 PLC 通信,控制伺服驱动器的 启停、模式切换。
- CANopen/EtherCAT:工业总线协议,用于 多轴协同控制。
- UART/RS485:用于 PC 调试、诊断、参数读取。
-
HMI 交互
- LCD 显示当前电机状态、报警信息、实时参数。
- 按键调整运行模式、输入目标转速或位置。
-
参数管理
- 上位机发送设定指令,修改 PI 参数、惯量补偿、编码器偏移。
- 将参数存储到 EEPROM/Flash,掉电不丢失。
-
故障诊断
- 实时检测电机状态,如果过流/过压等,发送报警到上位机。
- 例如,PLC 通过 CANopen 读取驱动器状态字,判断是否正常运行。
-
日志记录
- 存储历史报警信息,便于 PC 端诊断分析。
- 上位机可以通过 UART/CANopen 读取报警日志。
4. 交互数据流
上位机(PLC/PC)
▲ ▲
│ │
CANopen / Modbus / EtherCAT / UART
│ │
▼ ▼
+----------------------------+
| 应用层(Application Layer) |
|----------------------------|
| 通信协议解析 | ⇄ 解析上位机命令
| HMI 交互 | ⇄ 显示电机状态
| 参数管理 | ⇄ 读取/存储参数
| 故障诊断 | ⇄ 发送报警信息
| 日志记录 | ⇄ 读取历史记录
+----------------------------+
│
▼
+----------------------------+
| 控制层(Control Layer) | ⇄ 计算运动控制
|----------------------------|
| 位置环 / 速度环 / 电流环 |
| FOC 算法 |
| 插补 & 轨迹规划 |
+----------------------------+
│
▼
+----------------------------+
| 驱动层(Driver Layer) | ⇄ 直接操作硬件
|----------------------------|
| PWM 生成 |
| ADC 采样 |
| 编码器解码 |
+----------------------------+
5. 小结
1️⃣ 软件总共分为 4 层
✅ 应用层(Application)—— 与上位机交互,管理用户参数和报警日志。
✅ 控制层(Control)—— 计算 FOC 算法、位置/速度控制,负责电机运行。
✅ 驱动层(Driver)—— 直接与硬件交互,包括 PWM、ADC、编码器。
✅ 硬件抽象层(HAL)—— 屏蔽底层硬件,提供统一接口。
2️⃣ 应用层(Application)包含哪些模块
- 通信协议解析(CANopen、Modbus、EtherCAT) → 远程控制
- HMI 交互(LCD、按键、菜单系统) → 本地调试
- 参数管理(EEPROM/Flash 存储) → 读取/修改伺服参数
- 故障诊断(报警、过流、过压等) → 确保安全运行
- 日志记录(存储历史报警) → 提供维护数据
3️⃣ 偏向上位机交互的模块
✅ 通信协议解析(CANopen, Modbus, EtherCAT, UART)
✅ HMI 交互(LCD、按键)
✅ 参数管理(EEPROM 读写)
✅ 故障诊断(过流、过温、编码器异常检测)
✅ 日志记录(报警历史查询)
**词汇联想 ---- 更详细的某个模块,比如 “Modbus 通信流程” 或 “FOC 算法计算过程” **
Modbus 通信流程解析(适用于伺服驱动器)
Modbus 是一种 主从式(Master-Slave) 通信协议,常用于 PLC(主机)控制伺服驱动器(从机)。它支持 串行(RTU/ASCII) 和 以太网(TCP) 传输。
1. Modbus 主要特点
✅ 主从模式:上位机(PLC/PC)主动发送指令,伺服驱动器被动响应。
✅ 地址寻址:支持 247 个从机(RTU 模式),通过 从机地址(Slave ID) 区分设备。
✅ 寄存器映射:采用 功能码 + 寄存器地址 读写 伺服驱动器参数。
✅ 错误检测:RTU 模式使用 CRC 校验,保证数据完整性。
2. Modbus 通信流程
📌 主从设备数据流
PLC(Modbus Master)
│
▼
请求(READ/WRITE)
│
▼
伺服驱动器(Modbus Slave)
│
▼
响应(DATA/ERROR)
📌 通信步骤
Step 1:PLC 发送 Modbus 请求(READ/WRITE)
Step 2:伺服驱动器解析请求(检查从机地址 + 功能码 + CRC)
Step 3:伺服驱动器执行操作(读/写寄存器)
Step 4:伺服驱动器返回响应(成功数据或错误码)
Step 5:PLC 解析响应数据,控制伺服驱动器运行
3. Modbus 数据帧格式
Modbus 数据帧由 地址 + 功能码 + 数据 + 校验 组成。
📌 RTU 模式数据帧
字段 | 字节 | 描述 |
---|---|---|
从机地址(Slave ID) | 1 | 目标设备地址(1-247) |
功能码(Function Code) | 1 | 读/写操作代码 |
数据区(Data) | N | 具体寄存器地址 & 数据 |
CRC 校验(Error Check) | 2 | 计算数据完整性 |
示例(读取 03 寄存器数据)
[01] [03] [00] [0A] [00] [01] [C5] [CD]
01
→ 设备地址(从机 1)03
→ 读取保持寄存器00 0A
→ 寄存器地址 0x000A00 01
→ 读取 1 个寄存器C5 CD
→ CRC 校验码(低字节在前)
4. Modbus 主要功能码
功能码(Hex) | 操作 | 描述 |
---|---|---|
0x03 | 读保持寄存器(Read Holding Registers) | 读取 伺服参数(位置、速度、扭矩等) |
0x06 | 写单个寄存器(Write Single Register) | 设置 目标转速、目标位置 |
0x10 | 写多个寄存器(Write Multiple Registers) | 批量写入多个参数 |
5. 伺服驱动器 Modbus 寄存器映射
伺服驱动器通常通过 Modbus 03/06/10 功能码 访问内部寄存器,例如:
寄存器地址 | 功能 | 数据类型 | 说明 |
---|---|---|---|
0x0001 | 运行状态 | 16-bit | 0 = 停止 ,1 = 运行 |
0x0002 | 伺服使能 | 16-bit | 0 = 禁用 ,1 = 使能 |
0x0003 | 目标转速 | 16-bit | RPM |
0x0004 | 目标位置 | 32-bit | 编码器单位 |
0x0005 | 实际转速 | 16-bit | RPM |
0x0006 | 实际位置 | 32-bit | 反馈位置 |
6. Modbus 典型指令示例
📌 读取伺服状态
PLC 读取 1 号伺服驱动器的运行状态(0x0001
寄存器)
[01] [03] [00] [01] [00] [01] [D5] [CA]
解析
01
→ 从机地址03
→ 读取保持寄存器00 01
→ 目标寄存器地址0x0001
00 01
→ 读取 1 个寄存器D5 CA
→ CRC 校验
伺服返回(状态 = 运行)
[01] [03] [02] [00] [01] [79] [84]
02
→ 返回 2 字节数据00 01
→ 运行状态 = 179 84
→ CRC 校验
📌 设定目标转速
PLC 设置 1 号伺服目标转速 1500 RPM
[01] [06] [00] [03] [05] [DC] [88] [35]
解析
01
→ 设备地址06
→ 写单个寄存器00 03
→ 目标转速寄存器地址0x0003
05 DC
→ 1500(十进制)88 35
→ CRC 校验
伺服返回
[01] [06] [00] [03] [05] [DC] [88] [35]
(确认写入成功)
📌 伺服驱动器使能
PLC 发送指令,使能 1 号伺服驱动器
[01] [06] [00] [02] [00] [01] [18] [0A]
解析
00 02
→ 伺服使能寄存器00 01
→ 使能
伺服返回
[01] [06] [00] [02] [00] [01] [18] [0A]
7. Modbus 伺服驱动器通信架构
+------------------------+
| PLC/上位机(Modbus 主机)|
+------------------------+
│
Modbus RTU/TCP
│
+------------------------+
| 伺服驱动器(Modbus 从机)|
| - 解析 Modbus 指令 |
| - 读/写伺服参数 |
| - 反馈运行状态 |
+------------------------+
8. 小结
✅ Modbus 采用主从模式,PLC/PC 控制伺服驱动器。
✅ 支持多种功能码(0x03
读参数,0x06
写单个参数,0x10
批量写入)。
✅ 通信流程:主机发送指令 -> 伺服解析 -> 读取/写入数据 -> 伺服响应。
✅ 适用于 CANopen、Modbus RTU/ASCII、Modbus TCP。
💡 ** 完整的 Modbus 代码示例(C 语言嵌入式实现) **
完整的 Modbus RTU 代码示例(C 语言嵌入式实现)
以下代码实现 Modbus RTU 从机(伺服驱动器) 的核心功能,包括:
✅ 接收 Modbus RTU 请求(读取寄存器、写入寄存器)
✅ 解析功能码(0x03 读取寄存器, 0x06 写单个寄存器, 0x10 写多个寄存器)
✅ 生成响应数据帧并通过 UART 发送
✅ 支持 CRC 校验
📌 1. 伺服驱动器 Modbus RTU 框架
+-------------------------------------+
| 伺服驱动器(Modbus 从机) |
+-------------------------------------+
| UART 接收 Modbus 请求 | ⇄ PLC 发送读取/写入指令
| 解析数据帧(地址+功能码+数据+CRC) |
| 处理功能码(0x03/0x06/0x10) |
| 访问寄存器数据(位置、速度等) |
| 计算 CRC 并返回 Modbus 响应 |
+-------------------------------------+
📌 2. Modbus 伺服驱动器寄存器
#define MODBUS_ADDRESS 1 // 从机地址
#define REG_COUNT 10 // 伺服寄存器数量
// 伺服寄存器表
uint16_t servo_registers[REG_COUNT] = {
0x0000, // 0x0000: 伺服运行状态(0=停止,1=运行)
0x0000, // 0x0001: 伺服使能状态(0=关闭,1=使能)
0x05DC, // 0x0002: 目标速度(默认 1500 RPM)
0x0000, // 0x0003: 目标位置
0x0000, // 0x0004: 实际速度反馈
0x0000, // 0x0005: 实际位置反馈
0x0000, // 0x0006: 电流反馈
0x0000, // 0x0007: 负载扭矩
0x0000, // 0x0008: 报警状态
0x0000 // 0x0009: 运行时间
};
📌 3. CRC16 校验计算
Modbus RTU 采用 CRC-16(多项式 0xA001
) 进行校验:
uint16_t Modbus_CRC16(uint8_t *data, uint16_t length) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < length; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc >>= 1;
crc ^= 0xA001;
} else {
crc >>= 1;
}
}
}
return crc;
}
📌 4. 解析 Modbus 请求
void Modbus_ParseRequest(uint8_t *request, uint16_t length) {
if (length < 8) return; // 最小 Modbus RTU 帧长
// 校验 CRC
uint16_t received_crc = (request[length - 1] << 8) | request[length - 2];
uint16_t calculated_crc = Modbus_CRC16(request, length - 2);
if (received_crc != calculated_crc) return; // CRC 校验失败
uint8_t slave_id = request[0]; // 从机地址
uint8_t function_code = request[1]; // 功能码
uint16_t reg_address = (request[2] << 8) | request[3]; // 寄存器地址
uint16_t reg_count = (request[4] << 8) | request[5]; // 读取数量
if (slave_id != MODBUS_ADDRESS) return; // 不是本设备,忽略
switch (function_code) {
case 0x03: // 读取寄存器
Modbus_HandleReadRequest(reg_address, reg_count);
break;
case 0x06: // 写单个寄存器
Modbus_HandleWriteRequest(reg_address, reg_count);
break;
default:
break;
}
}
📌 5. 读取保持寄存器(功能码 0x03)
void Modbus_HandleReadRequest(uint16_t reg_address, uint16_t reg_count) {
uint8_t response[256];
uint16_t length = 0;
response[length++] = MODBUS_ADDRESS; // 从机地址
response[length++] = 0x03; // 功能码
response[length++] = reg_count * 2; // 字节数
for (uint16_t i = 0; i < reg_count; i++) {
uint16_t value = servo_registers[reg_address + i];
response[length++] = value >> 8;
response[length++] = value & 0xFF;
}
uint16_t crc = Modbus_CRC16(response, length);
response[length++] = crc & 0xFF;
response[length++] = crc >> 8;
UART_Send(response, length); // 通过串口发送响应
}
📌 6. 写单个寄存器(功能码 0x06)
void Modbus_HandleWriteRequest(uint16_t reg_address, uint16_t value) {
if (reg_address < REG_COUNT) {
servo_registers[reg_address] = value; // 更新寄存器值
}
uint8_t response[8];
response[0] = MODBUS_ADDRESS;
response[1] = 0x06;
response[2] = reg_address >> 8;
response[3] = reg_address & 0xFF;
response[4] = value >> 8;
response[5] = value & 0xFF;
uint16_t crc = Modbus_CRC16(response, 6);
response[6] = crc & 0xFF;
response[7] = crc >> 8;
UART_Send(response, 8); // 通过串口返回确认
}
📌 7. 串口接收 Modbus 数据
#define UART_BUFFER_SIZE 256
uint8_t uart_buffer[UART_BUFFER_SIZE];
uint16_t uart_index = 0;
void UART_Receive_Handler(uint8_t byte) {
uart_buffer[uart_index++] = byte;
if (uart_index >= 8) { // Modbus 最小帧长
Modbus_ParseRequest(uart_buffer, uart_index);
uart_index = 0; // 清空缓冲区
}
}
📌 8. 伺服 Modbus RTU 总体流程
- UART 接收 Modbus 数据
- 解析 Modbus 请求(地址 + 功能码 + CRC 校验)
- 处理功能码(读/写寄存器)
- 返回 Modbus 响应
✅ 小论
🚀 完整的 Modbus RTU 代码,支持:
- 读取寄存器(0x03)
- 写入寄存器(0x06)
- CRC 校验
- UART 串口收发