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

7 篇文章 1 订阅

简介:

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

1、实现的工具

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

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

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

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

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机器人小车的话就扫描一下二维码进群把:

 

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ROS机器人操作系统)是一款成熟的机器人操作系统,具有完备的生态体系,未来的发展意义可以成为机器人届中的”Linux、Android“。机器人的开发学习要综合软硬件的协同开发,硬件开发有些部分倾向于底层的设计和使用。软件开发可以依托C++、PYTHON等高级语言进行ROS接口应用开发,或者兼容ROS系统。本系列的ROS开发课程包含下位机开发、上位机开发、基于MBD(基于模型设计的开发)等。下位机作为机器人设计的基础部分是学习机器人操作系统必经之路,下位机我们通常会选择Arduino(适合学习不适合工程,代码执行效率差)、STM32系列产品(工程应用广泛,适合学习和工程开发,代码针对性强),当然还有NXP系列、51系列、TI DSP等,后期可以根据产品的性能和成本要求去考虑;上位机部分,主要是基于工控机、树莓派Raspberry、英伟达Jetson等可以运行操作系统的嵌入式设备再基于ROS操作系统进行实训学习。网络上对于ROS类的教学比较多,但是系统化从底层向高阶层层递升的教学方法偏少,知识碎片化严重,对机器人开发工程师深远的发展有负面影响,基于此本人通过多年自身的学习和工程实践,将机器人开发课程系统化、具象化、模块化地引导式学习,每节课程都有相应的课件和代码引导。对致力于机器人事业的学生有推动作用,且增强信心,系统化自己的机器人知识。为自己的职业规划和事业发展奠定坚实基础。最后,你们的支持,就是老师不断创作的动力!老师会不断更新机器人类相关知识,希望”与子同裳“。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值