零知實驗室發(fā)布新版ICM20948模塊,可以非常方便的應(yīng)用在零知各個系列開發(fā)板或其他類似MCU,它可以作為已經(jīng)停產(chǎn)的MPU9250的替代品,下面演示它在零知ESP8266上的使用。
一、ICM20948深度解析:九軸傳感器的核心技術(shù)
1.1 什么是IMU?
IMU(Inertial Measurement Unit)即慣性測量單元,是融合加速度計、陀螺儀和磁力計的核心傳感器。ICM20948作為新一代九軸IMU,具備以下技術(shù)特性:
參數(shù) | 規(guī)格 | 技術(shù)優(yōu)勢 |
加速度測量范圍 | ±2g/±4g/±8g/±16g | 16位ADC,0.98mg/LSB@±16g |
陀螺儀量程 | ±250/±500/±1000/±2000 dps | 0.0038°/s/LSB@±250dps |
磁力計量程 | ±4900μT | 16位分辨率,0.15μT/LSB |
數(shù)據(jù)輸出速率 | 最高1125Hz | 支持SPI/I2C雙接口 |
工作電壓 | 1.71V-3.6V | 超低功耗模式<5μA |
1.2 硬件架構(gòu)解析
芯片內(nèi)部采用三層堆疊結(jié)構(gòu):
MEMS傳感層:包含三軸加速度計和陀螺儀
磁力計層:AK09916磁力計通過I2C從接口連接
1.3 九軸數(shù)據(jù)融合原理
姿態(tài)解算通過傳感器融合算法實現(xiàn):
姿態(tài)矩陣=加速度計校準(zhǔn)?陀螺儀積分?磁力計補償
典型算法對比:
算法 | 計算復(fù)雜度 | 精度 | 適用場景 |
互補濾波 | 低 | 一般 | 低速運動 |
卡爾曼濾波 | 高 | 高 | 動態(tài)環(huán)境 |
Mahony | 中等 | 較高 | 嵌入式系統(tǒng) |
二、硬件系統(tǒng)搭建
2.1 物料清單
組件 | 型號 |
主控板 | 零知ESP8266 |
九軸傳感器 | ICM20948 |
連接線 | 杜邦線 |
電源 | USB適配器 |
2.2 電路連接詳解
零知ESP8266和ICM20948九軸加速度傳感器的接線圖:
零知ESP8266 | ICM20948 |
3.3V | VCC |
GND | GND |
SCL | SCL |
SDA | SDA |
ESP8266和ICM20948接線圖
三、軟件系統(tǒng)開發(fā)
3.1 校準(zhǔn)驗證代碼
??// 在setup()中添加的校準(zhǔn)驗證 if(SerialDebug) { Serial.println("Post-Calibration Accel Bias (mg):"); Serial.print(1000*myIMU.accelBias[0]); Serial.print(" "); Serial.print(1000*myIMU.accelBias[1]); Serial.print(" "); Serial.println(1000*myIMU.accelBias[2]); }
將加速度偏置轉(zhuǎn)換為mg單位(1g=1000mg)
X/Y軸偏置應(yīng)<50mg,Z軸接近0(理想值)
確保校準(zhǔn)過程有效,避免硬件安裝誤差
3.2 動態(tài)零位補償
?static int calibration_cnt = 0; if(calibration_cnt < 1000 && abs(myIMU.gx)0.5 && abs(myIMU.gy)0.5) { myIMU.accelBias[0] += myIMU.ax * 0.001; myIMU.accelBias[1] += myIMU.ay * 0.001; calibration_cnt++; }
前1000次采樣持續(xù)修正加速度偏置
0.001為學(xué)習(xí)率系數(shù),控制校準(zhǔn)速度
實現(xiàn)動態(tài)自適應(yīng),消除溫度漂移影響
3.3傳感器數(shù)據(jù)預(yù)處理
1.加速度計處理
myIMU.ax = (float)myIMU.accelCount[0] * myIMU.aRes - myIMU.accelBias[0]; myIMU.ay = (float)myIMU.accelCount[1] * myIMU.aRes - myIMU.accelBias[1]; myIMU.az = (float)myIMU.accelCount[2] * myIMU.aRes - myIMU.accelBias[2];
數(shù)據(jù)處理流程:
accelCount:原始ADC值
aRes:分辨率計算(例如±16g量程時為2048 LSB/g)
減去校準(zhǔn)偏置消除零位誤差
關(guān)鍵參數(shù):
量程設(shè)置:建議初始化時配置為±8g
分辨率公式:aRes = 16.0 / 32768.0 (16位ADC)
2.陀螺儀處理
?myIMU.gx = (float)myIMU.gyroCount[0] * myIMU.gRes - myIMU.gyroBias[0]; myIMU.gy = (float)myIMU.gyroCount[1] * myIMU.gRes - myIMU.gyroBias[1]; myIMU.gz = (float)myIMU.gyroCount[2] * myIMU.gRes - myIMU.gyroBias[2];
漂移控制:
典型偏置值應(yīng)<1°/s
溫度每升高1℃,零偏變化約0.01°/s
改進(jìn)建議:添加溫度補償函數(shù)
3.磁力計數(shù)據(jù)融合
float mx_raw = (float)myIMU.magCount[1] * myIMU.mRes; // X/Y交換 float my_raw = (float)myIMU.magCount[0] * myIMU.mRes; float mz_raw = -(float)myIMU.magCount[2] * myIMU.mRes; // Z反轉(zhuǎn) myIMU.mx = (mx_raw - myIMU.magBias[1]) * myIMU.magScale[1]; myIMU.my = (my_raw - myIMU.magBias[0]) * myIMU.magScale[0]; myIMU.mz = (mz_raw - myIMU.magBias[2]) * myIMU.magScale[2];
magBias:硬鐵干擾補償
magScale:軟鐵畸變校正
注意:校準(zhǔn)數(shù)據(jù)需對應(yīng)新坐標(biāo)系
3.4姿態(tài)解算核心算法
1.Mahony濾波器調(diào)用
MahonyQuaternionUpdate( myIMU.ay, // 加速度Y→X myIMU.ax, // 加速度X→Y -myIMU.az, // 加速度Z反轉(zhuǎn) myIMU.gy * DEG_TO_RAD, // 陀螺Y→X myIMU.gx * DEG_TO_RAD, // 陀螺X→Y -myIMU.gz * DEG_TO_RAD,// 陀螺Z反轉(zhuǎn) myIMU.mx, myIMU.my, myIMU.mz, myIMU.deltat );
2.歐拉角轉(zhuǎn)換
? myIMU.yaw = atan2(2.0f * (*(getQ()+1) * *(getQ()+2) + *getQ() * *(getQ()+3)), *getQ() * *getQ() + *(getQ()+1) * *(getQ()+1) - *(getQ()+2) * *(getQ()+2) - *(getQ()+3) * *(getQ()+3)); myIMU.pitch = -asin(2.0f * (*(getQ()+1) * *(getQ()+3) - *getQ() * *(getQ()+2))); myIMU.roll = atan2(2.0f * (*getQ() * *(getQ()+1) + *(getQ()+2) * *(getQ()+3)), *getQ() * *getQ() - *(getQ()+1) * *(getQ()+1) - *(getQ()+2) * *(getQ()+2) + *(getQ()+3) * *(getQ()+3)); myIMU.pitch *= RAD_TO_DEG; myIMU.yaw *= RAD_TO_DEG; // Declination of SparkFun Electronics (40°05'26.6"N 105°11'05.9"W) is // 8° 30' E ± 0° 21' (or 8.5°) on 2016-07-19 // - http://www.ngdc.noaa.gov/geomag-web/#declination myIMU.yaw -= 8.5; myIMU.roll *= RAD_TO_DEG;
3.5數(shù)據(jù)輸出
串口協(xié)議設(shè)計
//打印格式與processing端格式一致 Serial.print("Or: "); Serial.print(myIMU.yaw, 2); Serial.print(" "); Serial.print(myIMU.pitch, 2); Serial.print(" "); Serial.print(myIMU.roll, 2); Serial.println(" ");
3.6Processing 3D可視化驗證
將代碼庫文件安裝包解壓到C:UsersAdministratorDocumentsProcessinglibraries,然后在Processing中選擇開發(fā)板對應(yīng)的串口號,就可以看到我們的3D模型根據(jù)九軸的姿態(tài)進(jìn)行變化啦:
import processing.serial.*; // 傳感器數(shù)據(jù) float roll, pitch, yaw; PVector accelerometer = new PVector(); PVector gyroscope = new PVector(); PVector magneticField = new PVector(); // 3D模型 PShape model; PImage bgImage; // 串口配置 Serial port; String[] serialPorts; int selectedPort = 0; boolean printSerial = false; void setup() { size(1024, 800, P3D); frameRate(60); // 加載資源 bgImage = loadImage("background.png"); model = loadShape("biplane.obj"); // 確保使用標(biāo)準(zhǔn)OBJ格式 model.scale(30); // 初始化串口 serialPorts = Serial.list(); if(serialPorts.length > 0) connectSerial(serialPorts[0]); } void draw() { background(bgImage); // 3D場景設(shè)置 pushMatrix(); translate(width/2, height/2, 0); lights(); // 應(yīng)用旋轉(zhuǎn) rotateX(radians(pitch)); rotateY(radians(yaw)); rotateZ(radians(roll)); // 繪制模型 shape(model); popMatrix(); // 顯示數(shù)據(jù) displaySensorData(); } void serialEvent(Serial p) { try { String rawData = p.readStringUntil('n').trim(); if(printSerial) println(rawData); String[] parts = split(rawData, ' '); if(parts.length >= 4) { switch(parts[0]) { case "Or:": // 歐拉角格式:Or: yaw pitch roll yaw = float(parts[1]); pitch = float(parts[2]); roll = float(parts[3]); break; case "Accel:": accelerometer.set(float(parts[1]), float(parts[2]), float(parts[3])); break; case "Gyro:": gyroscope.set(float(parts[1]), float(parts[2]), float(parts[3])); break; case "Mag:": magneticField.set(float(parts[1]), float(parts[2]), float(parts[3])); break; } } } catch(Exception e) { println("Serial Error: " + e.getMessage()); } } void displaySensorData() { fill(0, 255, 0); textSize(16); textAlign(LEFT, TOP); String data = "Accelerometer(g): " + nfp(accelerometer.x,1,2) + ", " + nfp(accelerometer.y,1,2) + ", " + nfp(accelerometer.z,1,2) + "n" + "Gyroscope(deg/s): " + nfp(gyroscope.x,1,2) + ", " + nfp(gyroscope.y,1,2) + ", " + nfp(gyroscope.z,1,2) + "n" + "Orientation: n" + "Yaw: " + nfp(yaw,1,1) + "°n" + "Pitch: " + nfp(pitch,1,1) + "°n" + "Roll: " + nfp(roll,1,1) + "°"; text(data, 20, 20); } void connectSerial(String portName) { if(port != null) port.stop(); try { port = new Serial(this, portName, 115200); port.bufferUntil('n'); println("Connected to: " + portName); } catch(Exception e) { println("Connection failed: " + e.getMessage()); } } void keyPressed() { // 切換串口 if(key == ' ') { selectedPort = (selectedPort + 1) % serialPorts.length; connectSerial(serialPorts[selectedPort]); } // 切換調(diào)試輸出 if(key == 'P' || key == 'p') printSerial = !printSerial; // 重置視角 if(key == 'R' || key == 'r') { yaw = pitch = roll = 0; } }
四、實現(xiàn)結(jié)果分析
觀察串口打印輸出的DMP姿態(tài)解算數(shù)據(jù)如下:
Processing 3D可視化驗證:https://www.bilibili.com/video/BV1n3RPYWE8E/?share_source=copy_web&vd_source=75d3b293c1933aa8dc6757ac429e12da
?
五、項目資源匯總
5.1 參考資料
ICM20948數(shù)據(jù)手冊
ESP8266技術(shù)參考
5.2 源碼獲取
https://github.com/Leeri1y/ICM20948-ESP8266
參考Github倉庫
??
64位Windows系統(tǒng)的Processing安裝包:
通過網(wǎng)盤分享的文件:processing-4.3.3.7z
鏈接: https://pan.baidu.com/s/12B4F33M1caRncVjSJiFPTg?pwd=9h5i 提取碼: 9h5i
5.3 擴(kuò)展學(xué)習(xí)
Mahony濾波器數(shù)學(xué)推導(dǎo)
歡迎各位道友相互討論,一直在學(xué)習(xí)的路上!
審核編輯 黃宇
-
Processing
+關(guān)注
關(guān)注
0文章
11瀏覽量
9075 -
IMU
+關(guān)注
關(guān)注
6文章
333瀏覽量
46380 -
ESP8266
+關(guān)注
關(guān)注
50文章
963瀏覽量
46529
發(fā)布評論請先 登錄
相關(guān)推薦
零知開源——ESP8266+MPU6050 實現(xiàn)運動姿態(tài)檢測

零知開源——ESP8266+MPU6050 實現(xiàn)運動姿態(tài)檢測
零知開源——ESP8266結(jié)合ICM20948實現(xiàn)高精度姿態(tài)解算
《電子發(fā)燒友電子設(shè)計周報》聚焦硬科技領(lǐng)域核心價值 第2期:2025.03.3--2025.03.7
請問MPU6050的軟件解算姿態(tài)和DMP解算姿態(tài)各自的優(yōu)缺點是什么?
使用esp8266實現(xiàn)STM32聯(lián)網(wǎng)(最簡單USART方法)
ESP8266入門博客---記錄

ESP8266迷你系統(tǒng)開源分享

ESP8266物聯(lián)網(wǎng)開源分享

ESP8266 SMD轉(zhuǎn)DIP適配器開源分享

評論