采用旋转式编码器实现步进电机速度环控制算法

1. 步进电机闭环控制原理概述

我们知道步进电机是一种数字信号驱动的电机,其主要优点之一就是拥有很好的开环控制能力,控制系统不需要传感器和相应电路的反馈电机信息, 在负载不超载和脉冲频率合适的情况下,步进电机接收到的脉冲数和转子的角位移就是严格成正比关系。既然如此,那为什么要在步进电机上引入闭环控制呢? 虽然步进电机可以很好的开环控制,但实际在一些开环系统中,步进电机有可能由于自身性能及系统机械结构等因素的影响,在快速启停或负载突变时出现失步、过冲甚至堵转, 控制器无法知晓和矫正,这些现象在某些对精度要求较高的系统中可能导致严重后果。而加入传感器反馈组成闭环系统后,可以检测是否有失步等现象发生并及时纠正偏差。

目前的步进电机闭环控制方案有很多种,有些比较简单,只做失步的检测和矫正,有些非常复杂,可以完全控制步进电机的转矩和位置,改善步进电机的转矩频率特性, 降低发热和平均功耗,提高电机运行效率。平时听到的一些控制名词,比如速度环、位置环和电流环这些,就可以用于步进电机的闭环控制, 当然这些名词同样适用于其他的电机闭环系统。

在这里我们介绍一种以步进电机转速作为被控量(也就是速度环),使用旋转编码器作为反馈传感器,PID算法进行控制的闭环控制系统, 系统框图如下所示,为了方便叙述,没有将步机电机驱动器加入系统框图:

../_images/步进电机闭环控制原理.png

图中的旋转编码器作为反馈通道,负责收集步进电机转子在单位采样时间内的实际执行的步数,系统将实际步数转换为转速并与目标转速进行比较然后计算出偏差, 偏差值输入到PID控制器中,控制器输出经过修正的期望转速,最后交由步进电机执行。从框图中我们可以知道,当步进电机在运动过程中发生丢步, 会出现实际转速偏离目标转速,编码器将实际转速反馈给系统,控制器就能及时做出偏差修正。

2. 步进电机速度环控制–位置式PID

本案例结合PID控制、步进电机编码器测速来讲解如何使用位置式PID对步进电机进行速度闭环控制。 

PID的方案讲解参考:位置式PID算法讲解和C语言实现-CSDN博客

编码器测速的方案参考:增量式和位置式编码器的原理讲解以及步进电机测速方案实现-CSDN博客

3.步进电机速度环控制

stepper_ctrl.h

#ifndef __BSP_STEP_MOTOR_CTRL_H
#define	__BSP_STEP_MOTOR_CTRL_H


/*宏定义*/
/*******************************************************/
#define T1_FREQ           (SystemCoreClock/TIM_PRESCALER) // 频率ft值

/*电机单圈参数*/
#define STEP_ANGLE				1.8f                        //步进电机的步距角 单位:度
#define FSPR              ((float)(360.0f/STEP_ANGLE))//步进电机的一圈所需脉冲数

#define MICRO_STEP        32          				        //细分器细分数 
#define SPR               (FSPR*MICRO_STEP)           //细分后一圈所需脉冲数

#define PULSE_RATIO       ((float)(SPR/ENCODER_TOTAL_RESOLUTION))//步进电机单圈脉冲数与编码器单圈脉冲的比值
#define TARGET_SPEED      1                           //步进电机运动时的目标转速,单位:转/秒
#define SAMPLING_PERIOD   50                          //PID采样频率,单位Hz

typedef struct {
  unsigned char stepper_dir : 1;               //步进电机方向
  unsigned char stepper_running : 1;           //步进电机运行状态
  unsigned char MSD_ENA : 1;                   //驱动器使能状态
}__SYS_STATUS;


void MSD_ENA(int NewState);
void Set_Stepper_Stop(void);
void Set_Stepper_Start(void);
void Stepper_Speed_Ctrl(void);

#endif /* __STEP_MOTOR_CTRL_H */

stepper_ctrl.c-步进电机闭环控制

 /**
   * @brief  步进电机位置式PID控制
   * @retval 无
   * @note   基本定时器中断内调用
   */
 void Stepper_Speed_Ctrl(void)
 {
   /* 编码器相关变量 */
   __IO int16_t capture_per_unit = 0;
   __IO int32_t capture_count = 0;
   static __IO int32_t last_count = 0;

   /* 经过pid计算后的期望值 */
   __IO float cont_val = 0;

   /* 当电机运动时才启动pid计算 */
   if((sys_status.MSD_ENA == 1) && (sys_status.stepper_running == 1))
   {
     /* 计算单个采样时间内的编码器脉冲数 */
     capture_count = __HAL_TIM_GET_COUNTER(&TIM_EncoderHandle) + (encoder_overflow_count * ENCODER_TIM_PERIOD);
     capture_per_unit = capture_count - last_count;
     last_count = capture_count;

     /* 单位时间内的编码器脉冲数作为实际值传入pid控制器 */
     cont_val = PID_realize((float)capture_per_unit);// 进行 PID 计算

     /* 判断速度方向 */
     cont_val > 0 ? (MOTOR_DIR(CW)) : (MOTOR_DIR(CCW));

     /* 对计算得出的期望值取绝对值 */
     cont_val = fabsf(cont_val);
     /* 计算比较计数器的值 */
     OC_Pulse_num = ((uint16_t)(T1_FREQ / (cont_val * PULSE_RATIO * SAMPLING_PERIOD))) >> 1;

   #if PID_ASSISTANT_EN
     int temp = capture_per_unit;
     set_computer_value(SEED_FACT_CMD, CURVES_CH1, &temp, 1);  // 给通道 1 发送实际值
   #else
     printf("实际值:%d,目标值:%.0f\r\n", capture_per_unit, pid.target_val);// 打印实际值和目标值
   #endif
   }
   else
   {
     capture_per_unit = 0;
     cont_val = 0;
     pid.actual_val = 0;
     pid.err = 0;
     pid.err_last = 0;
     pid.integral = 0;
   }
 }

进电机闭环控制部分与步进电机速度环控制–增量式PID基本相同,这里只对不同点作出说明。

  • 第25行:使用 capture_per_unit 作为实际值传给位置式PID控制器进行运算,并把返回值赋值给 cont_val

闭环控制周期调用

步进电机闭环控制周期调用与上一节“步进电机速度环控制–增量式PID”完全相同。

main函数

main.c-主函数

/**
   * @brief  主函数
   * @param  无
   * @retval 无
   */
 int main(void)
 {
   /* 初始化系统时钟为168MHz */
   SystemClock_Config();
   /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
   DEBUG_USART_Config();
   printf("按下按键1启动电机、按键2停止、按键3增加目标值、按键4减少目标值\r\n");
   /* 初始化时间戳 */
   HAL_InitTick(5);
   /*按键中断初始化*/
   Key_GPIO_Config();
   /*led初始化*/
   LED_GPIO_Config();
   /* 初始化基本定时器定时,20ms产生一次中断 */
   TIMx_Configuration();
   /* 编码器接口初始化 */
   Encoder_Init();
   /*步进电机初始化*/
   stepper_Init();
   /* 上电默认停止电机 */
   Set_Stepper_Stop();
   /* PID算法参数初始化 */
   PID_param_init();

   /* 目标速度转换为编码器的脉冲数作为pid目标值 */
   pid.target_val = TARGET_SPEED * ENCODER_TOTAL_RESOLUTION / SAMPLING_PERIOD;

 #if PID_ASSISTANT_EN
   int Temp = pid.target_val;    // 上位机需要整数参数,转换一下
   set_computer_value(SEED_STOP_CMD, CURVES_CH1, NULL, 0);    // 同步上位机的启动按钮状态
   set_computer_value(SEED_TARGET_CMD, CURVES_CH1, &Temp, 1);// 给通道 1 发送目标值
 #endif

   while(1)
   {
     /* 扫描KEY1,启动电机 */
     if( Key_Scan(KEY1_GPIO_PORT,KEY1_PIN) == KEY_ON  )
     {
     #if PID_ASSISTANT_EN
       Set_Stepper_Start();
       set_computer_value(SEED_START_CMD, CURVES_CH1, NULL, 0);// 同步上位机的启动按钮状态
     #else
       Set_Stepper_Start();
     #endif
     }
     /* 扫描KEY2,停止电机 */
     if( Key_Scan(KEY2_GPIO_PORT,KEY2_PIN) == KEY_ON  )
     {
     #if PID_ASSISTANT_EN
       Set_Stepper_Stop();
       set_computer_value(SEED_STOP_CMD, CURVES_CH1, NULL, 0);// 同步上位机的启动按钮状态
     #else
       Set_Stepper_Stop();
     #endif
     }
     /* 扫描KEY3,增大目标速度 */
     if( Key_Scan(KEY3_GPIO_PORT,KEY3_PIN) == KEY_ON  )
     {
       /* 目标速度增加48,对应电机转速增加1 */
       pid.target_val += 48;

     #if PID_ASSISTANT_EN
       int temp = pid.target_val;
       set_computer_value(SEED_TARGET_CMD, CURVES_CH1, &temp, 1);// 给通道 1 发送目标值
     #endif
     }
     /* 扫描KEY4,减小目标速度 */
     if( Key_Scan(KEY4_GPIO_PORT,KEY4_PIN) == KEY_ON  )
     {
       /* 目标速度减小48,对应电机转速减少1 */
       pid.target_val -= 48;

     #if PID_ASSISTANT_EN
       int temp = pid.target_val;
       set_computer_value(SEED_TARGET_CMD, CURVES_CH1, &temp, 1);// 给通道 1 发送目标值
     #endif
     }
   }
 }

  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

驽马匠人

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

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

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

打赏作者

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

抵扣说明:

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

余额充值