【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)交互,接收/发送指令:

  1. 通信协议解析

    • Modbus :用于 PLC 通信 ,控制伺服驱动器的 启停、模式切换
    • CANopen /EtherCAT :工业总线协议,用于 多轴协同控制
    • UART/RS485 :用于 PC 调试、诊断、参数读取
  2. HMI 交互

    • LCD 显示当前电机状态、报警信息、实时参数。
    • 按键调整运行模式、输入目标转速或位置。
  3. 参数管理

    • 上位机发送设定指令 ,修改 PI 参数、惯量补偿、编码器偏移
    • 将参数存储到 EEPROM/Flash,掉电不丢失。
  4. 故障诊断

    • 实时检测电机状态 ,如果过流/过压等,发送报警到上位机
    • 例如,PLC 通过 CANopen 读取驱动器状态字,判断是否正常运行。
  5. 日志记录

    • 存储历史报警信息 ,便于 PC 端诊断分析
    • 上位机可以通过 UART/CANopen 读取报警日志

4. 交互数据流

plaintext 复制代码
  上位机(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 通信流程

📌 主从设备数据流

plaintext 复制代码
    PLC(Modbus Master)
        │
        ▼
  请求(READ/WRITE)
        │
        ▼
  伺服驱动器(Modbus Slave)
        │
        ▼
  响应(DATA/ERROR)

📌 通信步骤

Step 1PLC 发送 Modbus 请求 (READ/WRITE)
Step 2伺服驱动器解析请求 (检查从机地址 + 功能码 + CRC)
Step 3伺服驱动器执行操作(读/写寄存器)
Step 4伺服驱动器返回响应 (成功数据或错误码)
Step 5PLC 解析响应数据,控制伺服驱动器运行


3. Modbus 数据帧格式

Modbus 数据帧由 地址 + 功能码 + 数据 + 校验 组成。

📌 RTU 模式数据帧

字段 字节 描述
从机地址(Slave ID) 1 目标设备地址(1-247)
功能码(Function Code) 1 读/写操作代码
数据区(Data) N 具体寄存器地址 & 数据
CRC 校验(Error Check) 2 计算数据完整性

示例(读取 03 寄存器数据)

plaintext 复制代码
[01] [03] [00] [0A] [00] [01] [C5] [CD]
  • 01 → 设备地址(从机 1)
  • 03 → 读取保持寄存器
  • 00 0A → 寄存器地址 0x000A
  • 00 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 寄存器)

plaintext 复制代码
[01] [03] [00] [01] [00] [01] [D5] [CA]

解析

  • 01 → 从机地址
  • 03 → 读取保持寄存器
  • 00 01 → 目标寄存器地址 0x0001
  • 00 01 → 读取 1 个寄存器
  • D5 CA → CRC 校验

伺服返回(状态 = 运行)

plaintext 复制代码
[01] [03] [02] [00] [01] [79] [84]
  • 02 → 返回 2 字节数据
  • 00 01 → 运行状态 = 1
  • 79 84 → CRC 校验

📌 设定目标转速

PLC 设置 1 号伺服目标转速 1500 RPM

plaintext 复制代码
[01] [06] [00] [03] [05] [DC] [88] [35]

解析

  • 01 → 设备地址
  • 06 → 写单个寄存器
  • 00 03 → 目标转速寄存器地址 0x0003
  • 05 DC → 1500(十进制)
  • 88 35 → CRC 校验

伺服返回

plaintext 复制代码
[01] [06] [00] [03] [05] [DC] [88] [35]

(确认写入成功)


📌 伺服驱动器使能

PLC 发送指令,使能 1 号伺服驱动器

plaintext 复制代码
[01] [06] [00] [02] [00] [01] [18] [0A]

解析

  • 00 02 → 伺服使能寄存器
  • 00 01 → 使能

伺服返回

plaintext 复制代码
[01] [06] [00] [02] [00] [01] [18] [0A]

7. Modbus 伺服驱动器通信架构

plaintext 复制代码
+------------------------+
|  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 框架

plaintext 复制代码
+-------------------------------------+
|      伺服驱动器(Modbus 从机)       |
+-------------------------------------+
| UART 接收 Modbus 请求               | ⇄  PLC 发送读取/写入指令
| 解析数据帧(地址+功能码+数据+CRC)  |
| 处理功能码(0x03/0x06/0x10)       |
| 访问寄存器数据(位置、速度等)       |
| 计算 CRC 并返回 Modbus 响应          |
+-------------------------------------+

📌 2. Modbus 伺服驱动器寄存器

c 复制代码
#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 进行校验:

c 复制代码
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 请求

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

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

c 复制代码
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 数据

c 复制代码
#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 总体流程

  1. UART 接收 Modbus 数据
  2. 解析 Modbus 请求(地址 + 功能码 + CRC 校验)
  3. 处理功能码(读/写寄存器)
  4. 返回 Modbus 响应

✅ 小论

🚀 完整的 Modbus RTU 代码,支持:

  • 读取寄存器(0x03)
  • 写入寄存器(0x06)
  • CRC 校验
  • UART 串口收发
相关推荐
水滴石轩26 分钟前
HarmonyOS NEXT ArkTS与H5的交互详解
架构
TechStack 创行者1 小时前
基于 Docker 和 Flask 构建高并发微服务架构
docker·微服务·容器·架构·flask
Aska_Lv4 小时前
Spring---循环依赖探讨
后端·架构
啾啾Fun5 小时前
[Java微服务架构]1_架构选择
架构·微服务架构选择
Goboy6 小时前
从零开始的NLP处理实践指南
后端·程序员·架构
dapeng-大鹏6 小时前
Gone v2 Tracer 组件-给微服务提供统一的traceID
微服务·云原生·架构·golang·traceid·gone
宋发元14 小时前
如何设计微服务及其设计原则?
微服务·云原生·架构
Moshow郑锴15 小时前
Kubernetes的组成和架构
容器·架构·kubernetes
交响梦17 小时前
医院信息系统平台总体架构原则
大数据·数据库·人工智能·架构·健康医疗