使用江科大代码实现姿态解算

之前跟人做了一个平衡车,但是是使用的HAL库,我一开始学习使用的是标准库,跟着江科大学习的。所以,我一直准备用标准库实现一次,这几天学习了MPU6050的姿态解算,学习了一下四元数,欧拉角。

我的理解就是,使用欧拉角进行计算时,会出现多解。

A` = 旋转矩阵*A,进行公示求解时,

当出现90度时,cos90 = 0

所以旋转矩阵会退化,只要第二次出现90度时,只要a - y 的值定了,那么任何角都是一样的,所以会出现 【30 90  60】和【40 90 70】是一样的。

所以,引入四元数

q = q0 + q1i +q2j +a3k, 具体公式网上都有的,我们这里主要使用

后面就是一系列计算,算出欧拉角了

附上我的代码

江科大的I2C我只修改了引脚,和启用PB3和PB4的i/o功能

void MyI2C_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //JTAG-DP 禁用 + SW-DP 使能。只将PA15 ,PB3 ,PB4变成普通IO口。
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStructure);//默认是低电平
	
	GPIO_SetBits(GPIOB,GPIO_Pin_4|GPIO_Pin_3);
	
}
#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "MPU6050_Reg.h"

#define MPU6050_ADDRESS 0xD0


uint8_t FLAG;




/**
  * 函    数:MPU6050初始化
  * 参    数:无
  * 返 回 值:无
  */
void MPU6050_Init(void)
{
	MyI2C_Init();
	MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);
	MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);
	MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x04);     //采样率分频寄存器,配置采样率 1000/(4+1) =  100
	MPU6050_WriteReg(MPU6050_CONFIG,0x06);         //配置寄存器,配置DLPF 设置数字低通滤波器(DLPF)
	MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x00);   //陀螺仪配置寄存器,选择满量程为±250°/s
	MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x00);  //加速度计配置寄存器,选择满量程为±2g
	
	// 配置中断为低电平有效
    MPU6050_WriteReg(MPU6050_INT_PIN_CFG, 0x80);   // INT 低电平有效,推挽输出
    MPU6050_WriteReg(MPU6050_INT_ENABLE, 0x01);    // 启用 Data Ready 中断
	
	//配置外部中断(INT引脚触发)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
	GPIO_InitTypeDef GPIO_InitTypeStrcutrue;
	GPIO_InitTypeStrcutrue.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitTypeStrcutrue.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitTypeStrcutrue.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitTypeStrcutrue);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5);
	EXTI_InitTypeDef EXTI_InitTypeStruct;
	EXTI_InitTypeStruct.EXTI_Line = EXTI_Line5;
	EXTI_InitTypeStruct.EXTI_LineCmd = ENABLE;
	EXTI_InitTypeStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitTypeStruct.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitTypeStruct);
	
	//配置NVIC
	NVIC_InitTypeDef NVIC_InitTypeStrcut;
	NVIC_InitTypeStrcut.NVIC_IRQChannel = EXTI9_5_IRQn;
	NVIC_InitTypeStrcut.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitTypeStrcut.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitTypeStrcut.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitTypeStrcut);
	
}

uint8_t MPU_GetFlag(void)
{
	if(FLAG == 1)
	{
		FLAG = 0;
		return 1;
	}
	return 0;
	
}

//中断函数
void EXTI9_5_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line5) != RESET)
	{
		//进行PID
		
		 FLAG =  1;
		// 清除中断标志位
		EXTI_ClearITPendingBit(EXTI_Line5);
	}
	
}



#include "stm32f10x.h"
#include "MPU6050.h"
#include "math.h"

#define RtA (57.2957795f)  // 弧度转角度,180/π ≈ 57.2957795
#define Ki  0.005f         // 积分系数
#define DT  0.005f          // 计算周期的一半,单位s

// 加速度和角速度
int16_t AX, AY, AZ, GX, GY, GZ;

typedef struct {
    float c1, c2, c3, a1, a2, a3, a;
} Degree;

Degree d;

typedef struct {
    float q0, q1, q2, q3;
    float exInt, eyInt, ezInt;
} Quater;

Quater q = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};

void Dmp_Init(void) {
    MPU6050_Init();
}

void MPU6050_Read(void) {
    MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);
    
    // 转换为物理量
    d.c1 = GX / 131.0f;  // 角速度(°/s)
    d.c2 = GY / 131.0f;
    d.c3 = GZ / 131.0f;
    
    // 转换为rad/s
    d.c1 /= RtA;
    d.c2 /= RtA;
    d.c3 /= RtA;
    
    d.a1 = AX / 16384.0f;  // 加速度(g)
    d.a2 = AY / 16384.0f;
    d.a3 = AZ / 16384.0f;
    
    // 加速度归一化
    float norm = sqrtf(d.a1 * d.a1 + d.a2 * d.a2 + d.a3 * d.a3);
    if (norm > 1e-6f) {  // 防止除零
        float inv_norm = 1.0f / norm;
        d.a1 *= inv_norm;
        d.a2 *= inv_norm;
        d.a3 *= inv_norm;
        d.a = 1.0f;
    } else {
        d.a = 0.0f;
    }
}

void ComputeEulerAngles(float *pitch, float *roll, float *yaw) {
    MPU6050_Read();
    
    // 计算姿态误差
    float gx = d.c1, gy = d.c2, gz = d.c3;
    float gravity_x = 2.0f * (q.q1 * q.q3 - q.q0 * q.q2);
    float gravity_y = 2.0f * (q.q0 * q.q1 + q.q2 * q.q3);
    float gravity_z = q.q0*q.q0 - q.q1 * q.q1 - q.q2 * q.q2 + q.q3*q.q3;
    
    float error_x = d.a2 * gravity_z - d.a3 * gravity_y;
    float error_y = d.a3 * gravity_x - d.a1 * gravity_z;
    float error_z = d.a1 * gravity_y - d.a2 * gravity_x;
    
    // 更新四元数
    float Kp = 0.5f;
    
    // 误差积分
    q.exInt += Ki * error_x ;
    q.eyInt += Ki * error_y ;
    q.ezInt += Ki * error_z ;
    
    // 修正角速度
    gx += Kp * error_x + q.exInt;
    gy += Kp * error_y + q.eyInt;
    gz += Kp * error_z + q.ezInt;
    
    // 四元数微分方程
    float q0_dot = (-q.q1 * gx - q.q2 * gy - q.q3 * gz) * DT; 
    float q1_dot = (q.q0 * gx - q.q3 * gy + q.q2 * gz) * DT;
    float q2_dot = (q.q3 * gx + q.q0 * gy - q.q1 * gz) * DT;
    float q3_dot = (-q.q2 * gx + q.q1 * gy + q.q0 * gz) * DT;
    
    // 更新四元数
    q.q0 += q0_dot;
    q.q1 += q1_dot;
    q.q2 += q2_dot;
    q.q3 += q3_dot;
    
    // 归一化
    float norm = sqrtf(q.q0 * q.q0 + q.q1 * q.q1 + q.q2 * q.q2 + q.q3 * q.q3);
    if (norm > 1e-6f) {
        float inv_norm = 1.0f / norm;
        q.q0 *= inv_norm;
        q.q1 *= inv_norm;
        q.q2 *= inv_norm;
        q.q3 *= inv_norm;
    }
    
    // 计算欧拉角
    float q0q0 = q.q0 * q.q0;
    float q1q1 = q.q1 * q.q1;
    float q2q2 = q.q2 * q.q2;
    float q3q3 = q.q3 * q.q3;
    
    *roll = atan2f(2.0f * (q.q2 * q.q3 + q.q0 * q.q1), q0q0 - q1q1 - q2q2 + q3q3);
    *pitch = asinf(-2.0f * (q.q1 * q.q3 - q.q0 * q.q2));
    *yaw = atan2f(2.0f * (q.q1 * q.q2 + q.q0 * q.q3), q0q0 + q1q1 - q2q2 - q3q3);
    
//    // 转换为度
//    *roll *= RtA;
//    *pitch *= RtA;
//    *yaw *= RtA;
}

如果想更好的理解我建议看一下这个视频     视频连接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值