ROS机器人DIY教程之,STM32电机PWM控制

简介:

电机调速需要使用到STM32的PWM输出控制电机驱动器从而完成电机调速功能。

1、实现的工具

starrobot底层开发板、12V 5200ma锂电池、GB37-520减速电机、USB数据线、Keil5

ROS机器人DIY教程之,STM32电机PWM控制_第1张图片ROS机器人DIY教程之,STM32电机PWM控制_第2张图片ROS机器人DIY教程之,STM32电机PWM控制_第3张图片

starrobot底层开发板板载了A4950电机驱动器,预留和电机相同线序的XH2.54-6P接口,即插即用。电机转动主要使用到电机线+、电机线-两根线,编码器GND、编码器B相、编码器A相、编码器5V主要用于测速,这个下一章节通过编码器获取电机转速值会进行讲解。A4950电机驱动芯片支持8~25V、最大电流3A的输出,可以满足常用的GB37-520减速电机驱动。驱动芯片原理如下:

ROS机器人DIY教程之,STM32电机PWM控制_第4张图片

选择PWM互补输出,PWM互补输出IN1和IN2都是PWM,只是同一时刻的值是相反的,如下图:

假设黄色是IN1、蓝色是IN2同一时刻IN1为高电平,IN2则为低电平,从而使电机进行转动,只需要两个引脚即可。

ROS机器人DIY教程之,STM32电机PWM控制_第5张图片

2、代码分享

首先我们要知道,STM32单片机引脚PWM电压输出为0~3.3V。PWM一个周期内有高电平和低电平,高低电平时间的不同就可以得到不同的占空比。STM32中影响PWM的主要有两个参数:

1、预分频值psc,决定定时器的时钟频率

2、自动重载值arr,范围在0~65535之间,决定了定时器溢出的时间。

本文使用STM32F4定时器1的时钟频率为168M:如果psc = 168,arr = 1000,那么PWM频率 f = (168/168)M/1000 = 1kHz

void MotorInit(uint32_t arr_,uint32_t psc_)    
{
        GPIO_InitTypeDef GPIO_InitStructure;
	    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	    TIM_OCInitTypeDef       TIM_OCInitStructure;
	    TIM_BDTRInitTypeDef      TIM_BDTRInitStructure;

	    RCC_AHB1PeriphClockCmd(MOTOR_A_PORT_CLK[this->motor_] |MOTOR_B_PORT_CLK[this->motor_], ENABLE);
	    RCC_APB2PeriphClockCmd(MOTOR_TIM_CLK[this->motor_], ENABLE);
    		    /** init motor_ gpio **/
		GPIO_InitStructure.GPIO_Pin   = MOTOR_A_PIN[this->motor_];
		GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;							//复用功能
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;						//速度100MHz
		GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 							//推挽复用输出
		GPIO_Init(MOTOR_A_PORT[this->motor_], &GPIO_InitStructure);

		GPIO_InitStructure.GPIO_Pin = MOTOR_B_PIN[this->motor_];
		GPIO_Init(MOTOR_B_PORT[this->motor_], &GPIO_InitStructure);

		GPIO_PinAFConfig(MOTOR_A_PORT[this->motor_],MOTOR_A_PINSOU[this->motor_],MOTOR_AF_TIM[this->motor_]);  //GPIOA8复用为定时器1
		GPIO_PinAFConfig(MOTOR_B_PORT[this->motor_],MOTOR_B_PINSOU[this->motor_],MOTOR_AF_TIM[this->motor_]);  //GPIOA7复用为定时器1

		TIM_DeInit(MOTOR_TIM[this->motor_]);
		TIM_TimeBaseInitStructure.TIM_Period = arr_;      //arr 自动重装载值
		TIM_TimeBaseInitStructure.TIM_Prescaler = psc_;     //psc 定时器分频
		TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;    
		TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
		TIM_TimeBaseInitStructure.TIM_RepetitionCounter  = 0;
		TIM_TimeBaseInit(MOTOR_TIM[this->motor_], &TIM_TimeBaseInitStructure); 
		TIM_ARRPreloadConfig(MOTOR_TIM[this->motor_],ENABLE);

		TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                      //选择定时器模式:TIM脉冲宽度调制模式2
		TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;          //比较输出使能
		TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;       //互补输出允许 
		TIM_OCInitStructure.TIM_Pulse = 0;
		TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;              //High为占空比高极性,此时占空比为50%,Low则为反极性,占空比为50%
		TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;            //互补输出,与以上相反	
		TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;						 //
		TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;         //

		if(MOTOR_TIM[this->motor_] != STARBOT_MOTOR4_TIM)
		{                      
			TIM_OC1Init(MOTOR_TIM[this->motor_], &TIM_OCInitStructure);           
			TIM_OC1PreloadConfig(MOTOR_TIM[this->motor_],TIM_OCPreload_Enable);

			TIM_OC2Init(MOTOR_TIM[this->motor_], &TIM_OCInitStructure);
			TIM_OC2PreloadConfig(MOTOR_TIM[this->motor_],TIM_OCPreload_Enable);

			TIM_OC3Init(MOTOR_TIM[this->motor_], &TIM_OCInitStructure);
			TIM_OC3PreloadConfig(MOTOR_TIM[this->motor_],TIM_OCPreload_Enable);
		}
		else
		{
			TIM_OC3Init(MOTOR_TIM[this->motor_], &TIM_OCInitStructure);           
			TIM_OC3PreloadConfig(MOTOR_TIM[this->motor_],TIM_OCPreload_Enable);  
		}
//		TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
//		TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
//		TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
//		TIM_BDTRInitStructure.TIM_DeadTime = 0x90;
//		TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;               
//		TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
//		TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
//		TIM_BDTRConfig(MOTOR_TIM[this->motor_], &TIM_BDTRInitStructure);
		
		TIM_BDTRInitStructure.TIM_AutomaticOutput=TIM_AutomaticOutput_Enable;
		TIM_BDTRInitStructure.TIM_Break=TIM_Break_Disable;//TIM_Break_Enable;
		TIM_BDTRInitStructure.TIM_BreakPolarity=TIM_BreakPolarity_High;
		TIM_BDTRInitStructure.TIM_DeadTime=28;
		TIM_BDTRInitStructure.TIM_LOCKLevel=TIM_LOCKLevel_OFF;
		TIM_BDTRInitStructure.TIM_OSSIState=TIM_OSSIState_Disable;//TIM_OSSIState_Disable;//TIM_OSSIState_Enable;
		TIM_BDTRInitStructure.TIM_OSSRState=TIM_OSSRState_Disable;//TIM_OSSRState_Disable;//TIM_OSSRState_Enable;

		TIM_BDTRConfig(MOTOR_TIM[this->motor_],&TIM_BDTRInitStructure);
		TIM_ARRPreloadConfig(MOTOR_TIM[this->motor_], ENABLE);

		//TIM_CCPreloadControl(MOTOR_TIM[this->motor_],ENABLE);
		TIM_Cmd(MOTOR_TIM[this->motor_], ENABLE);
		TIM_CtrlPWMOutputs(MOTOR_TIM[this->motor_], ENABLE);
}
void Motor_spin(int pwm)
{
	if(this->motor == MOTOR4){
		if(pwm < 0){
			TIM_CCxCmd(MOTOR_TIM[this->motor], MOTOR_CHANNEL[this->motor], TIM_CCx_Enable); 
			TIM_CCxNCmd(MOTOR_TIM[this->motor], MOTOR_CHANNEL[this->motor], TIM_CCxN_Disable);
		}else if(pwm > 0) {
			TIM_CCxCmd(MOTOR_TIM[this->motor], MOTOR_CHANNEL[this->motor], TIM_CCx_Disable); 
			TIM_CCxNCmd(MOTOR_TIM[this->motor], MOTOR_CHANNEL[this->motor], TIM_CCxN_Enable);
		}
	}
	if((this->motor == MOTOR1) || (this->motor == MOTOR3) || (this->motor == MOTOR2)){
		if(pwm > 0){
			TIM_CCxCmd(MOTOR_TIM[this->motor], MOTOR_CHANNEL[this->motor], TIM_CCx_Enable); 
			TIM_CCxNCmd(MOTOR_TIM[this->motor], MOTOR_CHANNEL[this->motor], TIM_CCxN_Disable);
		}else if(pwm < 0) {
			TIM_CCxCmd(MOTOR_TIM[this->motor], MOTOR_CHANNEL[this->motor], TIM_CCx_Disable); 
			TIM_CCxNCmd(MOTOR_TIM[this->motor], MOTOR_CHANNEL[this->motor], TIM_CCxN_Enable);
		}
	}
	if(MOTOR_CHANNEL[this->motor] == TIM_Channel_1){
		TIM_SetCompare1(MOTOR_TIM[this->motor], abs(pwm));
	}
	if(MOTOR_CHANNEL[this->motor] == TIM_Channel_2){
		TIM_SetCompare2(MOTOR_TIM[this->motor], abs(pwm));
	}
	if(MOTOR_CHANNEL[this->motor] == TIM_Channel_3){
		TIM_SetCompare3(MOTOR_TIM[this->motor], abs(pwm));
	}
}

在主函数中调用MotorInit()和Motor_spin()即可完成电机的调速,例如给定500的PWM值,Motor_spin(500)

3、总结

电机的调速主要使用到STM32 PWM输出进行驱动电机驱动器,从而对电机进行调速,大概思路就是这样,如果你也在自己动手制作ROS机器人小车的话就扫描一下二维码进群把:

ROS机器人DIY教程之,STM32电机PWM控制_第6张图片

 

你可能感兴趣的:(STM32,ROS,stm32,电机控制,ROS,STM,PWM互补输出)