0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程

零知实验室 来源:PCB56242069 作者:PCB56242069 2025-06-09 14:01 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

STM32F1

本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA+上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式物联网开发者。在基础驱动上新增 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA+上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增滤波参数优化,重点解决yaw值漂移问题,提供完整的参数调优方案和效果对比。,重点解决yaw值漂移问题,提供完整的参数调优方案和效果对比。

一、硬件准备

1.硬件清单

零知标准板(主控STM32F103RBT6)

ICM20948九轴传感器模块

USB转串口模块(用于调试和数据传输)

杜邦线若干

2.接线方式

ICM20948引脚 零知开发板引脚
VCC 3.3V
GND GND
SDA A4
SCL A5

硬件连接图

wKgZPGhGdd6AJ8-uAAhf9arQelo722.png

连接实物图

wKgZO2hGdfCAPPreAEqjqT86Jw8506.png

注意:确保I2C引脚正确,避免接反导致芯片损坏。

二、软件环境搭建

开发环境

零知 IDE + 零知开发板支持包

所需库文件:

AHRSAlgorithms.cpp(姿态解算库)

ICM20948.cpp(传感器驱动库)

库文件关键功能

AHRSAlgorithms.cpp

Madgwick/Mahony滤波算法

四元数实时输出getQ()

参数可调:Kp、Ki、beta

ICM20948.cpp

I2C通信底层驱动

自动量程配置(加速度计±2/4/8/16g,陀螺仪±250/500/1000/2000dps)

磁力计初始化initAK09916()

校准函数calibrateICM20948()

三、核心代码实现

主程序框架

((ICM20948_VOFA.ino))

/* ICM20948完整优化代码 */
#include "AHRSAlgorithms.h"
#include "ICM20948.h"

#define AHRS true
#define SerialDebug true 

int myLed = LED_BUILTIN;  
ICM20948 myIMU;

void setup() {
  pinMode(myLed, OUTPUT);
  digitalWrite(myLed, HIGH);
  
  Serial.begin(115200);
  Wire.begin();
  
  // 初始化与自检
  if(myIMU.begin()) {
    Serial.println("ICM20948初始化成功");
    
    // 执行两级校准
    myIMU.calibrateICM20948(myIMU.gyroBias, myIMU.accelBias);
    float magBias[3], magScale[3];
    myIMU.magCalICM20948(magBias, magScale);
    
    // 设置优化分辨率
    myIMU.getAres(); 
    myIMU.getGres();
    myIMU.getMres();
  } else {
    Serial.println("传感器初始化失败!");
    while(1);
  }
}

void loop() {
  // 数据读取
  if (myIMU.readByte(ICM20948_ADDRESS, INT_STATUS_1) & 0x01) {
    myIMU.readAccelData(myIMU.accelCount);
    myIMU.readGyroData(myIMU.gyroCount);
    myIMU.readMagData(myIMU.magCount);
    
    // 单位转换
    myIMU.ax = (float)myIMU.accelCount[0] * myIMU.aRes;
    myIMU.ay = (float)myIMU.accelCount[1] * myIMU.aRes;
    myIMU.az = (float)myIMU.accelCount[2] * myIMU.aRes;
    myIMU.gx = (float)myIMU.gyroCount[0] * myIMU.gRes;
    myIMU.gy = (float)myIMU.gyroCount[1] * myIMU.gRes;
    myIMU.gz = (float)myIMU.gyroCount[2] * myIMU.gRes;
    myIMU.mx = (float)myIMU.magCount[0] * myIMU.mRes - myIMU.magBias[0];
    myIMU.my = (float)myIMU.magCount[1] * myIMU.mRes - myIMU.magBias[1];
    myIMU.mz = (float)myIMU.magCount[2] * myIMU.mRes - myIMU.magBias[2];
  }
  
  // 更新时间基准
  myIMU.updateTime();
  
  // 姿态解算(使用优化参数)
  MahonyQuaternionUpdate(
    myIMU.ax, myIMU.ay, myIMU.az,
    myIMU.gx * DEG_TO_RAD, 
    myIMU.gy * DEG_TO_RAD,
    myIMU.gz * DEG_TO_RAD,
    myIMU.my, myIMU.mx, myIMU.mz, // 轴序修正
    myIMU.deltat
  );
  
  // 转换为欧拉角
  const float* q = getQ();
  myIMU.yaw   = atan2(2.0f*(q[1]*q[2] + q[0]*q[3]), 
                   q[0]*q[0] + q[1]*q[1] - q[2]*q[2] - q[3]*q[3]) * RAD_TO_DEG;
  myIMU.pitch = -asin(2.0f*(q[1]*q[3] - q[0]*q[2])) * RAD_TO_DEG;
  myIMU.roll  = atan2(2.0f*(q[0]*q[1] + q[2]*q[3]),
                   q[0]*q[0] - q[1]*q[1] - q[2]*q[2] + q[3]*q[3]) * RAD_TO_DEG;
  
  // 发送到VOFA+
  Serial.print(myIMU.yaw, 1);   // yaw
  Serial.print(",");
  Serial.print(myIMU.pitch, 1); // pitch
  Serial.print(",");
  Serial.println(myIMU.roll, 1);// roll

  delay(10); // 100Hz输出
}

关键配置修改 关键配置修改

在ICM20948.cpp中调整量程(根据应用需求):


// 加速度计量程 (AFS_2G/AFS_4G/AFS_8G/AFS_16G)
void ICM20948::getAres()
{
  switch (Ascale)
  {
    // Possible accelerometer scales (and their register bit settings) are:
    // 2 Gs (00), 4 Gs (01), 8 Gs (10), and 16 Gs  (11).
    // Here's a bit of an algorith to calculate DPS/(ADC tick) based on that
    // 2-bit value:
    case AFS_2G:
      aRes = 2.0f / 32768.0f;
      break;
    case AFS_4G:
      aRes = 4.0f / 32768.0f;
      break;
    case AFS_8G:
      aRes = 8.0f / 32768.0f;
      break;
    case AFS_16G:
      aRes = 16.0f / 32768.0f;
      break;
  }
}

// 陀螺仪量程 (GFS_250DPS/GFS_500DPS/GFS_1000DPS/GFS_2000DPS)
void ICM20948::getGres()
{
  switch (Gscale)
  {
    // Possible gyro scales (and their register bit settings) are:
    // 250 DPS (00), 500 DPS (01), 1000 DPS (10), and 2000 DPS (11).
    // Here's a bit of an algorith to calculate DPS/(ADC tick) based on that
    // 2-bit value:
    case GFS_250DPS:
      gRes = 250.0f / 32768.0f;
      break;
    case GFS_500DPS:
      gRes = 500.0f / 32768.0f;
      break;
    case GFS_1000DPS:
      gRes = 1000.0f / 32768.0f;
      break;
    case GFS_2000DPS:
      gRes = 2000.0f / 32768.0f;
      break;
  }
}

四、VOFA+上位机配置

数据协议设置

选择FireWater协议

格式:q0, q1, q2(逗号分隔+换行符)

波特率:115200

控件添加

3D立方体:显示实时姿态、绑定四元数数据通道、设置模型缩放比例

波形图:各轴角速度/加速度

仪表盘:显示偏航角(Yaw)

界面效果

wKgZPGhGdoiAXQueAAN-scVaVj8629.png

实时显示传感器3D姿态及运动波形

五、滤波参数优化与动态效果对比

1.传感器校准

float gyroBias[3], accelBias[3];
IMU.calibrateICM20948(gyroBias, accelBias); // 上电时执行一次

2.问题现象

使用默认参数(Kp=10.0, Ki=0.0)时,VOFA+显示yaw值持续漂移(约2-5°/s),动态运动时零漂明显

wKgZPGhGdsmAKVLyADKPt9vrm7Y358.png

3.优化方案

在AHRSAlgorithms.h中调整Mahony滤波参数:

// 原参数(漂移明显)
// #define Kp 2.0f * 5.0f
// #define Ki 0.0f

// 优化参数(大幅改善漂移)
#define Kp 3.0f    // 降低比例增益,减少高频噪声响应
#define Ki 0.1f   // 降低积分增益,抑制累积误差

效果对比

参数状态 Yaw漂移率 VOFA+动态表现
默认(Kp=10f,Ki=0.0f) 2-5°/s 静止时缓慢旋转,运动后复位慢
优化(Kp=3.0f,Ki=0.1f) <0.5°/s 静止稳定,运动后快速收敛

4.优化后效果

wKgZO2hGdx6AQVO4AEiJ6SyHx1Y906.png

参数调整原理

Kp过高:对加速度计噪声敏感,导致高频抖动

Ki过高:积分累积误差引起零漂

黄金比例:Kp/Ki ≈ 20-30时平衡动态响应与稳定性

六、效果演示

静态测试

传感器平放时,VOFA+显示俯仰角/横滚角接近0°

Z轴加速度≈9.8 m/s²

wKgZPGhGd1yADzgMAAOKsE6xV8E188.png

动态测试

旋转开发板,3D模型同步跟随

快速晃动时波形图显示各轴加速度变化

演示视频: https://live.csdn.net/v/480172?spm=1001.2014.3001.5501

输出速率调优

ICM20948原始数据输出率约100Hz(10ms/次)

当delt_t=60ms时,姿态解算循环(16.7Hz)与传感器更新周期不同步

导致部分数据帧被重复使用或跳过

wKgZO2hGd-uAEFeSAAPHqou5WHM818.png

完整工程代码

百度网盘获取完整工程文件,链接如下:

https://pan.baidu.com/s/11tr8XJvNrNernqwK1zA9Mw?pwd=pbxd

七、效果验证与结论

测试结果

指标 优化前 优化后
静态yaw漂移 2-5°/s <0.5°/s
动态收敛时间 >3s <1s
高温稳定性 漂移增加300% 漂移增加<50%

结论

通过调整Kp/Ki比例可有效抑制yaw漂移

磁力计轴序修正提升方位角精度

VOFA+可视化提供直观参数调优依据

三阶段校准确保全温度范围稳定性

✔(●'◡'●)

零知开源是一个真正属于国人自己的开源软硬件平台,在开发效率上超越了Arduino平台并且更加容易上手,大大降低了开发难度。
零知开源在软件方面提供了完整的学习教程和丰富示例代码,让不懂程序的工程师也能非常轻而易举的搭建电路来创作产品,测试产品。快来动手试试吧!
www.lingzhilab.com


审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 传感器
    +关注

    关注

    2574

    文章

    54420

    浏览量

    786276
  • 可视化
    +关注

    关注

    1

    文章

    1318

    浏览量

    22602
  • stm32f1
    +关注

    关注

    1

    文章

    60

    浏览量

    12804
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    开源——STM32F407VET6驱动SHT41温湿度传感器完整教程

    目基于STM32F407VET6增强板,实现SHT41高精度温湿度传感器驱动和数据采集。SHT41是Sensirion推出的新一代数字
    发表于 07-10 12:01

    开源——STM32F407VET6驱动SHT41温湿度传感器完整教程

    摘要:本项目基于STM32F407VET6增强板驱动SHT41高精度温湿度传感器,实现±0.2℃温度精度和±1.8%RH湿度精度的数据采
    的头像 发表于 07-09 18:53 929次阅读
    <b class='flag-5'>零</b><b class='flag-5'>知</b><b class='flag-5'>开源</b>——<b class='flag-5'>STM32F407VET6</b><b class='flag-5'>驱动</b>SHT41温湿度<b class='flag-5'>传感器</b>完整教程

    开源——STM32F1驱动BMP581压强传感器使用SPI实现ST7789显示的环境监测系统

    组件 型号 数量 主控板标准板 1 气压传感器 BMP581 1 显示屏ST7789 (240x320)1 杜邦线公对公若干 1.2 接线方案
    发表于 07-03 17:26

    开源——STM32F103RBT6驱动 ICM20948 传感器vofa + 上位可视化教程

    STM32F1本教程使用标准板(STM32F103RBT6)通过I2C驱动ICM20948
    发表于 06-09 14:53

    经验——STM32F4驱动ICM20948 运动传感器 + VOFA上位可视化验证与抗漂移优化

    核心优化成果:经过系统性调优,将ICM20948的yaw漂移从初始的15°/min降至0.8°/min,动态响应时间缩短40%,摇摆幅度减少75% 一、问题根源:传感器漂移难题在
    发表于 06-06 10:03

    经验——STM32F4驱动ICM20948 运动传感器 + VOFA上位可视化验证与抗漂移优化

    通过对ICM20948传感器的系统性优化,成功将yaw漂移从15°/min降至0.8°/min,动态性能提升显著。硬件层面优化了I2C
    的头像 发表于 06-06 09:43 1297次阅读
    <b class='flag-5'>零</b><b class='flag-5'>知</b>经验——<b class='flag-5'>STM32F</b>4<b class='flag-5'>驱动</b><b class='flag-5'>ICM20948</b> <b class='flag-5'>九</b><b class='flag-5'>轴</b>运动<b class='flag-5'>传感器</b> + <b class='flag-5'>VOFA</b><b class='flag-5'>上位</b><b class='flag-5'>机</b><b class='flag-5'>可视化</b>验证与抗漂移优化

    开源——STM32F4驱动MAX31865实现PT100高精度测温

    材料增强板(STM32F407VET6) MAX31865模块(支持三线制PT100) 三线制PT100传感器 0.96寸I2C OLED显示屏(SSD1306
    发表于 05-26 18:52

    开源——STM32F1驱动MAX31865读取三线PT100温度传感器

    STM32F103RBT6) MAX31865模块(支持三线制PT100) 三线制PT100传感器 0.96寸I2C OLED显示屏(SSD1306驱动) 杜邦线若干 2.MAX31865跳线修改三线制PT100必须修改模块
    发表于 05-23 18:27

    开源——STM32F1驱动MAX31865读取三线PT100温度传感器

    本教程详细介绍了如何使用标准板(STM32F103RBT6)通过MAX31865模块读取三线制PT100铂电阻温度,并通过I2C OLED实时显示温度值和电阻值。教程内容包括硬件接线配置、三线
    的头像 发表于 05-23 18:05 1846次阅读
    <b class='flag-5'>零</b><b class='flag-5'>知</b><b class='flag-5'>开源</b>——<b class='flag-5'>STM32F</b>1<b class='flag-5'>驱动</b>MAX31865读取三线PT100温度<b class='flag-5'>传感器</b>

    STM32F103RCT6采集不同采样率传感器数据发送到位数据不完整

    你好,我用STM32F103RCT6对2个传感器实时采集数据,传感器1:SPI通信,采样率1000HZ,TIM2中断判断并通过串口1发送数据到上位
    发表于 04-23 01:22

    用NANO STM32F103RBT6的开发板烧录不了是哪里出了问题?

    今天用久别的NANO STM32F103RBT6的开发板,在公司的电脑上编译基本工程,怎么就烧录不了了?望好友伸出援助之手,不胜感激。
    发表于 03-10 07:48

    开源——ESP8266结合ICM20948实现高精度姿态解算

    清单 组件 型号 主控板 ESP8266 传感器 ICM20948 连接线 杜邦
    发表于 03-07 15:46

    开源——ESP8266结合ICM20948实现高精度姿态解算

    IMU惯性测量单元,融合加速度计、陀螺仪和磁力计的核心传感器,实现高精度姿态解算
    的头像 发表于 03-07 14:09 2044次阅读
    <b class='flag-5'>零</b><b class='flag-5'>知</b><b class='flag-5'>开源</b>——ESP8266结合<b class='flag-5'>ICM20948</b>实现高精度姿态解算

    开源——MPU6050六传感器模块实践教程,轻松实现运动检测!

    增强板I2C通信       本教程将指导您如何使用增强板与MPU6050六传感器模块
    的头像 发表于 02-20 16:17 1809次阅读
    <b class='flag-5'>零</b><b class='flag-5'>知</b><b class='flag-5'>开源</b>——MPU6050六<b class='flag-5'>轴</b><b class='flag-5'>传感器</b>模块实践教程,轻松实现运动检测!

    开源——MPU6050六传感器模块实践教程,轻松实现运动检测!

    本帖最后由 PCB56242069 于 2025-2-20 17:27 编辑 ​增强板I2C通信 本教程将指导您如何使用增强板与MPU6050六
    发表于 02-20 15:53