STM32 HAL库PID控制电机 第三章 PID控制双电机

这篇具有很好参考价值的文章主要介绍了STM32 HAL库PID控制电机 第三章 PID控制双电机。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

STM32 HAL库PID控制电机

第三章 PID控制双电机

注:本文含全部PID控制代码,保证可以运行,如不能运行可以留言回复

1 基础配置

1.1 编码器电路图及配置

stm32的pid精准控制电机,STM32HAL库入门学习,stm32,单片机,嵌入式硬件

引脚 定时器通道
PA0 TIM2_CH1
PA1 TIM2_CH2
PB6 TIM4_CH1
PB7 TIM4_CH2

因此需要把TIM2、TIM4配置为编码器模式。在STM32CubeIDE中找到定时器2与定时器4,进行模式配置。以下以定时器2为例,定时器4只需进行相同配置即可。选择定时器为编码器模式,设置为不分频,最大计数值为65535,使能自动重装载,并选择TI1和TI2两路输入,实现四倍频效果。
stm32的pid精准控制电机,STM32HAL库入门学习,stm32,单片机,嵌入式硬件
stm32的pid精准控制电机,STM32HAL库入门学习,stm32,单片机,嵌入式硬件
配置完定时器2和定时器4后,需要再使用一个定时器,利用其产生50ms中断来读取当前的小车速度值,本次例程中采用定时器3产生中断。

周期为50ms,计算方法为 :T=(arr+1)*(psc+1)/Tclk

注意: T I M 3 需要在 N V I C S e t t i n g 中开启中断 \color{red}{注意:TIM3需要在NVIC Setting中开启中断} 注意:TIM3需要在NVICSetting中开启中断
stm32的pid精准控制电机,STM32HAL库入门学习,stm32,单片机,嵌入式硬件

1.2 增量式PID控制

PID可以分为位置式PID与增量式PID,关于PID的具体控制原理知识不在此进行详细介绍,在这篇文章有:https://blog.csdn.net/weixin_43002939/article/details/130178782

重点介绍的为在本例程中采用的增量式PID。

增量式PID是通过改变输出量的大小来控制被控量的稳定,增量式PID与位置式PID不同,增量式返回的数值为当前时刻的控制量与上一时刻的控制量的差值,以此差值作为新的控制量进行反馈。

举个例子:设定小车的速度为0.2m/s,通过编码器进行测速得到速度反馈,与设定值产生了偏差ek,系统中保存了上一次的偏差e(k-1)还有上上次的的偏差e(k-2),这三个值作为输入量通过增量式PID的计算公式得到Δu(k),将上一次经过PID计算后的u(k-1)加上本次的增量Δu(k),便得到本次控制周期的PID输出u(k)。将输出值经过二次的计算转换后,得到可以对电机转速进行控制的PWM占空比,进而对小车的运动速度进行控制。

增量式PID的公式:Kp比例系数、Ki积分系数、Kd微分系数、e(k)偏差

Δu(k)=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]

了解增量式PID的一些基础知识后,让我们来看看如何用代码实现算法过程吧!文章来源地址https://www.toymoban.com/news/detail-570867.html

2 main.c文件

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : Main program body
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2023 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "rtc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "../../icode/pid/pid.h"
#include "../inc/retarget.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
int  Encoder_A,Encoder_B ; //编码器的脉冲计数
float  Target_Velocity_A=30,Target_Velocity_B=30;
int Moto_A=0,Moto_B=0; //电机PWM变量 应是Motor的 向Moto致敬
float Velocity_KP_A = 1, Velocity_KI_A = 0.2, Velocity_KD_A = 0; //PID系数
float Velocity_KP_B = 1, Velocity_KI_B = 0.2, Velocity_KD_B = 0;

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_RTC_Init();
  MX_TIM1_Init();
  MX_USART1_UART_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_TIM4_Init();
  /* USER CODE BEGIN 2 */


	HAL_TIM_Base_Start_IT(&htim3);                       //开启10ms定时器中断
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_4); //开启TIM1的PWM
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
	HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_1);  //启动定时器2的编码器模式
	HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_2);
	HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_1);  //启动定时器4的编码器模式
	HAL_TIM_Encoder_Start(&htim4, TIM_CHANNEL_2);
	RetargetInit(&huart1);


  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
	while (1) {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */


	}
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSI|RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.LSIState = RCC_LSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC;
  PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSI;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)  //定时器3中断回调函数
{

	if (htim == (&htim3)) {
		Encoder_A=Read_Velocity(2);		//===更新速度信息
		Encoder_B=Read_Velocity(4);
		Moto_A=Incremental_PI_A(CalActualSpeed(Encoder_A),Target_Velocity_A);	//===速度PID控制器
		Moto_B=Incremental_PI_B(CalActualSpeed(Encoder_B),Target_Velocity_B);
		Xianfu_Pwm();                                  //===PWM限幅
		Set_Pwm_A(Moto_A);
		Set_Pwm_B(Moto_B);
//		Set_Pwm(Target_Velocity_A);

//		printf("Target_Velocity_A:%.2f \n",Target_Velocity_A);


		printf("%.2f,%.2f \n",CalActualSpeed(Encoder_A),CalActualSpeed(Encoder_B));

//		printf("Encoder_B:%.2f \n",CalActualSpeed(Encoder_B));
//		printf("Moto_A is %d\r\n",Moto_A);

//		printf("Target_Velocity_B: %.2f\r\n",Target_Velocity_B);
//		printf("Encoder_B is %d \r\n",Encoder_B);
//		printf("Moto_B is %d\r\n",Moto_B);




	}

}
/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
	/* User can add his own implementation to report the HAL error return state */
	__disable_irq();
	while (1) {
	}
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

3 pid.c

/*
 * pid.c
 *
 *  Created on: 2023年4月4日
 *      Author: 77454
 */

#include "pid.h"

/**************************************************************************
 函数功能:单位时间读取编码器计数
 入口参数:定时器
 返回  值:速度值
 **************************************************************************/
int Read_Velocity(uint8_t TIMX) {
	int Encoder_TIM;
	switch (TIMX) {
	case 2:
		Encoder_TIM = -(short) TIM2->CNT;
		TIM2->CNT = 0;
		break;
	case 3:
		Encoder_TIM = (short) TIM3->CNT;
		TIM3->CNT = 0;
		break;
	case 4:
		Encoder_TIM = (short) TIM4->CNT;
		TIM4->CNT = 0;
		break;
	default:
		Encoder_TIM = 0;
	}
	return Encoder_TIM;
}

//计算速度  cm/s
float CalActualSpeed(int pulse) {
	return (float) (0.3092424 * pulse);
}

/**************************************************************************
 函数功能:取绝对值
 入口参数:int
 返回  值:unsigned int
 **************************************************************************/
int myabs(int a) {
	int temp;
	if (a < 0)
		temp = -a;
	else
		temp = a;
	return temp;
}

/**************************************************************************
 函数功能:赋值给PWM寄存器
 入口参数:PWM
 返回  值:无
 **************************************************************************/
void Set_Pwm_A(int moto_A) {
	if (moto_A < 0) {
		HAL_GPIO_WritePin(AIN1_GPIO_Port, AIN1_Pin, GPIO_PIN_SET);
		HAL_GPIO_WritePin(AIN2_GPIO_Port, AIN2_Pin, GPIO_PIN_RESET);
	} else {
		HAL_GPIO_WritePin(AIN1_GPIO_Port, AIN1_Pin, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(AIN2_GPIO_Port, AIN2_Pin, GPIO_PIN_SET);
	}

	__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_4, myabs(moto_A));

}
void Set_Pwm_B(int moto_B) {
	if (moto_B < 0) {
		HAL_GPIO_WritePin(BIN1_GPIO_Port, BIN1_Pin, GPIO_PIN_RESET);
		HAL_GPIO_WritePin(BIN2_GPIO_Port, BIN2_Pin, GPIO_PIN_SET);
	} else {
		HAL_GPIO_WritePin(BIN1_GPIO_Port, BIN1_Pin, GPIO_PIN_SET);
		HAL_GPIO_WritePin(BIN2_GPIO_Port, BIN2_Pin, GPIO_PIN_RESET);
	}
	__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, myabs(moto_B));
}
/**************************************************************************
 函数功能:限制PWM赋值
 入口参数:无
 返回  值:无
 **************************************************************************/
void Xianfu_Pwm(void) {
	int Amplitude = 7200;    //===PWM满幅是7200 限制在7100
	if (Moto_A < -Amplitude)
		Moto_A = -Amplitude;
	if (Moto_A > Amplitude)
		Moto_A = Amplitude;
	if (Moto_B < -Amplitude)
		Moto_B = -Amplitude;
	if (Moto_B > Amplitude)
		Moto_B = Amplitude;
}

/**************************************************************************
 函数功能:增量PI控制器
 入口参数:编码器测量值,目标速度
 返回  值:电机PWM
 根据增量式离散PID公式
 pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)+Kd[e(k)-2e(k-1)+e(k-2)]
 e(k)代表本次偏差
 e(k-1)代表上一次的偏差  以此类推
 pwm代表增量输出
 在我们的速度控制闭环系统里面,只使用PI控制
 pwm+=Kp[e(k)-e(k-1)]+Ki*e(k)
 **************************************************************************/
int Incremental_PI_A(float Encoder, float Target) {
	static float Bias_A, Pwm_A, Last_bias_A;
	Bias_A = Target - Encoder;                                  //计算偏差
	Pwm_A += Velocity_KP_A * (Bias_A - Last_bias_A) + Velocity_KI_A * Bias_A; //增量式PI控制器
	Last_bias_A = Bias_A;	                                   //保存上一次偏差
	return Pwm_A;                                           //增量输出
}

int Incremental_PI_B(float Encoder, float Target) {
	static float Bias, Pwm, Last_bias;
	Bias = Target - Encoder;                                  //计算偏差
	Pwm += Velocity_KP_B * (Bias - Last_bias) + Velocity_KI_B * Bias; //增量式PI控制器
	Last_bias = Bias;	                                   //保存上一次偏差
	return Pwm;                                           //增量输出
}


4 pid.h

/*
 * pid.h
 *
 *  Created on: 2023年4月4日
 *      Author: 77454
 */

#ifndef PID_PID_H_
#define PID_PID_H_

#include "main.h"
#include "tim.h"

extern int Encoder_A;
extern float Target_Velocity_A;
extern int Moto_A;
extern float Velocity_KP_A;
extern float Velocity_KI_A;
extern float Velocity_KD_A;

extern int Encoder_B;
extern float Target_Velocity_B;
extern int Moto_B;
extern float Velocity_KP_B;
extern float Velocity_KI_B;
extern float Velocity_KD_B;


int Read_Velocity(uint8_t TIMX);
int myabs(int a);
void Set_Pwm_A(int moto_A);
void Set_Pwm_B(int moto_B);
int Incremental_PI_A(float Encoder,float Target);
int Incremental_PI_B(float Encoder, float Target);

void Xianfu_Pwm(void);
float CalActualSpeed(int pulse);




#endif /* PID_PID_H_ */

到了这里,关于STM32 HAL库PID控制电机 第三章 PID控制双电机的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32CubeMX 直流电机串级PID位置速度控制、HAL库、cubemx、PID、串级PID、位置控制、速度控制、双环控制

    提示:本文章的串级PID位置速度控制,是在前两篇文章速度控制,位置控制的基础上实现的,这一章节中不需要额外的cubemx的配置,只需要写简单的代码即可,复杂的地方在于串级pid的调试过程。 pid是我们在学习单片机中首先要学会的控制算法,而串级pid又是在单pid的基础上

    2024年02月14日
    浏览(53)
  • STM32 HAL库PID控制电机 第二章 TB6612FNG芯片驱动GB37-520电机

    1 电路图 2 TB6612简介 TB6612是双驱动,可同时驱动两个电机 STBY:接单片机的IO口清零电机全部停止,置1通过AIN1 AIN2,BIN1,BIN2 来控制正反转 VM:建议接10V以内电源( 瞬间上电12V可能会有尖峰电压击穿器件 ) VCC:接5V电源 GND:接电源负极 PWMA:接单片机的PWM口 ,控制转速 PWM

    2023年04月22日
    浏览(95)
  • stm32(HAL)库编码器电机pid代码及利用VOFA+对Pid波形显示调参

    PID控制是一种经典的反馈控制算法,它通过不断地调整输出来使系统的实际值与设定值尽量接近,并保持在设定值附近。PID控制器由三个部分组成:比例§、积分(I)和微分(D)。 比例作用(P):比例作用通过测量实际值与设定值之间的偏差,乘以一个比例系数来产生输出。输出

    2024年02月13日
    浏览(62)
  • 基于stm32的减速直流电机PID算法控制

    本例程采用了HAL库进行项目开发(主要使用软件CubexMX和keil5),文章末尾会有代码开源,欢迎各位对文章进行指正和探讨。         硬件组成:stm32f103c8t6最小系统板;0.96寸LED12864(I2C通讯模式);智能小车12v移动电源;25GA370直流减速电机(带霍尔编码器);JDY-31蓝牙模块

    2024年02月20日
    浏览(48)
  • QT上位机控制stm32,并利用PID控制编码电机旋转

    QT上位机控制stm32,并利用PID控制编码电机旋转             由于最近在学习电机控制算法之类的东西,看到论文大多使用PID、或以PID衍生的ADRC作为电机的主流控制,于是自己也写了一个stm32控制L298N以驱动直流电机的程序,并用QT做了一个上位机实现了用软件改变PID的参数

    2023年04月09日
    浏览(45)
  • stm32cubemx hal学习记录:电机控制

    1、配置RCC、SYS,SYS的Timebase Source选择TIM6 2、配置USART1、时钟84MHz 3、激活FreeRTOS,选择CMSIS_V1,Config parameters种USE_TIMERS选择ENABLE 1、选用TIM3的编码器模式  2、驱动使用L298N,将PB6、PB7设置为输出模式  3、使用TIM2的CH1输出1kHz的PWM 1、设置两个软件定时器,一个用于总控制,一个

    2024年02月17日
    浏览(42)
  • 【正点原子STM32连载】第三十三章 待机模式实验 摘自【正点原子】APM32F407最小系统板使用指南

    1)实验平台:正点原子stm32f103战舰开发板V4 2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420 3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html## 本章介绍APM32F407低功耗模式中的待机模式,进入待机模式后,MCU内部的电压调压器将断开1.3V电源域

    2024年02月07日
    浏览(57)
  • 【正点原子STM32连载】第三十三章 单通道ADC采集实验 摘自【正点原子】APM32E103最小系统板使用指南

    1)实验平台:正点原子APM32E103最小系统板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420 3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban 本章介绍使用APM32E103模数转换器(ADC)进行带通道的电压采集。通过本章的学习,读者将学习到单通

    2024年02月19日
    浏览(58)
  • STM32控制步进电机:基于HAL库定时器中断的闭环步进电机驱动+精准控制脉冲数

    该篇文章中用到的步进电机闭环驱动器为Emm42_V4.0步进电机闭环驱动器。该闭环驱动器自带FOC矢量闭环控制算法,能实现力矩、速度、位置三环控制。 如下图所示,该42步进闭环电机驱动器的A+、A-、B+、B-连接步进电机,通过右侧的使能、脉冲、方向端对步进电机进行驱动控制

    2024年02月01日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包