搜索
bottom↓
回复: 48

stm32F4-discovery + mpu6050 + hmc5883l + freeRTOS实现姿态解算

  [复制链接]

出0入0汤圆

发表于 2014-7-22 08:48:40 | 显示全部楼层 |阅读模式
本帖最后由 6091820503 于 2014-7-22 21:36 编辑

最近在看飞控的代码,尝试自己拿stm32f4实现姿态解算,移植了FreeRTOS操作系统,便于多任务的管理。
gyro accel更新频率1Khz,mag更新频率50Hz

//hmc885l任务
  1. void hmc5883Task()
  2. {
  3.         portTickType xLastWakeTime = xTaskGetTickCount();
  4.         uint8_t buf[6] = {0};
  5.         uint8_t ID[3] = {0};
  6.         float yaw = 0.0f;
  7.         int16_t magX, magY, magZ;
  8.         //延时100ms为了让mpu6050先初始化,不然mpu6050不好使
  9.         vTaskDelayUntil( &xLastWakeTime, ( 100 / portTICK_RATE_MS ) );
  10.         printf("hmc5883 initialising...\r\n");
  11.         I2C_init();
  12.         delay(2000);
  13.         //important!!! I2C can visit HMC5883 only when mpu6050 works in bypass mode
  14.         setI2CBypassEnabled(true);
  15.         printf("%s %d\r\n", __FILE__, __LINE__);
  16.         vTaskDelayUntil( &xLastWakeTime, ( 10 / portTICK_RATE_MS ) );
  17.         printf("%s %d\r\n", __FILE__, __LINE__);
  18.         HMC5883L_init();
  19.         printf("%s %d\r\n", __FILE__, __LINE__);
  20.         vTaskDelayUntil( &xLastWakeTime, ( 10 / portTICK_RATE_MS ) );
  21.         printf("%s %d\r\n", __FILE__, __LINE__);
  22.         ID[0] = getIDA();
  23.         ID[1] = getIDB();
  24.         ID[2] = getIDC();
  25.         printf("ID: %c %c %c\r\n", ID[0], ID[1], ID[2]);
  26.         printf("%s %d\r\n", __FILE__, __LINE__);
  27.         while(1)
  28.         {
  29.                 //HMC5883 内部寄存器地址会自增
  30.                 //HMC5883L_init();
  31.                 read_HMC5883L_reg_multi(HMC5883L_DATA_X_MSB_REG, buf, 6);
  32.                 magX = ((int16_t)buf[0] << 8) +  buf[1];
  33.                 magZ = ((int16_t)buf[2] << 8) +  buf[3];
  34.                 magY = ((int16_t)buf[4] << 8) +  buf[5];
  35.                
  36.                 mag[0] = magX*hmc5883l_scale[0];
  37.                 mag[1] = magY*hmc5883l_scale[1];
  38.                 mag[2] = magZ*hmc5883l_scale[2];
  39.                
  40.                 //yaw = atan2(-mag[1], mag[0])*RAD2DEG;
  41.                 //printf("mag: %f  %f  %f  %f\r\n", mag[0], mag[1], mag[2], yaw);
  42.                 //hmc5883L最大读取频率75Hz
  43.                 vTaskDelayUntil( &xLastWakeTime, ( 20 / portTICK_RATE_MS ) );
  44.         }       
  45. }
复制代码


//mpu6050任务
  1. void mpu6050Task(){
  2.        
  3.         portTickType xLastWakeTime = xTaskGetTickCount();
  4.         uint8_t res;
  5.         uint32_t count = 0;
  6.         float q[4] = {0.0f};
  7.         float rpy[3] = {0.0f};
  8.         bool first_loop = true;
  9.         float theta = 0.0f;
  10.         //delay(2000000);
  11.         //不要使用delay函数,使用vTaskDelayUntil避免浪费时间
  12.         vTaskDelayUntil( &xLastWakeTime, ( 10 / portTICK_RATE_MS ) );
  13.        
  14.         printf("mpu6050 initialising...\r\n");
  15.         I2C_init();
  16.         //important!!! I2C can visit HMC5883 only when mpu6050 works in bypass mode
  17.         //setI2CBypassEnabled(false);
  18.        
  19.         //delay(2000000);
  20.         vTaskDelayUntil( &xLastWakeTime, ( 10 / portTICK_RATE_MS ) );
  21.         setup_mpu6050();

  22.         printf("hello world, ready to blink\r\n");
  23.         res = read_mpu6050_reg(MPU6050_REG_WHOAMI);
  24.         printf("MPU6050: whoami:  %hhd", res);
  25.         res = read_mpu6050_reg(MPU6050_REG_PWR_MGMT_1);
  26.         printf("MPU6050: pwr_mgmt_1:  %hhd", res);
  27.        
  28.   while (1)
  29.   {
  30.     uint8_t buf[14];
  31.         //printf("read Sensor\r\n");
  32.     read_mpu6050_reg_multi(MPU6050_REG_ACCEL_XOUT_H, buf, 14);
  33.        
  34.         mpu6050_regs_to_float(buf, gyro, accel);

  35.           
  36.         count++;
  37.        
  38.           //gyro前几帧数据有读错的现象,进而导致标定不准,积分就更不准了
  39.         if(count < 100)
  40.         {
  41.                 //丢掉前100帧的数据,因为发现前面几帧数据非常不准
  42.         }else if(count < 200)
  43.         {
  44.                 //calibration
  45.                 gyro_bias[0]  += gyro[0];
  46.                 gyro_bias[1]  += gyro[1];
  47.                 gyro_bias[2]  += gyro[2];
  48.                 printf("gyro_0: %f %f %f\r\n", gyro[0], gyro[1], gyro[2]);
  49.                 printf("accel: %f %f %f\r\n", accel[0], accel[1], accel[2]);
  50.                 //printf("%d ", count);
  51.         }else if(count == 200)
  52.         {
  53.                 gyro_bias[0] /= 100.0f;
  54.                 gyro_bias[1] /= 100.0f;
  55.                 gyro_bias[2] /= 100.0f;
  56.                 printf("gyro_bias: %f %f %f\r\n", gyro_bias[0], gyro_bias[1], gyro_bias[2]);
  57.         }else
  58.         {
  59.                 //printf("gyro*: %f %f %f\r\n", gyro[0], gyro[1], gyro[2]);
  60.                 gyro[0] -= gyro_bias[0];
  61.                 gyro[1] -= gyro_bias[1];
  62.                 gyro[2] -= gyro_bias[2];
  63.                 //printf("gyro : %f %f %f\r\n", gyro[0], gyro[1], gyro[2]);
  64.                 //MadgwickAHRSupdateIMU(gyro[0], gyro[1], gyro[2], accel[0], accel[1], accel[2]);
  65.                 //第一次更新姿态,需要对姿态进行初始化
  66.                 if(first_loop)
  67.                 {
  68.                         theta = atan2f(accel[0], -accel[2]);
  69.                         rpy[1] = theta * RAD2DEG;
  70.                         rpy[0] = atan2f(-accel[1], -accel[2] / cosf(theta)) * RAD2DEG;
  71.                         rpy[2] = atan2f(-mag[1], mag[0]) * RAD2DEG;
  72.                         RPY2Quaternion(rpy, q);//初始化q
  73.                         q0 = q[0];
  74.                         q1 = q[1];
  75.                         q2 = q[2];
  76.                         q3 = q[3];
  77.                         first_loop = false;
  78.                 }
  79.                
  80.                
  81.                 MadgwickAHRSupdate(gyro[0], gyro[1], gyro[2], accel[0], accel[1], accel[2], mag[0], mag[1], mag[2]);
  82.                 q[0] = q0;
  83.                 q[1] = q1;
  84.                 q[2] = q2;
  85.                 q[3] = q3;
  86.                 //printf("q: %f %f %f %f\r\n", q0, q1, q2,q3);
  87.                
  88.                 Quaternion2RPY(q, rpy);
  89.                 //printf("rpy: %f %f %f\r\n", rpy[0], rpy[1], rpy[1]);
  90.         }
  91.         //由于目前串口是阻塞发送,发送频率太高时,系统很容易阻塞
  92.         if(count%50 == 0)
  93.         {
  94.                 //printf("rpy: %f %f %f\r\n", rpy[0], rpy[1], rpy[1]);
  95.                 print_rpy_float(rpy);
  96.                
  97.                 //print_motion_float(gyro, accel, accel);
  98.                 //print_motion((int16_t*)&buf[0], (int16_t*)&buf[8], (int16_t*)&buf[8]);
  99.                 //printf("count: %d\r\n", count);
  100.                 //printf("q: %f %f %f %f\r\n", q0, q1, q2,q3);
  101.                 //printf("rpy: %f %f %f\r\n", rpy[0], rpy[1], rpy[1]);
  102.         }
  103.        
  104.         vTaskDelayUntil( &xLastWakeTime, ( 1 / portTICK_RATE_MS ) );
  105.        
  106.   }
  107. }
复制代码


//main函数中只需启动各个任务即可
  1. int main(void){
  2.        
  3.         SystemInit();
  4.         button_init();
  5.        
  6.         xTaskCreate( LEDTask,  "LED", configMINIMAL_STACK_SIZE,
  7.     NULL, mainTIME_TASK_PRIORITY, &hTimeTask );
  8.        
  9. //        xTaskCreate( ButtonTask,  "button", configMINIMAL_STACK_SIZE,
  10. //    NULL, mainTIME_TASK_PRIORITY, &hTimeTask );
  11.        
  12.         xTaskCreate( debugConsoleTask,  "console", configMINIMAL_STACK_SIZE,
  13.     NULL, mainTIME_TASK_PRIORITY, &hTimeTask );
  14.        
  15.                 xTaskCreate( mpu6050Task, "mpu6050", configMINIMAL_STACK_SIZE,
  16.     NULL, mainTIME_TASK_PRIORITY, &hTimeTask );
  17.        
  18.         xTaskCreate( hmc5883Task, "hmc5883", configMINIMAL_STACK_SIZE,
  19.     NULL, mainTIME_TASK_PRIORITY, &hTimeTask );
  20.        
  21. //        xTaskCreate( ms5611Task, "ms5611", configMINIMAL_STACK_SIZE,
  22. //    NULL, mainTIME_TASK_PRIORITY, &hTimeTask );
  23.                        
  24.     vTaskStartScheduler();

  25.     // Will only get here if there was insufficient memory to create
  26.     // the idle task.
  27.     while(1);
  28. }
复制代码






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2014-7-22 08:49:13 | 显示全部楼层
占个楼,好加东西

出0入0汤圆

 楼主| 发表于 2014-7-22 08:49:29 | 显示全部楼层
再占一层,好加东西

出0入0汤圆

发表于 2014-7-22 09:25:53 | 显示全部楼层
帮顶~字数不够

出0入0汤圆

发表于 2014-7-22 09:37:23 | 显示全部楼层
楼主分享了好东西,这个要赞一个!!!

出0入0汤圆

 楼主| 发表于 2014-7-22 09:48:30 | 显示全部楼层
姿态有锯齿,是因为发送频率太低,只有20Hz

出0入0汤圆

发表于 2014-7-22 21:12:53 | 显示全部楼层
顶起!!!!!!!!!

出0入0汤圆

发表于 2014-7-22 22:40:10 | 显示全部楼层
顶起!!!!!!!!,!,

出0入0汤圆

发表于 2014-7-22 22:48:59 | 显示全部楼层
lena 绑定。。。字数补丁

出0入0汤圆

发表于 2014-7-24 12:11:35 | 显示全部楼层
这个必须支持

出0入0汤圆

 楼主| 发表于 2014-7-24 12:42:13 | 显示全部楼层
硬件: STM32F4-Discovery + GY86

出0入0汤圆

发表于 2014-7-24 13:15:42 | 显示全部楼层
谢谢,最近在搞这个

出0入4汤圆

发表于 2014-7-24 14:49:12 | 显示全部楼层
都玩F4了,我还在弄F1

出0入0汤圆

发表于 2014-7-24 21:14:05 | 显示全部楼层
mark备用。刚刚用过6050做姿态,没有加指南针校正。学习一下。

出0入0汤圆

 楼主| 发表于 2014-7-25 01:02:58 | 显示全部楼层
sunliezhi 发表于 2014-7-24 14:49
都玩F4了,我还在弄F1

其实我觉得片子不重要,算法和原理才是关键

出0入0汤圆

 楼主| 发表于 2014-7-25 01:03:59 | 显示全部楼层
kakarotto 发表于 2014-7-24 21:14
mark备用。刚刚用过6050做姿态,没有加指南针校正。学习一下。

虽然把别人的一份椭圆拟合放进去了,但是并没有搞明白,还在继续学习

出0入0汤圆

发表于 2014-7-25 22:01:39 | 显示全部楼层
MARK一下

出0入0汤圆

发表于 2014-8-9 17:13:36 | 显示全部楼层
谢谢 分享。。

出0入0汤圆

发表于 2014-8-20 18:59:57 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2014-9-2 09:32:29 | 显示全部楼层
不错............

出0入0汤圆

发表于 2014-10-26 09:48:06 | 显示全部楼层
不错的文章,mark下,希望能多交流。

出0入0汤圆

发表于 2014-10-27 10:45:15 | 显示全部楼层
楼主  有上位机不   谢谢

出0入0汤圆

发表于 2014-10-27 10:47:13 | 显示全部楼层
MARK 收藏

出0入0汤圆

发表于 2014-10-27 11:15:50 | 显示全部楼层
楼主   谢谢 分享

出0入0汤圆

发表于 2014-10-27 11:53:51 | 显示全部楼层
感谢分享,最近在关注姿态算法

出0入0汤圆

发表于 2014-10-27 12:29:43 | 显示全部楼层
看来飞控向m4转移是大势所趋了

出0入0汤圆

发表于 2014-11-1 13:43:14 | 显示全部楼层
请问一下,GY-86只能读MPU6050却读不出HMC5883L是什么原因呢?读ID也读不出来,读ID需要先初始化设置吗?

出0入0汤圆

 楼主| 发表于 2014-11-1 13:51:30 | 显示全部楼层
svon 发表于 2014-11-1 13:43
请问一下,GY-86只能读MPU6050却读不出HMC5883L是什么原因呢?读ID也读不出来,读ID需要先初始化设置吗? ...

有没有设置bypass mode?

出0入0汤圆

发表于 2014-11-1 13:53:16 | 显示全部楼层
楼主分享了好东西,这个要赞一个!!!

出0入0汤圆

发表于 2014-11-1 13:54:28 | 显示全部楼层
最近也在学习,非常感谢

出0入0汤圆

发表于 2014-11-1 14:50:05 | 显示全部楼层
6091820503 发表于 2014-11-1 13:51
有没有设置bypass mode?

现在Register 55 – INT Pin / Bypass Enable Configuration这个寄存器是0x02,Register 106 – User Control这个寄存器是0x00,应该是设置好了,但还是没反应。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

 楼主| 发表于 2014-11-1 16:46:09 | 显示全部楼层
svon 发表于 2014-11-1 14:50
现在Register 55 – INT Pin / Bypass Enable Configuration这个寄存器是0x02,Register 106 – User Con ...

我也想不到,只能多加些调试信息,看看程序卡在哪里了
printf("FILE: %s LINE:%d", __FILE__, __LINE__);

出0入0汤圆

发表于 2014-11-1 16:54:32 | 显示全部楼层
6091820503 发表于 2014-11-1 16:46
我也想不到,只能多加些调试信息,看看程序卡在哪里了
printf("FILE: %s LINE:%d", __FILE__, __LINE__); ...

谢谢楼主,设置好了,bypass模式设置要在唤醒芯片之后。

出0入0汤圆

 楼主| 发表于 2014-11-1 18:11:12 | 显示全部楼层
svon 发表于 2014-11-1 16:54
谢谢楼主,设置好了,bypass模式设置要在唤醒芯片之后。

great!

出0入0汤圆

发表于 2014-11-2 09:14:20 | 显示全部楼层
楼主,我用MPU6050的陀螺仪数据对四元数进行三阶龙格-库塔积分时,发现精度很低,z轴转90°差别在10°左右,如果我转动得快的话,有的轴就飞了。我是用的1KHz的sample_rate,积分的周期是1ms,静止时减去校准初始值后x、y轴是0.0几,z轴是0.1dps左右的水平。感觉精度太低了,不知楼主做的结果怎么样?

出0入0汤圆

 楼主| 发表于 2014-11-2 09:44:37 | 显示全部楼层
svon 发表于 2014-11-2 09:14
楼主,我用MPU6050的陀螺仪数据对四元数进行三阶龙格-库塔积分时,发现精度很低,z轴转90°差别在10°左右 ...

陀螺仪校准之后,静止误差跟你的差不多,也很小。
正常积分频率够快的话,应该是可以跟上运动速度的。
我觉得你应该测试一下你的积分步长,到底是不是1ms

出0入0汤圆

发表于 2014-11-2 10:33:09 | 显示全部楼层
6091820503 发表于 2014-11-2 09:44
陀螺仪校准之后,静止误差跟你的差不多,也很小。
正常积分频率够快的话,应该是可以跟上运动速度的。
我 ...

好的,一般陀螺仪积分频率用多快呢?只用陀螺仪的话快速晃动传感器还能回的来吗?

出0入0汤圆

 楼主| 发表于 2014-11-2 10:56:55 | 显示全部楼层
svon 发表于 2014-11-2 10:33
好的,一般陀螺仪积分频率用多快呢?只用陀螺仪的话快速晃动传感器还能回的来吗? ...

只用陀螺仪理论上就是不行的,积分量本身就跟上次的姿态有关,如果上次姿态就不准,就会发散,所以必须不断的用加速度计去修正

出0入0汤圆

发表于 2014-11-2 11:01:06 | 显示全部楼层
6091820503 发表于 2014-11-2 10:56
只用陀螺仪理论上就是不行的,积分量本身就跟上次的姿态有关,如果上次姿态就不准,就会发散,所以必须不 ...

迟一点会做融合,但最好是陀螺仪需要尽量提高自身精度,我再瞅瞅~谢谢哈。

出0入0汤圆

发表于 2014-11-4 12:55:34 | 显示全部楼层
学习了,多谢!

出0入0汤圆

发表于 2014-12-19 22:02:20 | 显示全部楼层
你好!能请教一下你的电子罗盘校正方式吗,就是那个hmc5883l_scale[]的计算我没太看懂,麻烦你了!

出0入0汤圆

发表于 2015-6-11 13:55:40 | 显示全部楼层
谢谢楼主分享

出0入0汤圆

发表于 2015-6-11 13:56:10 | 显示全部楼层
谢谢楼主分享

出0入0汤圆

发表于 2015-6-12 09:21:51 | 显示全部楼层
这2天开始调6050,lz代码参考下,谢谢分享

出0入0汤圆

发表于 2015-6-15 18:54:39 | 显示全部楼层
谢谢楼主的分享

出0入4汤圆

发表于 2015-6-17 15:25:25 | 显示全部楼层
可以参考一下pixhawk的代码!或许对你有帮助!!

出0入0汤圆

发表于 2016-4-26 11:05:31 | 显示全部楼层
MARK

出0入0汤圆

发表于 2016-5-18 15:44:55 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2016-11-14 15:10:37 | 显示全部楼层
下载来学习下,算法水太深呀
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-6 09:20

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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