找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1|回复: 0
收起左侧

小白MPU6050求助!求指点,到底是哪出问题了

[复制链接]
ID:1145832 发表于 2026-5-1 20:43 | 显示全部楼层 |阅读模式
利用正点原子旧版的MPU6050程序做了一个扫频程序,想要得到PWM与姿态角的关系,但是角度出来问题很大,直接从30度内跑到100+,后面有附带情况,附件的图片读取格式是PWM偏移量-角度信息-角速度信息,现在已经知道的是MPU6050直接运行例程是没有问题的,非常灵敏。但是想办法加入控制舵机并且读取姿态角就出问题,试过很多办法了,修改IIC速率减少影响,提高主程序到100Hz匹配DMP速率,但是都会出现这种情况。下面是我的程序,请大佬们过目!#include "led.h"#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "mpu6050.h"
#include "usmart.h"   
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
#include "pwm.h"
#include <math.h>

/* ========== 通道选择 ========== */
//#define SWEEP_CHANNEL_PITCH
#define SWEEP_CHANNEL_ROLL

/* 各通道中位值 */
#define PITCH_CENTER   160
#define ROLL_CENTER    150

/* 舵机有效范围 */
#define SERVO_MIN  50
#define SERVO_MAX  250

/* 扫频参数 */
#define SWEEP_TOTAL      45.0f
#define SWEEP_F_START    0.1f
#define SWEEP_F_END      1.0f
#define SWEEP_AMPLITUDE  40.0f
#define SAMPLE_PERIOD_MS 50

/* 系统延时对齐参数 */
#define SYSTEM_DELAY_MS   100
#define DELAY_BUF_LEN     20
#define DELAY_STEPS       (SYSTEM_DELAY_MS / SAMPLE_PERIOD_MS)

/* ★ 陀螺仪量程换算 ★ */
// 正点原子默认 MPU_Set_Gyro_Fsr(3) → ±2000°/s → 灵敏度 16.4 LSB/(°/s)
#define GYRO_SCALE 16.4f

int main(void)
{         
    u8 t = 0;
    float pitch, roll, yaw;
    short aacx, aacy, aacz;
    short gyrox, gyroy, gyroz;
    short temp;

    /* 扫频专用变量 */
    float t_sweep = 0.0f;
    float dt = SAMPLE_PERIOD_MS / 1000.0f;
    float phase = 0.0f;
    float f_current;
    float sweep_ratio;
    float sin_val;
    u16 pwm_pitch, pwm_roll;
    int32_t signed_offset, pwm;

    /* 延时对齐缓存 */
    int pwm_buf[DELAY_BUF_LEN];
    int buf_index = 0;
    int aligned_pwm;
    int delayed_index;
    int i;

    /* 输出变量 */
    int pwm_offset;
    float output_angle;
    float output_rate;   // ★ 新增:输出角速度

    /* LCD背光 GPIO 初始化结构体 */
    GPIO_InitTypeDef GPIO_InitStructure;

    /* ---------- 初始化 PWM 延时缓存 ---------- */
    for(i = 0; i < DELAY_BUF_LEN; i++) {
        pwm_buf = 0;
    }

    /* ---------- 系统初始化 ---------- */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    uart_init(500000);
    delay_init();
    usmart_dev.init(72);
    LED_Init();
    KEY_Init();
    LCD_Init();
    MPU_Init();

    MPU_Set_Gyro_Fsr(3);   // 强制陀螺仪量程为 ±2000°/s, 与 GYRO_SCALE 一致

    /* PWM初始化(50Hz) */
    TIM3_PWM_Init(1999, 719);
    TIM_SetCompare1(TIM3, ROLL_CENTER);
    TIM_SetCompare2(TIM3, PITCH_CENTER);
    TIM_SetCompare4(TIM3, 150);

    /* LCD背光修复 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_SetBits(GPIOB, GPIO_Pin_0);

    /* LCD 显示 */
    POINT_COLOR = RED;
    LCD_ShowString(30,50,200,16,16,"ELITE STM32");      
    LCD_ShowString(30,70,200,16,16,"MPU6050 SWEEP");      
    LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
    LCD_ShowString(30,110,200,16,16,"2026/4/28");

    /* DMP初始化 */
    while(mpu_dmp_init())
    {
        LCD_ShowString(30,130,200,16,16,"MPU6050 Error");
        delay_ms(200);
        LCD_Fill(30,130,239,130+16,WHITE);
        delay_ms(200);
    }  
    LCD_ShowString(30,130,200,16,16,"MPU6050 OK");

#ifdef SWEEP_CHANNEL_PITCH
    LCD_ShowString(30,150,200,16,16,"Pitch Sweep");
#elif defined(SWEEP_CHANNEL_ROLL)
    LCD_ShowString(30,150,200,16,16,"Roll Sweep");
#endif

    POINT_COLOR = BLUE;
    LCD_ShowString(30,170,200,16,16,"Sweeping...    ");         
    LCD_ShowString(30,200,200,16,16," Temp:    . C");      
    LCD_ShowString(30,220,200,16,16,"Pitch:    . C");      
    LCD_ShowString(30,240,200,16,16," Roll:    . C");         
    LCD_ShowString(30,260,200,16,16," Yaw :    . C");         

    delay_ms(1000);

    /* ---------- 主循环:相位连续扫频 ---------- */
    while(1)
    {
        /* 1. 固定非激活通道 */
#ifdef SWEEP_CHANNEL_PITCH
        TIM_SetCompare1(TIM3, ROLL_CENTER);
        TIM_SetCompare4(TIM3, 150);
#elif defined(SWEEP_CHANNEL_ROLL)
        TIM_SetCompare2(TIM3, PITCH_CENTER);
        TIM_SetCompare4(TIM3, 150);
#endif

        /* 2. 计算当前频率 */
        sweep_ratio = t_sweep / SWEEP_TOTAL;
        if(sweep_ratio > 1.0f) sweep_ratio = 1.0f;
        f_current = SWEEP_F_START + (SWEEP_F_END - SWEEP_F_START) * sweep_ratio;

        /* 3. 相位连续的chirp信号 */
        phase += 2.0f * 3.1415926f * f_current * dt;
        sin_val = sinf(phase);
        signed_offset = (int32_t)(SWEEP_AMPLITUDE * sin_val);

        /* 4. PWM输出 */
#ifdef SWEEP_CHANNEL_PITCH
        pwm = PITCH_CENTER + signed_offset;
        if(pwm < SERVO_MIN) pwm = SERVO_MIN;
        if(pwm > SERVO_MAX) pwm = SERVO_MAX;
        TIM_SetCompare2(TIM3, (u16)pwm);
#elif defined(SWEEP_CHANNEL_ROLL)
        pwm = ROLL_CENTER + signed_offset;
        if(pwm < SERVO_MIN) pwm = SERVO_MIN;
        if(pwm > SERVO_MAX) pwm = SERVO_MAX;
        TIM_SetCompare1(TIM3, (u16)pwm);
#endif

        /* 5. 存入PWM缓存(环形缓冲区) */
        pwm_buf[buf_index] = (int)signed_offset;

        /* 6. 获取延时对齐后的PWM偏移量 */
        delayed_index = buf_index - DELAY_STEPS;
        if(delayed_index < 0) delayed_index += DELAY_BUF_LEN;
        aligned_pwm = pwm_buf[delayed_index];

        buf_index++;
        if(buf_index >= DELAY_BUF_LEN) buf_index = 0;

        /* 7. 读取IMU并输出对齐后的数据(包含角速度) */
        if(mpu_dmp_get_data(&pitch, &roll, &yaw) == 0)
        {
            temp = MPU_Get_Temperature();
            MPU_Get_Accelerometer(&aacx, &aacy, &aacz);
            MPU_Get_Gyroscope(&gyrox, &gyroy, &gyroz);

            // 根据实际轴映射,Pitch 用 gyro_y,Roll 用 gyro_x
#ifdef SWEEP_CHANNEL_PITCH
            output_angle = pitch;
            output_rate  = gyroy / GYRO_SCALE;   // 对应 Pitch 轴角速度
#elif defined(SWEEP_CHANNEL_ROLL)
            output_angle = roll;
            output_rate  = gyrox / GYRO_SCALE;   // 对应 Roll 轴角速度
#endif

            /* ? 核心输出:对齐后的 PWM偏移, 角度, 角速度 */
            printf("%d, %.4f, %.2f\r\n", aligned_pwm, output_angle, output_rate);

            /* LCD 刷新(每10次循环一次) */
            if((t % 10) == 0)
            {
                if(temp < 0) { LCD_ShowChar(30+48,200,'-',16,0); temp = -temp; }
                else LCD_ShowChar(30+48,200,' ',16,0);
                LCD_ShowNum(30+48+8,200,temp/100,3,16);
                LCD_ShowNum(30+48+40,200,temp%10,1,16);

                if(pitch < 0) { LCD_ShowChar(30+48,220,'-',16,0); pitch = -pitch; }
                else LCD_ShowChar(30+48,220,' ',16,0);
                LCD_ShowNum(30+48+8,220,(int)(pitch*10)/10,3,16);
                LCD_ShowNum(30+48+40,220,(int)(pitch*10)%10,1,16);

                if(roll < 0) { LCD_ShowChar(30+48,240,'-',16,0); roll = -roll; }
                else LCD_ShowChar(30+48,240,' ',16,0);
                LCD_ShowNum(30+48+8,240,(int)(roll*10)/10,3,16);
                LCD_ShowNum(30+48+40,240,(int)(roll*10)%10,1,16);

                if(yaw < 0) { LCD_ShowChar(30+48,260,'-',16,0); yaw = -yaw; }
                else LCD_ShowChar(30+48,260,' ',16,0);
                LCD_ShowNum(30+48+8,260,(int)(yaw*10)/10,3,16);
                LCD_ShowNum(30+48+40,260,(int)(yaw*10)%10,1,16);

                t = 0;
                LED0 = !LED0;
            }
        }
        t++;

        delay_ms(SAMPLE_PERIOD_MS);
        t_sweep += dt;

        /* 扫频结束,舵机归中 */
        if(t_sweep >= SWEEP_TOTAL)
        {
#ifdef SWEEP_CHANNEL_PITCH
            TIM_SetCompare2(TIM3, PITCH_CENTER);
#elif defined(SWEEP_CHANNEL_ROLL)
            TIM_SetCompare1(TIM3, ROLL_CENTER);
#endif
            LCD_ShowString(30,170,200,16,16,"Sweep Finished!");
            while(1) { LED0 = !LED0; delay_ms(200); }
        }
    }        
}
90CF34F9C4BF223B0E9DE8CAAAADBF73.png
AF1E4A097B731E8874CA16F68938AEF4.png
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表