【电机控制】小白从零开始:STM32双闭环(速度环、位置环)电机控制(软件篇)

这篇具有很好参考价值的文章主要介绍了【电机控制】小白从零开始:STM32双闭环(速度环、位置环)电机控制(软件篇)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

小白从零开始:STM32双闭环(速度环、位置环)电机控制(软件篇)


小白从零开始:STM32双闭环(速度环、位置环)电机控制(硬件篇)

前言

小白从零开始:STM32双闭环(速度环、位置环)电机控制(软件篇)

杭州研究生手把手教你搞不定STM32

使用工具:
1.语言:C语言
2.代码编译:KEIL5、
3.代码烧录:FLYMCU

【电机控制】小白从零开始:STM32双闭环(速度环、位置环)电机控制(软件篇),电机控制,stm32,单片机,嵌入式硬件


提示:以下是本篇文章正文内容,下面案例可供参考

一、电机测速

#include "encoder.h"
void Encoder_TIM4_Init(void)
{      
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_ICInitTypeDef TIM_ICInitStructure;
//      NVIC_InitTypeDef    NVIC_InitStructure;	

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//ʹÄܶ¨Ê±Æ÷4µÄʱÖÓ
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//ʹÄܶ˿ÚB
	
	/*- Õý½»±àÂëÆ÷ÊäÈëÒý½Å PB->6   PB->7 -*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;//¶Ë¿ÚÅäÖà      
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//¸¡¿ÕÊäÈë
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure); //³õʼ»¯GPIOB                        

	/*- TIM4±àÂëÆ÷ģʽÅäÖà -*/
	//TIM_DeInit(TIM4); 
	TIM_TimeBaseStructure.TIM_Period = 65535;//¼Æ´ÎÊý;ÉèÖüÆÊýÆ÷×Ô¶¯ÖØ×°ÔØ
	TIM_TimeBaseStructure.TIM_Prescaler = 0;//Ô¤·ÖƵÆ÷
	TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1 ;//Ñ¡ÔñʱÖÓ·ÖƵģʽ£º²»·ÖƵ
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//Á¬ÐøÏòÉϼÆÊýģʽ
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);              
                 
	TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_BothEdge ,TIM_ICPolarity_BothEdge);	//ÅäÖñàÂëÆ÷ģʽ´¥·¢Ô´ºÍ¼«ÐÔË«±ßÑؼì²â ²»ÖªµÀ¿ÉÒÔ¿´¼¼ÊõÊÖ²áÉÏÃæÓнéÉܱàÂëÆ÷ģʽ
	//ʹÓñàÂëÆ÷ģʽ3
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 	Ñ¡ÔñÊäÈë¶Ë IC1Ó³Éäµ½TI1ÉÏ
 	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge;	//ÉÏÉýÑز¶»ñ
 	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //Ó³Éäµ½TI1ÉÏ
 	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;	 //ÅäÖÃÊäÈë·ÖƵ,²»·ÖƵ
 	TIM_ICInitStructure.TIM_ICFilter = 0x01;//IC1F=0000 ÅäÖÃÊäÈëÂ˲¨Æ÷ ²»ÂË
// 
	TIM_ICInit(TIM4, &TIM_ICInitStructure);
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//ÇÀÕ¼ÓÅÏȼ¶2
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//×ÓÓÅÏȼ¶3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQͨµÀʹÄÜ
	NVIC_Init(&NVIC_InitStructure);	//¸ù¾ÝÖ¸¶¨µÄ²ÎÊý³õʼ»¯VIC¼Ä´æÆ÷
	
	TIM_ClearFlag(TIM4, TIM_FLAG_Update);
      TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); 	
	TIM_SetCounter(TIM4,0);
	TIM_Cmd(TIM4, ENABLE);   //Æô¶¯TIM4¶¨Ê±Æ÷
 }

__IO int16_t EncoderOverflowCnt = 0;
//¶¨Ê±Æ÷4ÖжϷþÎñ³ÌÐò
void TIM4_IRQHandler(void)
{
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET)
	{
		if((TIM4->CR1 & TIM_CounterMode_Down) != TIM_CounterMode_Down)
		{
			EncoderOverflowCnt++;/*±àÂëÆ÷¼ÆÊýÖµ[ÏòÉÏ]Òç³ö*/
		}
		else
		{
			EncoderOverflowCnt--;/*±àÂëÆ÷¼ÆÊýÖµ[ÏòÏÂ]Òç³ö*/
		}
	}
	TIM_ClearITPendingBit(TIM4,TIM_IT_Update);  //Çå³ýÖжϱê־λ
}
int Read_Speed(void)
{
  int Encoder_TIM;    

		Encoder_TIM= (short)TIM4 -> CNT;  
		TIM4 -> CNT=0;	

		return Encoder_TIM;
}

二、电机PID控制算法

记得PID参数自己调一下哦

/**************************************************************************
º¯Êý¹¦ÄÜ£ºÔöÁ¿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_P(int Encoder,int Target)
{ 	
  static int pwmout=0,last_error=0,last_last_error=0;
  int error =Target  - Encoder;
	int d_error=error-last_error;
  int dd_error = -2*last_error+error+last_last_error; 
//	//ËÀÇøãÐÖµ	
//	if((error>-cu_error_zone)&&(error<cu_error_zone))
//	{
//		error=0;
//		d_error=0;
//		dd_error=0;
//	}
  pwmout+=P*d_error/10 +I*error/10+D*dd_error/10;
  last_last_error=last_error;
  last_error = error;
	if(pwmout > 1000) pwmout = 1000;
	if(pwmout <=0) pwmout = 0;
  return pwmout;
}

/**************************************************************************
º¯Êý¹¦ÄÜ£ºÔöÁ¿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 (int Encoder,int Target)
{ 	
  float KP = 0;
	float KI = 0;
	float KD = 0;
  static int pwmout=0,last_error=0,last_last_error=0;
  int error =Target  - Encoder;
	int d_error=error-last_error;
  int dd_error = -2*last_error+error+last_last_error; 
  pwmout+=KP*d_error/10 +KI*error/10+KD*dd_error/10;
  last_last_error=last_error;
  last_error = error;
	if(pwmout > 1000) pwmout = 1000;
	if(pwmout <=0) pwmout = 0;
  return pwmout;
}

/**************************************************************************
º¯Êý¹¦ÄÜ£ºÎ»ÖÃʽPID¿ØÖÆÆ÷
Èë¿Ú²ÎÊý£º±àÂëÆ÷²âÁ¿Öµ£¬Ä¿±êλÖÃ
·µ»Ø  Öµ£ºµç»úPWM
¸ù¾ÝÔöÁ¿Ê½ÀëÉ¢PID¹«Ê½ 
pwm+=Kp[e£¨k£©+Ki*e(k)+Kd[e(k)-e(k-1)]
e(k)´ú±í±¾´ÎÆ«²î 
e(k-1)´ú±íÉÏÒ»´ÎµÄÆ«²î  ÒÔ´ËÀàÍÆ 
pwm´ú±íÔöÁ¿Êä³ö
pwm+=Kp[e£¨k£©-e(k-1)]+Ki*e(k)
**************************************************************************/
int Incremental_PID (int Encoder,int Target)
{ 	

  static int pwmout=0,last_error=0,I_error=0;
	int error=Target-Encoder;
		int d_error=error-last_error;	
//È¡¾ø¶ÔÖµ
//	if(error>0)error=error;
//	else error=-error;
//ËÀÇøãÐÖµ	
	if((error>-lo_error_zone)&&(error<lo_error_zone))
	{
		error=0;
		I_error=0;
		d_error=0;
	}
//»ý·ÖÏî¡¢»ý·Ö·ÖÀë½Ï´óÆ«²îʱȥµô»ý·Ö×÷ÓÃ
	if(error>lo_integral_start && error<lo_integral_max)
	{
		I_error+=error;
		if(I_error>lo_integral_max)
		{
			I_error=lo_integral_max;
		}
		else if(I_error<-lo_integral_max)
		{
			I_error=-lo_integral_max;
		}
	}
	//I_error+=error;
//λÖÃʽPIDËã·¨
  pwmout+=KPP*error/10 +KII*I_error/10+KDD*d_error/10;
//Îó²î´«µÝ
	last_error = error;
//PWMÏÞ·ù
	if(pwmout > 1000) pwmout = 1000;
	if(pwmout <=0) pwmout = 0;
//·µ»Øµ±Ç°Êµ¼ÊÖµ
  return pwmout;
}

三、电机PWM输出

PWM占空比输出脉冲

#include "pwm.h"
#include "led.h"

//PWMÊä³ö³õʼ»¯
//arr£º×Ô¶¯ÖØ×°Öµ
//psc£ºÊ±ÖÓÔ¤·ÖƵÊý
void PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStruct;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	TIM_OCInitTypeDef TIM_OCInitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1 | RCC_APB2Periph_AFIO,ENABLE);//¿ªÆôʱÖÓ
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;//³õʼ»¯GPIO--PA8¡¢PA11Ϊ¸´ÓÃÍÆÍìÊä³ö
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8 |GPIO_Pin_11;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	TIM_TimeBaseStructInit(&TIM_TimeBaseInitStruct);//³õʼ»¯¶¨Ê±Æ÷¡£
	TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period=arr;
	TIM_TimeBaseInitStruct.TIM_Prescaler=psc;
	TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitStruct);/*¡¾2¡¿*///TIM2
	
	TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1;//³õʼ»¯Êä³ö±È½Ï
	TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;
	TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
	TIM_OCInitStruct.TIM_Pulse=0;
	TIM_OC1Init(TIM1,&TIM_OCInitStruct);
	TIM_OC4Init(TIM1,&TIM_OCInitStruct);
	
	TIM_CtrlPWMOutputs(TIM1,ENABLE);//¸ß¼¶¶¨Ê±Æ÷רÊô--MOEÖ÷Êä³öʹÄÜ
	
	TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);/*¡¾3¡¿*///ENABLE//OC1ԤװÔؼĴæÆ÷ʹÄÜ
	TIM_OC4PreloadConfig(TIM1,TIM_OCPreload_Enable);//ENABLE//OC4ԤװÔؼĴæÆ÷ʹÄÜ
	TIM_ARRPreloadConfig(TIM1,ENABLE);//TIM1ÔÚARRÉÏԤװÔؼĴæÆ÷ʹÄÜ
	
	TIM_Cmd(TIM1,ENABLE);//¿ª¶¨Ê±Æ÷¡£
 

}

void Motor_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);//¿ªÆôʱÖÓ
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//³õʼ»¯GPIO--PB12¡¢PB13¡¢PB14¡¢PB15ΪÍÆÍìÊä³ö
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	//GPIO_SetBits(GPIOA,GPIO_Pin_8);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//³õʼ»¯GPIO--PB12¡¢PB13¡¢PB14¡¢PB15ΪÍÆÍìÊä³ö
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_13;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOC,&GPIO_InitStruct);
	GPIO_SetBits(GPIOC,GPIO_Pin_13);
	
	
}



四、双闭环速度环在内、位置环在外

单闭环正转速度环

		Motor_pwm=Incremental_PI(speed,set_speed);			//»ñÈ¡PID¼ÆËãµÄPWMÖµ
		TIM_SetCompare1(TIM1,Motor_pwm);								//Êä³öPWMÖµ
		LED0=0;
		LED1=1;

单闭环正转位置环

		Motor_pwm=Incremental_PID(position,set_potision);			//»ñÈ¡PID¼ÆËãµÄPWMÖµ
		TIM_SetCompare1(TIM1,Motor_pwm);								//Êä³öPWMÖµ
		LED0=0;
		LED1=1;

双闭环正转位置环+速度环

		if((t++%2) == 0)
		{
			Motor_pwm=Incremental_PID(position,set_potision);			//»ñÈ¡PID¼ÆËãµÄPWMÖµ
		}
		Motor_pwm=Incremental_PI(speed,Motor_pwm);			//»ñÈ¡PID¼ÆËãµÄPWMÖµ
		TIM_SetCompare1(TIM1,Motor_pwm);								//Êä³öPWMÖµ
		LED0=0;
		LED1=1;

总结

本文仅仅简单介绍了软件驱动方面的配置,评论区欢迎讨论。文章来源地址https://www.toymoban.com/news/detail-658769.html

到了这里,关于【电机控制】小白从零开始:STM32双闭环(速度环、位置环)电机控制(软件篇)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 基于STM32闭环步进电机控制系统设计

    ** 单片机设计介绍,1654基于STM32闭环步进电机控制系统设计(仿真,程序,说明)   基于STM32的闭环步进电机控制系统设计是一种利用STM32微控制器开发的系统,用于实现对步进电机的精确控制。以下是该系统的一般设计概述: STM32微控制器:作为主控芯片,STM32具备高性能

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

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

    2024年02月01日
    浏览(36)
  • STM32F103C8T6实现CAN通讯与直流编码电机转速闭环控制

    本次实验目的是通过CAN发送目标转速与转向信息,接收方在接到CAN数据流后开始对直流编码电机进行转速闭环控制。我会尽量说清每个函数,注释每一句代码,希望能对大家有所帮助。 CAN通讯基于STM32自带CAN通讯模块,配合库函数使用十分方便。关于CAN通讯可以参考站内大佬

    2023年04月08日
    浏览(25)
  • Makerbase SimpleFOC ESP32例程4 双电机闭环速度测试

    1.1 硬件清单 序号 品名 数量 1 ESP32 FOC V1.0 主板 1 2 YT2804电机 2 3 12V电源适配器 1 4 USB 线 1 5 6pin杜邦线 2 注意:YT2804是改装的云台无刷电机,带有AS5600编码器,可实现360°连续运转。 主要参数如下: 序号 品名 数量 1 输入电压 12V 2 极对数 7 3 工作电流 180mA 4 最大转速 3840RPM 5 编码

    2024年02月08日
    浏览(32)
  • 【STM32】使用HAL库进行电机速度环PID控制,代码+调参

    主控:STM32F103C8T6 在进行速度控制之前,我们首先需要进行速度采样,这里参见这篇博文 ​ 这里不细说电机驱动模块的选型和使用,而是说一个常见的误区。我们驱动电机要使用两路PWM,一般是一路给PWM信号,一路是纯低电平。但这其实是不好的,正确的做法是一路给PWM,另

    2023年04月20日
    浏览(41)
  • 【STM32】使用HAL库进行电机PID位置环控制,代码+调参

    前面两篇博文已经实现了电机测速和PID速度环控制,在这篇博文中,我们主要说明位置环的代码怎么写以及PID参数怎么调。 ​ 写完速度环后位置环就很简单了。 ​ 在串级PID中,内环的控制量一般是外环控制量的微分。在我们这里,外环是控制量是电机转动的位置(也可以说

    2024年02月16日
    浏览(32)
  • STM32单片机PWM控制实现电机调速度(小车运动,STM32F103C8T6&TB6612&TT电机)

    作者:公子易平 时间:2023/6/6 前段时间做一个智能小车的相关项目时,发现很少有人能够将STM32的PWM控制讲清楚,故而书此文,希望对后来的学习者有所帮助。 STM32F103C8T6最小系统板 直流TT电机 电机驱动芯片(TB6612) 杜邦线若干 接线情况: TB6612引脚说明: STM32主控芯片与TB6612接

    2024年02月15日
    浏览(31)
  • S速度曲线轨迹规划(普通变频位置闭环控制算法详细介绍+SCL代码)

    位置控制用PD控制器,详细内容介绍请查看下面博客文章: PD控制器算法详细解读_RXXW_Dor的博客-CSDN博客 鉴于积分和微分在工程上的大量应用,这篇博文主要讲解工程上的如何求导f\\\'(x),导数反映的是函数(信号)的变化率,牛顿也是在研究运动的时候提出了微积分的概念,我

    2024年02月12日
    浏览(33)
  • 基于STM32F103C8T6使用Arduino IDE编程闭环控制4个带编码器的有刷直流电机

    题记:标题有点长了,纯粹为了方便被检索到~~~本贴主要用于支持南方科技大学SDIM学院工业设计专业大三综合项目移动底盘学习,也是我自己按照费曼学习方法的一次尝试,用从底层搭建一个机器人底盘来复习自动控制原理。         由于工业设计专业没有开设嵌入式课程

    2024年02月05日
    浏览(29)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包