基于增量PID的电机速度控制仿真


带详细注释的代码

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>

/*-------- 模拟参数配置 --------*/
#define SIM_INERTIA 0.2f    // 电机惯性系数(0-1,值越大响应越慢)
#define SIM_LATENCY 3       // 转速测量延迟周期数(模拟传感器延迟)

/*-------- PID控制器结构体 --------*/
typedef struct {
    float Kp;           // 比例系数
    float Ki;           // 积分系数
    float Kd;           // 微分系数
    float e1;           // 前一次误差
    float e2;           // 前两次误差
    int32_t target;     // 目标转速(RPM)
    int32_t output;     // 控制输出(PWM占空比,0-10000对应0%-100%)
} PID_Controller;

/*-------- 电机模拟器结构体 --------*/
typedef struct {
    float real_speed;       // 电机真实转速(带惯性)
    int32_t display_speed;  // 显示给控制器的转速(带测量延迟)
    int32_t speed_buffer[SIM_LATENCY]; // 延迟缓冲区
} Motor_Simulator;

/*-------- PID初始化函数 --------
 * 参数:pid控制器指针,PID系数
 * 功能:初始化PID参数和状态*/
void PID_Init(PID_Controller *pid, float Kp, float Ki, float Kd) {
    pid->Kp = Kp;
    pid->Ki = Ki;
    pid->Kd = Kd;
    pid->e1 = pid->e2 = 0;
    pid->target = 0;
    pid->output = 0;  // 初始输出从0开始
}

/*-------- PID更新函数 --------
 * 参数:pid控制器指针,当前测量转速
 * 功能:计算增量式PID输出并更新状态*/
void PID_Update(PID_Controller *pid, int32_t current) {
    // 计算当前误差
    float e0 = pid->target - current;
    
    // 增量式PID公式:
    // Δu = Kp*(e0-e1) + Ki*e0 + Kd*(e0-2e1+e2)
    float delta = pid->Kp * (e0 - pid->e1) 
                + pid->Ki * e0 
                + pid->Kd * (e0 - 2*pid->e1 + pid->e2);
    
    // 更新输出并限幅
    pid->output += (int32_t)delta;
    pid->output = (pid->output > 10000) ? 10000 : 
                 (pid->output < 0) ? 0 : pid->output;
    
    // 更新误差历史
    pid->e2 = pid->e1;
    pid->e1 = e0;
}

/*-------- 电机模拟器更新函数 --------
 * 参数:电机指针,当前PWM占空比
 * 功能:模拟电机动态响应和测量延迟*/
void Motor_Update(Motor_Simulator *motor, int32_t pwm) {
    /* 物理模型计算 */
    // 推力计算:PWM占空比转换为推力(300RPM/周期为最大推力)
    float thrust = pwm / 10000.0f * 300.0f;
    
    // 摩擦力计算:与当前速度成正比(0.1为摩擦系数)
    float friction = motor->real_speed * 0.1f;
    
    // 速度变化 = (推力 - 摩擦力) * 惯性系数
    motor->real_speed += (thrust - friction) * (1.0f - SIM_INERTIA);
    
    // 添加随机噪声(模拟测量误差)
    motor->real_speed += (rand() % 21 - 10); // ±10RPM噪声
    if(motor->real_speed < 0) motor->real_speed = 0;
    
    /* 测量延迟模拟 */
    // 更新环形缓冲区
    for(int i = SIM_LATENCY-1; i > 0; i--)
        motor->speed_buffer[i] = motor->speed_buffer[i-1];
    motor->speed_buffer[0] = (int32_t)motor->real_speed;
    
    // 显示延迟后的转速
    motor->display_speed = motor->speed_buffer[SIM_LATENCY-1];
}

int main() {
    PID_Controller pid;
    Motor_Simulator motor = {0};
    srand(time(NULL));  // 初始化随机数生成器

    // 初始化PID参数(可调参数)
    PID_Init(&pid, 2.8f, 0.15f, 0.5f);
    pid.target = 2000;  // 设置目标转速为2000RPM

    // 打印表格头部
    printf("时间(s)┃目标转速┃实际转速┃显示转速┃PWM输出┃误差\n");
    printf("═══════╋════════╋════════╋════════╋═══════╋═════\n");

    // 主控制循环(每周期模拟100ms)
    for(int t = 0; t < 300; t++) {
        // 1. 获取带延迟的测量转速
        int32_t measured = motor.display_speed;
        
        // 2. 更新PID控制器
        PID_Update(&pid, measured);
        
        // 3. 更新电机状态
        Motor_Update(&motor, pid.output);
        
        // 每秒打印一次状态
        if(t % 10 == 0) {
            printf("%6.1f ┃%7d ┃%7d ┃%7d ┃%5d%% ┃%4d\n",
                   t/10.0,                // 当前时间(秒)
                   pid.target,            // 目标转速
                   (int)motor.real_speed, // 真实转速
                   measured,              // 控制器接收的转速
                   pid.output/100,        // PWM百分比
                   pid.target - measured  // 当前误差
            );
        }
    }
    return 0;
}

基于增量PID的电机速度控制仿真

一、项目概述

本代码实现了一个完整的直流电机速度控制仿真系统,采用增量式PID算法,具有以下特点:

  • 纯软件仿真:无需硬件即可运行测试
  • 真实物理模拟:包含惯性、摩擦力和测量延迟
  • 可视化输出:实时显示控制状态
  • 参数可调:方便测试不同控制效果

二、核心原理

1. 增量式PID控制

与传统位置式PID不同,增量式PID计算的是控制量的增量

Δu = Kp*(e₀-e₁) + Ki*e₀ + Kd*(e₀-2e₁+e₂)

优势:

  • 避免积分饱和
  • 更易实现无扰切换
  • 对计算误差不敏感
2. 电机物理模型
速度变化 = (推力 - 摩擦力) × 惯性系数
  • 推力计算thrust = PWM% × 300 RPM/周期
  • 摩擦力friction = 0.1 × 当前速度
  • 平衡条件:当thrust = friction时达到稳态
3. 测量延迟模拟

使用环形缓冲区实现3个周期的测量延迟,更真实反映实际系统中的传感器响应。

三、关键代码解析

1. PID控制器结构
typedef struct {
    float Kp, Ki, Kd;  // PID系数
    float e1, e2;      // 历史误差
    int32_t target;    // 目标值
    int32_t output;    // 控制输出
} PID_Controller;
2. 电机模拟器
void Motor_Update(...) {
    // 物理模型计算
    float thrust = ...; // 与PWM成正比
    float friction = ...; // 与速度成正比
    // 延迟缓冲区处理
    ...
}

四、使用示例

输出示例(目标2000RPM)
时间(s)┃目标转速┃实际转速┃显示转速┃PWM输出┃误差
   0.0 ┃   2000 ┃      0 ┃      0 ┃   0% ┃2000
   1.0 ┃   2000 ┃    183 ┃      0 ┃  43% ┃2000
   2.0 ┃   2000 ┃    612 ┃    183 ┃  67% ┃1817
   3.0 ┃   2000 ┃   1235 ┃    612 ┃  78% ┃1388
   4.0 ┃   2000 ┃   1859 ┃   1235 ┃  68% ┃ 765
   5.0 ┃   2000 ┃   1982 ┃   1859 ┃  65% ┃ 141
   6.0 ┃   2000 ┃   2016 ┃   1982 ┃  66% ┃  18
参数调节建议
  • 超调过大:增大Kd或减小Kp
  • 收敛慢:增大Kp或Ki
  • 稳态误差:适当增大Ki

五、扩展方向

  1. 添加图形界面:使用Matplotlib实时显示曲线
  2. 实现自动整定:加入Ziegler-Nichols自整定算法
  3. 支持多种电机:修改物理模型参数
  4. 添加负载扰动:模拟突加负载场景

六、总结

本代码为学习PID控制算法提供了完整的仿真环境,通过调整参数可以直观观察控制效果差异。实际硬件应用中需注意:

  1. 测量周期的精确性
  2. 传感器噪声处理
  3. 执行器输出限制
  4. 系统安全保护机制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九层指针

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值