一:实现效果
DMA解算舵机
从下到上分别为舵机1,2,3,分别由函数Servo_SetAngle1(),Servo_SetAngle2(),Servo_SetAngle3()控制。
舵机1:偏航角Yaw:绕Z轴转动(机头水平转)
舵机2:横滚角Roll:绕X轴转动(飞机左右翻滚)
舵机3:俯仰角Pitch:绕Y轴转动(飞机上下抬头)
二:硬件介绍
1:MPU6050
/*
MPU6050的欧拉角范围可以按照以下方式清晰地表示和归纳:Pitch角(俯仰角):
绕Y轴旋转
范围:±90°
方向:与旋转方向相反转是增大。具体来说,抬头时Pitch角为正,低头时Pitch角为负。Roll角(横滚角):
绕X轴旋转
范围:±180°
方向:与旋转方向相反转是增大。具体来说,右滚时Roll角为正,左滚时Roll角为负。Yaw角(偏航角):
绕Z轴旋转
范围:±180°
方向:与旋转方向相反转是增大。具体来说,右偏时Yaw角为正,左偏时Yaw角为负。MPU6050通过其集成的三轴陀螺仪和三轴加速度计来测量这些角度。
这些角度数据对于理解物体的空间姿态和进行姿态控制非常关键。
在读取和使用这些数据时,需要特别注意它们的范围和方向性,以确保正确的数据处理和姿态控制。*/
2:舵机
高电平宽度=某电频的持续时间
CCR=高电频
舵机的控制一般需要一个20ms的时基脉冲(周期),该脉冲的高电平部分一般为0.5ms~2.5ms范围内的角度控制脉冲部分。以180度角度舵机为例,那么对应的控制关系是这样的:
0.5ms--------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;
二:软件部分
pwm
#include "stm32f1xx_hal.h"
#include <stdio.h>
#include <stdarg.h>
TIM_HandleTypeDef TIM_Handle;
void PWM2_Init(uint16_t psc,uint16_t arr)
{
TIM_Handle.Instance=TIM2;
TIM_Handle.Init.Prescaler=psc;
TIM_Handle.Init.CounterMode=TIM_COUNTERMODE_UP; //计数模式
TIM_Handle.Init.Period=arr;
TIM_Handle.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; //时钟分频值--不分频
TIM_Handle.Init.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_DISABLE;//自动重装载值
HAL_TIM_PWM_Init(&TIM_Handle);
TIM_OC_InitTypeDef TIM_OC_Init={0};
TIM_OC_Init.OCMode=TIM_OCMODE_PWM1; //模式 CNT<CCR输出有效值
TIM_OC_Init.Pulse=0; //CCR
TIM_OC_Init.OCPolarity=TIM_OCPOLARITY_HIGH; //输出极性(有效值)
HAL_TIM_PWM_ConfigChannel(&TIM_Handle,&TIM_OC_Init,TIM_CHANNEL_1);
HAL_TIM_PWM_ConfigChannel(&TIM_Handle,&TIM_OC_Init,TIM_CHANNEL_2);
HAL_TIM_PWM_ConfigChannel(&TIM_Handle,&TIM_OC_Init,TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&TIM_Handle,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&TIM_Handle,TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&TIM_Handle,TIM_CHANNEL_3);
}
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM2)
{
if(htim->Channel==TIM_CHANNEL_1)
{
//TIM2_CH1为PA0
//TIM2_CH2为PA1
//TIM2_CH3为PA2
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_TIM2_CLK_ENABLE();
GPIO_InitTypeDef GPIO_Init;
GPIO_Init.Mode=GPIO_MODE_AF_PP; /*复用推挽输出*/
GPIO_Init.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2;
GPIO_Init.Speed=GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_Init);
}
}
}
一个定时器可以开启多个,PWM的通道我们这里开启3个通道输出PWM。
在STM32F103C8T6中,定时器,它们各自拥有独立的通道和相应的捕获/比较寄存器(CCR)。关于TIM是否使用一个CCR的问题,可以明确地表示:
- 定时器独立性:TIM是独立的定时器,它们各自有自己的寄存器和功能设置。
- 通道与CCR的关系:对于通用定时器,如TIM2和TIM3,它们都具备多个通道(Channel),每个通道都对应一个捕获/比较寄存器(CCR)。例如,TIM2的通道1对应CCR1,TIM3的通道1对应CCR1,以此类推。
- 通道1的CCR使用情况:
- TIM2的通道1(TIM2_CH1)使用CCR1进行捕获或比较操作。
- TIM3的通道1(TIM3_CH1)也使用CCR1进行捕获或比较操作,但这是TIM3的CCR1,与TIM2的CCR1是独立的。
- 总结:TIM2的通道1和TIM3的通道1不是使用一个CCR。它们各自有自己的CCR,即TIM2_CCR1和TIM3_CCR1。
这样的设计允许每个定时器独立地配置和操作其通道,从而实现更灵活和多样的功能。在编写代码时,你需要根据具体需求分别配置TIM2和TIM3的通道及其对应的CCR。
舵机
#include "stm32f1xx_hal.h"
#include "PWM.h"
void Servo_Init()
{
PWM2_Init(72-1,20000); //T=(72*20000)/72000 000=0.02s=20ms
}
//Angle:舵机的角度 0~180
void Servo_SetAngle1(float Angle)
{
__HAL_TIM_SET_COMPARE(&TIM_Handle,TIM_CHANNEL_1,Angle / 180 * 2000 + 500);
}
void Servo_SetAngle2(float Angle)
{
__HAL_TIM_SET_COMPARE(&TIM_Handle,TIM_CHANNEL_2,Angle / 180 * 2000 + 500);
}
void Servo_SetAngle3(float Angle)
{
__HAL_TIM_SET_COMPARE(&TIM_Handle,TIM_CHANNEL_3,Angle / 180 * 2000 + 500);
}
__HAL_TIM_SET_COMPARE 读取CCR的值
主控程序
#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "delay.h"
#include "UART.h"
#include "OLED.h"
#include <stdio.h>
#include <stdarg.h>
#include "IIC.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
#include "mpu6050.h"
#include "steering_engine.h"
float Pitch,Roll,Yaw;
uint8_t display_buf[20];
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
OLED_Init();
Uart_Init(115200);
MPU_Init();
mpu_dmp_init();
Servo_Init();
printf("串口初始化成功\r\n");
while(1)
{
mpu_dmp_get_data(&Pitch,&Roll,&Yaw); //欧拉角
sprintf((char *)display_buf,"pitch:%.2f ",Pitch);
OLED_ShowString(1,2,display_buf);
sprintf((char *)display_buf,"roll:%.2f ",Roll);
OLED_ShowString(2,2,display_buf);
sprintf((char *)display_buf,"yaw:%.2f ",Yaw);
OLED_ShowString(3,2,display_buf);
//偏航角Yaw:绕Z轴转动(机头水平转)
//横滚角Roll:绕X轴转动 (飞机左右翻滚)
//俯仰角Pitch:绕Y轴转动(飞机上下抬头)
Servo_SetAngle1(Yaw+90); //偏航角Yaw:绕Z轴转动(机头水平转)
Servo_SetAngle2(Pitch+90); //横滚角Roll:绕X轴转动(飞机左右翻滚)
if(Pitch >= 0) //俯仰角Pitch:绕Y轴转动(飞机上下抬头)
{
Servo_SetAngle3(90-Pitch); //俯仰角Pitch:绕Y轴转动(飞机上下抬头)
}
else if(Pitch <0)
{
float a = abs(Pitch);
Servo_SetAngle3(a+90);
}
}
}
/*
MPU6050的欧拉角范围可以按照以下方式清晰地表示和归纳:
Pitch角(俯仰角):
绕Y轴旋转
范围:±90°
方向:与旋转方向相反转是增大。具体来说,抬头时Pitch角为正,低头时Pitch角为负。
Roll角(横滚角):
绕X轴旋转
范围:±180°
方向:与旋转方向相反转是增大。具体来说,右滚时Roll角为正,左滚时Roll角为负。
Yaw角(偏航角):
绕Z轴旋转
范围:±180°
方向:与旋转方向相反转是增大。具体来说,右偏时Yaw角为正,左偏时Yaw角为负。
MPU6050通过其集成的三轴陀螺仪和三轴加速度计来测量这些角度。
这些角度数据对于理解物体的空间姿态和进行姿态控制非常关键。
在读取和使用这些数据时,需要特别注意它们的范围和方向性,以确保正确的数据处理和姿态控制。
*/