STM32F407VET6控制MG996R 180度舵机
电赛之前想做一下板球控制系统,就先驱动一下舵机。
180与360度舵机
360度舵机与一般舵机的区别是:给一般舵机一个PWM信号,舵机会转到一个特定角度,而给360度舵机一个PWM信号,舵机会以一个特定的速度转动,类似与电机。但与电机不同的是,360舵机是闭环控制,速度控制稳定。 PWM 信号与360舵机转速的关系:
0.5ms----------------正向最大转速;
1.5ms----------------速度为0;
2.5ms----------------反向最大转速;
180度舵机为例: 0.5ms-------2.5%---------0度;
1ms ----------5%-------45度;
1.5ms--------7.5%--------90度;
2ms ----------10%-------135度;
2.5ms --------12.5-------180度;
180度舵机
如上,180度的舵机,角度值与占空比是一一对应的,不管你现在是多少角度,只要是一个给定的占空比,就会到达相应的角度。 以F407驱动,168MHz,TIM2~TIM7的时钟为84M, 舵机需要的周期为20ms,所以 psc = 84-1 = 83; arr = 20000-1 = 19999; 这样就是 20000 * 84 / 84000000 = 0.02s = 20ms
使用的舵机为MG996R, ? 速度:4.8V@ 0.12±0.01sec/60°——6.0V@ 0.11±0.01sec/60° ? 扭力:4.8V@ 11kg-cm——6.0V@ 13kg-cm ? 电压:4.8V-6V ? 空载工作电流:220±20mA ? 堵转工作电流:2000±30mA ? 响应脉宽时间 ff5usec ? 角度偏差:回中差 ff1°,左右各 45° 误差 ff3°。 使用下面的共射极放大电路提供5V(4.8V到6V)的PWM控制舵机 由于共射极放大电路的反向功能,所以需要将占空比的值反过来,32输出的是5%占空比的方波,那么共射极输出的方波占空比就是95%
所以 0.5ms-------2.5%---------0度;40000-1000 = 39000;
1ms ----------5%-------45度;40000-2000 = 38000;
1.5ms--------7.5%--------90度;40000-3000 = 37000;
2ms ----------10%-------135度;40000-4000 = 36000;
2.5ms --------12.5%-------180度;40000-5000 = 35000;
CUBEMX配置生成代码(有部分TIM2定时器的配置)
#include "tim.h"
TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;
void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 16799;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 4999;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_Base_Start_IT(&htim2);
}
void MX_TIM3_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
htim3.Instance = TIM3;
htim3.Init.Prescaler = 41;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 39999;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 1000;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
HAL_TIM_MspPostInit(&htim3);
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM2)
{
__HAL_RCC_TIM2_CLK_ENABLE();
HAL_NVIC_SetPriority(TIM2_IRQn, 1, 2);
HAL_NVIC_EnableIRQ(TIM2_IRQn);
}
else if(tim_baseHandle->Instance==TIM3)
{
__HAL_RCC_TIM3_CLK_ENABLE();
}
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM3)
{
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
}
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM2)
{
__HAL_RCC_TIM2_CLK_DISABLE();
HAL_NVIC_DisableIRQ(TIM2_IRQn);
}
else if(tim_baseHandle->Instance==TIM3)
{
__HAL_RCC_TIM3_CLK_DISABLE();
}
}
void TIM3_CH1_PWM_SetPulse(u16 cmp)
{
__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1,cmp);
}
void Servo_ANGLE(float angle)
{
float temp = 0;
if(angle > 180)
angle = 180;
temp = (angle / 180) * Servo_Period + Servo_Static;
TIM3_CH1_PWM_SetPulse(Servo_Duty - temp);
}
void set_steering_gear_dutyfactor(u16 dutyfactor)
{
dutyfactor = 2.5/20*PWM_PERIOD_COUNT < dutyfactor ? 2.5/20*PWM_PERIOD_COUNT : dutyfactor;
dutyfactor = 0.5/20*PWM_PERIOD_COUNT > dutyfactor ? dutyfactor : 0.5/20*PWM_PERIOD_COUNT;
TIM3_CH1_PWM_SetPulse(PWM_PERIOD_COUNT - dutyfactor);
}
void set_steering_gear_angle(u16 angle_temp)
{
angle_temp = (0.5 + angle_temp / 180.0 * (2.5 - 0.5)) / 20.0 * PWM_PERIOD_COUNT;
set_steering_gear_dutyfactor(angle_temp);
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
}
}
封装舵机旋转角度函数
法1
(错误代码)
void Servo_ANGLE(u8 angle)
{
u16 temp = 0;
if(angle > 180)
angle = 180;
temp = (angle / 180) * Servo_Period + Servo_Static;
TIM3_CH1_PWM_SetPulse(Servo_Duty - temp);
}
发现只有180度才是正常的,其他的都是2.5的占空比,也就是angle是0的时候对应的值,把各个值printf一遍才发现,是C语言基础知识不牢啊。angel只要设定的是<180度,那么一个小于180的数除以180一定是0啊。所以这样是错误的。
那么修改(改为float类型的变量):
void Servo_ANGLE(float angle)
{
float temp = 0;
if(angle > 180)
angle = 180;
temp = (angle / 180) * Servo_Period + Servo_Static;
TIM3_CH1_PWM_SetPulse(Servo_Duty - temp);
}
法2
void set_steering_gear_dutyfactor(u16 dutyfactor)
{
dutyfactor = 2.5/20*PWM_PERIOD_COUNT < dutyfactor ? 2.5/20*PWM_PERIOD_COUNT : dutyfactor;
dutyfactor = 0.5/20*PWM_PERIOD_COUNT > dutyfactor ? dutyfactor : 0.5/20*PWM_PERIOD_COUNT;
TIM3_CH1_PWM_SetPulse(PWM_PERIOD_COUNT - dutyfactor);
}
void set_steering_gear_angle(u16 angle_temp)
{
angle_temp = (0.5 + angle_temp / 180.0 * (2.5 - 0.5)) / 20.0 * PWM_PERIOD_COUNT;
set_steering_gear_dutyfactor(angle_temp);
}
|