硬件学习_STM32_CubeMX_自动控制_PID闭环控制电机转速

写在前面:

这是一个新的栏目,用于记录硬件方面学习的历程。
之前硬件学习是比较零散的,没有系统性的整理过,希望这个栏目的开设能让我的学习更加系统。
注:本栏目是在学习进程中新增的,内容无任何顺序、关联。
仅是个人记录用,不适合学习者观看。

准备:

知识储备:

  • 定时器中断相关知识
  • PWM电机控制相关知识
  • 编码器计数器相关知识

系统组成:

  • STM32F103C8T6
  • L298N或TB6612电机控制模块
  • 光电编码器电机

电机接口定义:

电机接口为6PIN 排线,左右两根为电机正负极,接至L298N的一个电机口
中间四根为编码器线路,外两根为编码器电源,最中间两根为编码器脉冲输出

L298N使用:

12V供电
L298N使用PWM控制时需要拔掉跳线帽,并通过BIN1和BIN2的电平高低控制正反转(4根线连接至F103,分别为PWM、GND、BIN1、BIN2)

编码器使用:

ams1117 -5.0给予5V供电
3根线接至F103,分别为脉冲2条、GND

定时器配置:

F103总共有4个定时器,配置如下:

TIM1——空
TIM2——转速采样,100HZ
TIM3——2频道,PWM信号时钟,10kHZ ,对应PA7输出PWM
TIM4——编码器计数模式,上升沿触发,对应PB6/7接编码器

代码逻辑:

当TIM2计时,回调函数获取电机脉冲并换算为速度,输入到PID控制器中,PID控制器输出占空比到L298N

PID闭环控制逻辑(重点学习):

相关笔记:
硬件学习_STM32_CubeMX_自动控制_PID闭环控制电机转速_第1张图片

此处图片存在错误,增量式PID中的OUT无需+=,因为后面的return已经加上原始值。

注意增量PID和位置PID输出值的区别!!

代码实现(部分)

control.h
#ifndef __CONTROL_H
#define __CONTROL_H


//全局变量
extern unsigned int MotorSpeed;
extern int SpeedTarget;
extern int MotorOutput;

//函数声明
void GetMotorPulse(void);
int SpeedInnerControl(int Speed,int Target);
void SetMotorVoltageAndDirection(int Pwm);

#endif
control.c
#include "control.h"
#include "tim.h"
#include "main.h"
#include "math.h"

unsigned int MotorSpeed;//全局变量,电机当前速度数值,在encoder.c中获取
int SpeedTarget = 300;	//全局变量,速度目标值
int MotorOutput;		//全局变量,电机输出


//1.通过TIM4读取电机脉冲并计算速度

void GetMotorPulse(void)
{
    MotorSpeed = (short)(__HAL_TIM_GET_COUNTER(&htim4)/10);//TIM4计数器获得电机脉冲,该电机在10ms采样的脉冲/10则为实际转速的rpm
    __HAL_TIM_SET_COUNTER(&htim4,0);//计数器清零
}


//2.增量式PID控制器

int Error_Last,Error_Prev;//上一次偏差值,上上次误差
int Pwm_add,Pwm;//PWM增量,PWM输出占空比

float Kp = 10.0, Ki = 0.9, Kd = 0.0;//PID系数

int SpeedInnerControl(int Speed,int Target)//速度内环控制
{
    int Error = Speed - Target;		//偏差 = 目标速度 - 实际速度

    Pwm_add = Kp * (Error - Error_Last) + 										//比例
							Ki * Error +																		//积分
							Kd * (Error - 2.0f * Error_Last + Error_Prev);	//微分


    Pwm += Pwm_add;		//原始量+增量=输出量
	
		Error_Prev = Error_Last;	//保存上上次误差
    Error_Last = Error;	//保存上一次偏差

    if(Pwm > 100) Pwm = 100;	//限制上下限,防止超出PWM量程
    if(Pwm <-100) Pwm =-100;

    return Pwm;	//返回输出值
}



//3.电机电压和方向控制函数

void SetMotorVoltageAndDirection(int Pwm)
{
    if(Pwm < 0)//如果是反转
    {
        
			  HAL_GPIO_WritePin(BIN1_GPIO_Port, BIN1_Pin, GPIO_PIN_SET);//L298N反向
        HAL_GPIO_WritePin(BIN2_GPIO_Port, BIN2_Pin, GPIO_PIN_RESET);
        
				Pwm = (-Pwm);//如果计算值是负值,先取负得正,因为PWM寄存器只能是正值
        
				__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, Pwm);//输出
			
    } else
    {
			
        HAL_GPIO_WritePin(BIN1_GPIO_Port, BIN1_Pin, GPIO_PIN_RESET);
        HAL_GPIO_WritePin(BIN2_GPIO_Port, BIN2_Pin, GPIO_PIN_SET);
			
        __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, Pwm);
    }
}

TIM2回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim == &htim2)
    {
    	//1.获取电机速度
		GetMotorPulse();
		//2.PID控制器,取回占空比
        MotorOutput = SpeedInnerControl(MotorSpeed,SpeedTarget);
        //3.将占空比导入至电机控制函数
        SetMotorVoltageAndDirection(MotorOutput);

    }
}

实际调试:

使用Keil5自带Debug调试
使用STM32Studio调试
用手尝试让电机停止,观察控制效果
按住RST键在放开,可以观察到电机启动的曲线

CubeMX、HAL库是个好东西

能不用杜邦线不用杜邦线

磨刀不误砍柴工

兴趣是最好的老师

懂得放弃,但有时可以捡回来

每天锻炼一小时,幸福生活一辈子

你可能感兴趣的:(硬件学习,STM32,自动控制)