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

【PID】STM32通过闭环PID控制电机系统

一、系统方案设计

1. 硬件架构

  • 主控芯片:STM32F4/F3系列(带高级定时器,如TIM1/TIM8)。

  • 电机类型:直流有刷电机(带正交编码器反馈)。

  • 驱动器:H桥驱动芯片(如L298N或DRV8833),支持PWM调速和方向控制。

  • 反馈装置:增量式正交编码器(分辨率:1000 PPR)。

  • 通信接口:可选UART/USB用于调试和参数调整。

2. 控制流程

  1. 编码器读取:通过定时器硬件捕获编码器脉冲,计算实时转速。

  2. PID计算:根据设定转速与反馈转速的偏差,计算PWM输出。

  3. PWM输出:调整占空比控制电机转速,形成闭环。


二、关键代码配置及函数详解

1. 定时器配置(PWM生成)

// TIM1初始化,通道1输出PWM
void MX_TIM1_Init(void) {
  TIM_HandleTypeDef htim1;
  TIM_OC_InitTypeDef sConfigOC = {0};

  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 0;        // 无分频
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 8399;        // PWM频率=84MHz/(8400)≈10kHz
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  HAL_TIM_PWM_Init(&htim1);

  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;             // 初始占空比0%
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);

  HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); // 启动PWM
}

2. 编码器接口配置(定时器编码器模式)

// TIM2初始化,编码器模式
void MX_TIM2_Init(void) {
  TIM_Encoder_InitTypeDef sEncoderConfig = {0};
  TIM_HandleTypeDef htim2 = {0};

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 0;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 0xFFFF;      // 16位计数器
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

  // 配置编码器模式(正交解码)
  sEncoderConfig.EncoderMode = TIM_ENCODERMODE_TI12;
  sEncoderConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
  sEncoderConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  sEncoderConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  sEncoderConfig.IC1Filter = 0;
  sEncoderConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  sEncoderConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  sEncoderConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  sEncoderConfig.IC2Filter = 0;
  
  HAL_TIM_Encoder_Init(&htim2, &sEncoderConfig);
  HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL); // 启动编码器
}

3. 定时器中断配置(PID周期计算)

// TIM3初始化,10ms中断触发PID计算
void MX_TIM3_Init(void) {
  TIM_HandleTypeDef htim3;

  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 8400 - 1;     // 84MHz/8400=10kHz
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 100 - 1;         // 10kHz/100=100Hz(10ms)
  HAL_TIM_Base_Init(&htim3);
  HAL_TIM_Base_Start_IT(&htim3);       // 启动中断
}

4. PID算法实现

typedef struct {
  float Kp, Ki, Kd;
  float integral, prev_error;
} PIDController;

float PID_Compute(PIDController *pid, float setpoint, float measurement) {
  float error = setpoint - measurement;
  pid->integral += error * 0.01f;       // 积分项(10ms周期)
  float derivative = (error - pid->prev_error) / 0.01f; // 微分项
  float output = pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative;
  pid->prev_error = error;
  
  // 输出限幅(0~100%占空比)
  if (output > 8399) output = 8399;
  else if (output < 0) output = 0;
  return output;
}

5. 中断服务函数(关键逻辑)

// 定时器中断回调函数(10ms执行一次)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
  if (htim->Instance == TIM3) {
    static int32_t prev_count = 0;
    int32_t curr_count = TIM2->CNT;     // 读取编码器计数值
    int32_t delta = curr_count - prev_count;
    prev_count = curr_count;

    // 计算转速(假设编码器1000PPR,10ms周期)
    float speed_rpm = (delta * 6000.0f) / (1000 * 4); // 4倍频处理
    
    // PID计算并更新PWM
    float output = PID_Compute(&pid, target_speed, speed_rpm);
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, (uint32_t)output);
  }
}

三、关键配置注意事项

  1. 编码器接口

    • 使用定时器的编码器模式(如TIM2/TIM3),自动处理A/B相信号的正交计数。

    • 注意编码器倍频(4倍频常见),需在转速计算时修正。

  2. PWM频率选择

    • 电机驱动器支持的频率范围(通常1kHz-20kHz),避免高频噪声或驱动损耗。

  3. 中断优先级

    • PID计算中断(TIM3)需高于编码器计数中断(TIM2),确保实时性。

  4. 抗积分饱和

    • 在PID结构体中加入输出限幅,或使用积分分离算法。

  5. 方向控制

    • 若需双向控制,可通过GPIO设置电机方向,或配置互补PWM通道。


四、调试步骤

  1. 开环测试:先验证PWM输出和电机转向。

  2. 编码器读数:手动旋转电机,检查TIM2计数值变化。

  3. PID参数整定

    • 先设Ki=0, Kd=0,逐步增大Kp至系统震荡,然后减小到80%。

    • 加入Ki消除稳态误差,最后加入Kd抑制超调。

通过此方案,可实现高精度的电机闭环控制


http://www.kler.cn/a/568305.html

相关文章:

  • k8s拉取harbor镜像部署
  • golang介绍,特点,项目结构,基本变量类型与声明介绍(数组,切片,映射),控制流语句介绍(条件,循环,switch case)
  • 海洋cmsv9报错注入,order by 和limit注入
  • NFC拉起微信小程序申请URL scheme 汇总
  • JavaScript 简单类型与复杂类型-简单类型传参
  • Spring Boot拦截器(Interceptor)与过滤器(Filter)详细教程
  • EtherCAT总线学习笔记
  • 【03】STM32F407 HAL 库框架设计学习
  • openEuler环境下GlusterFS分布式存储集群部署指南
  • 前缀和 C++
  • 【pytest框架源码分析三】pluggy源码分析之hook注册调用流程
  • WordPress多语言插件GTranslate
  • (17)CT137A- UART串口发送实验
  • 【江科协-STM32】5. 输出比较
  • 当我删除word文件时无法删除,提示:操作无法完成,因为已在Microsoft Word中打开
  • Linux下的网络通信编程
  • 2.8作业
  • 自然语言处理:稠密向量表示
  • 基于PHP和MySQL的用户登录注册系统实现
  • NAT 技术:网络中的 “地址魔术师”