资讯动态

STM32驱动MPU6050全攻略:软件I2C与硬件I2C实战对比

发布时间:2026/8/24 8:58:58 来源:尧图企业网站定制
1. 项目概述从零到一玩转MPU6050最近在做一个两轮平衡小车的项目核心的传感器选型上MPU6050几乎是绕不开的选择。这颗集成了三轴加速度计和三轴陀螺仪的六轴传感器价格便宜、性能稳定是入门姿态感知和运动控制的绝佳器件。网上关于MPU6050的教程和代码很多但很多朋友在实际操作时还是会遇到各种问题比如数据读不出来、数据跳动太大、或者纠结于到底用软件模拟I2C还是硬件I2C。我自己在STM32平台上调试MPU6050也踩过不少坑从最开始的软件I2C调试不通到后来硬件I2C的时序问题再到数据滤波和姿态解算每一步都值得拿出来聊聊。这个项目的目的很明确在STM32平台上实现稳定、可靠地读取MPU6050的原始数据。我们会分别用软件模拟I2C和硬件I2C两种方式来实现并对比它们的优缺点和适用场景。无论你是刚接触STM32的新手还是想深入了解I2C通信和传感器驱动的朋友这篇内容都能给你提供一份可以直接“抄作业”的代码和清晰的调试思路。你会发现驱动一个传感器不仅仅是调用几个库函数那么简单背后的时序、寄存器配置、数据处理每一个环节都藏着学问。2. 核心思路与方案选型软件I2C vs 硬件I2C当我们决定用STM32读取MPU6050时第一个要做的选择题就是通信接口。MPU6050支持I2C和SPI但最常见、最省引脚的方式就是I2C。而在STM32上实现I2C通常有两条路软件模拟Software I2C和使用芯片自带的硬件I2C外设Hardware I2C。这两种方案没有绝对的好坏只有是否适合你的当前项目。软件模拟I2C顾名思义就是不用STM32内部的I2C专用硬件而是随便找两个普通的GPIO引脚比如PA0和PA1通过程序代码控制这两个引脚的高低电平和延时来模拟出I2C通信协议要求的时序起始信号、停止信号、数据读写、应答信号等。它的最大优点是灵活性和兼容性。首先引脚可以任意指定不受硬件限制当硬件I2C引脚被其他功能占用时这是唯一的出路。其次时序完全由代码控制可以规避不同型号STM32芯片硬件I2C可能存在的兼容性“坑”尤其是STM32F1系列的一些旧款芯片其硬件I2C确实有些小毛病。对于新手来说软件I2C的代码流程清晰每一步都可以自己掌控更容易理解I2C协议的本质。但缺点也很明显占用CPU资源。CPU需要不断地执行指令来翻转IO和制造延时通信速率较低且在高速或主循环任务繁忙时时序容易被打断导致通信失败。硬件I2C则是使用STM32内部集成的I2C外设控制器。你只需要配置好相应的复用功能引脚如I2C1的PB6-SCL PB7-SDA设置好时钟速度、模式等参数然后操作对应的数据寄存器、状态寄存器硬件就会自动帮你生成正确的I2C时序。它的核心优势是高效和稳定。通信过程由硬件自动完成不占用CPU时间CPU可以“通知”硬件去收发数据然后自己处理其他任务等硬件完成后再来读取结果。这种方式速率高、可靠性好适合在复杂的多任务系统中使用。但它的缺点在于配置相对复杂需要理解STM32的I2C架构和寄存器并且引脚是固定的缺乏灵活性。有时候因为硬件Bug或配置不当会出现卡在BUSY状态、无法产生停止条件等棘手问题。注意对于STM32F103等系列早期标准库的硬件I2C驱动可能存在一些瑕疵导致稳定性不佳这也是“软件I2C更稳定”说法的来源之一。但使用HAL库或者仔细调整时序参数后硬件I2C完全可以稳定工作。在我的项目实践中我通常会这样选择在学习、验证、快速原型阶段或者引脚资源紧张需要灵活分配时优先使用软件I2C因为它简单直接排错方便。在正式产品、需要高可靠性、低CPU占用的项目中则必须使用硬件I2C并充分测试其稳定性。接下来我们就从软件I2C开始一步步拆解如何驱动MPU6050。3. 软件模拟I2C驱动MPU6050详解软件I2C的本质是“用GPIO模仿一个状态机”。我们需要用代码精确地再现I2C总线上的每一个信号跳变和时序要求。MPU6050作为从设备其I2C地址通常是0x68当AD0引脚接低电平或0x69当AD0接高电平。我们以0x68为例。3.1 软件I2C底层时序模拟首先我们需要定义用于模拟SCL时钟线和SDA数据线的GPIO引脚并完成初始化将它们设置为推挽输出模式因为要主动控制高低电平。这里的关键是四个基本时序函数起始信号、停止信号、发送应答、等待应答。起始信号S在SCL高电平期间SDA产生一个下降沿。void I2C_Start(void) { SDA_OUT(); // 设置SDA为输出模式 I2C_SDA_HIGH(); I2C_SCL_HIGH(); delay_us(5); // 保持时间满足tHD;STA I2C_SDA_LOW(); delay_us(5); I2C_SCL_LOW(); // 钳住总线准备发送数据 }停止信号P在SCL高电平期间SDA产生一个上升沿。void I2C_Stop(void) { SDA_OUT(); I2C_SDA_LOW(); delay_us(5); I2C_SCL_HIGH(); delay_us(5); I2C_SDA_HIGH(); delay_us(5); }发送一个字节数据在SCL低电平时变化在SCL高电平时保持稳定。从最高位MSB开始依次发送。uint8_t I2C_SendByte(uint8_t byte) { uint8_t i, ack; SDA_OUT(); for (i 0; i 8; i) { if (byte 0x80) I2C_SDA_HIGH(); else I2C_SDA_LOW(); delay_us(2); I2C_SCL_HIGH(); delay_us(5); // 保证SCL高电平周期大于4.7us I2C_SCL_LOW(); delay_us(2); byte 1; } // 读取应答位 ack I2C_ReadAck(); return ack; // 返回0表示应答1表示非应答 }等待应答发送完一个字节通常是地址或数据后主机需要释放SDA线设置为输入模式并在第9个时钟脉冲高电平期间读取SDA线的电平。低电平表示从机应答ACK高电平表示非应答NACK。uint8_t I2C_ReadAck(void) { uint8_t ack; SDA_IN(); // 设置SDA为输入模式 I2C_SDA_HIGH(); // 内部上拉或外部上拉使能确保总线被释放 delay_us(2); I2C_SCL_HIGH(); delay_us(5); if (READ_SDA_PIN()) ack 1; // 读引脚电平 else ack 0; I2C_SCL_LOW(); SDA_OUT(); // 切换回输出模式为后续操作做准备 return ack; }实操心得这里的延时delay_us(5)非常关键。I2C标准模式速率为100kHz周期为10us高/低电平各需大于4.7us。我们的延时需要满足这个要求。太快可能导致从设备来不及反应太慢则通信效率低。如果发现通信不稳定可以适当增大延时比如到delay_us(10)。另外在切换SDA方向输入/输出时一定要确保SCL是低电平状态这是协议规定的。3.2 MPU6050寄存器读写函数封装有了底层的时序函数我们就可以封装针对MPU6050的读写函数了。MPU6050内部有很多寄存器比如电源管理寄存器0x6B、加速度计配置寄存器0x1C、陀螺仪配置寄存器0x1B以及数据寄存器0x3B开始。单字节写函数流程是起始信号 - 发送从机地址写模式0x681 | 0 0xD0- 等待应答 - 发送寄存器地址 - 等待应答 - 发送要写入的数据 - 等待应答 - 停止信号。void MPU6050_WriteReg(uint8_t reg, uint8_t data) { I2C_Start(); I2C_SendByte(MPU6050_ADDR_W); // 0xD0 I2C_SendByte(reg); I2C_SendByte(data); I2C_Stop(); }单字节读函数读操作稍复杂需要先“写”寄存器地址再重启总线进行读操作。流程起始信号 - 发送从机地址写模式- 等待应答 - 发送要读取的寄存器地址 - 等待应答 - 起始信号重复起始- 发送从机地址读模式0x681 | 1 0xD1- 等待应答 - 读取数据发送非应答信号表示结束- 停止信号。uint8_t MPU6050_ReadReg(uint8_t reg) { uint8_t data; I2C_Start(); I2C_SendByte(MPU6050_ADDR_W); I2C_SendByte(reg); I2C_Start(); // 重复起始条件 I2C_SendByte(MPU6050_ADDR_R); // 0xD1 data I2C_ReadByte(); // 读取一个字节 I2C_SendNAck(); // 发送非应答主机终止读取 I2C_Stop(); return data; }连续字节读函数读取传感器数据时我们需要连续读取多个寄存器例如从0x3B开始连续读14个字节获取三轴加速度、温度、三轴陀螺仪数据。流程与单字节读类似只是在读取最后一个字节前主机都需要发送应答ACK读取最后一个字节后发送非应答NACK。void MPU6050_ReadRegs(uint8_t reg, uint8_t *buf, uint8_t len) { I2C_Start(); I2C_SendByte(MPU6050_ADDR_W); I2C_SendByte(reg); I2C_Start(); // 重复起始条件 I2C_SendByte(MPU6050_ADDR_R); while (len 1) { *buf I2C_ReadByte(); I2C_SendAck(); // 发送应答继续读 len--; } *buf I2C_ReadByte(); // 读最后一个字节 I2C_SendNAck(); // 发送非应答终止读取 I2C_Stop(); }3.3 MPU6050初始化与数据读取流程有了读写函数初始化MPU6050就变得有章可循。通常的初始化步骤如下解除休眠MPU6050上电后处于睡眠模式。向电源管理寄存器10x6B写入0x00唤醒传感器。配置传感器量程加速度计量程配置加速度计配置寄存器0x1C。常用±2g0x00±4g0x08±8g0x10±16g0x18。量程越小灵敏度越高。陀螺仪量程配置陀螺仪配置寄存器0x1B。常用±250°/s0x00±500°/s0x08±1000°/s0x10±2000°/s0x18。配置数字低通滤波器DLPF配置配置寄存器0x1A。可以滤除传感器信号中的高频噪声根据你的应用需求选择截止频率。配置采样率采样率分频器寄存器0x19。采样率 陀螺仪输出速率 / (1 SMPLRT_DIV)。陀螺仪输出速率通常为1kHz当DLPF关闭或配置为256Hz时或8kHz当DLPF配置为其他值时。初始化代码示例void MPU6050_Init(void) { // 1. 软件I2C初始化GPIO初始化 Soft_I2C_Init(); // 2. 延时等待MPU6050上电稳定 delay_ms(100); // 3. 解除休眠 MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x00); delay_ms(10); // 4. 设置加速度计量程为±2g MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x00); // 5. 设置陀螺仪量程为±250°/s MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x00); // 6. 配置数字低通滤波器带宽约94Hz MPU6050_WriteReg(MPU6050_CONFIG, 0x02); // 7. 设置采样率分频输出速率1kHz/(19)100Hz MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09); }数据读取就很简单了调用我们写好的连续读函数即可void MPU6050_GetData(int16_t *accel, int16_t *gyro, int16_t *temp) { uint8_t buf[14]; MPU6050_ReadRegs(MPU6050_ACCEL_XOUT_H, buf, 14); // 数据是高字节在前低字节在后 accel[0] (int16_t)((buf[0] 8) | buf[1]); // Accel X accel[1] (int16_t)((buf[2] 8) | buf[3]); // Accel Y accel[2] (int16_t)((buf[4] 8) | buf[5]); // Accel Z temp[0] (int16_t)((buf[6] 8) | buf[7]); // Temperature gyro[0] (int16_t)((buf[8] 8) | buf[9]); // Gyro X gyro[1] (int16_t)((buf[10] 8) | buf[11]); // Gyro Y gyro[2] (int16_t)((buf[12] 8) | buf[13]); // Gyro Z }读出来的accel和gyro是原始数据需要根据你设置的量程进行转换。例如加速度计量程为±2g时灵敏度为16384 LSB/g。那么实际的加速度值单位g为ax_g accel_x / 16384.0。4. 硬件I2C驱动MPU6050实战基于HAL库使用硬件I2C我们不再需要手动模拟时序而是利用STM32的HAL库或标准库提供的API。这里以STM32CubeMX生成HAL库代码为例。4.1 CubeMX配置与代码生成引脚配置在CubeMX的Pinout视图里找到你想使用的I2C外设比如I2C1。将对应的SCL和SDA引脚如PB6 PB7设置为I2C1_SCL和I2C1_SDA。这两个引脚会自动配置为复用开漏输出Alternate Function Open Drain并且内部上拉如果使能了的话。务必在原理图上为这两条线连接外部上拉电阻通常4.7kΩ到10kΩ这是I2C总线正常工作的物理基础。I2C参数配置在Connectivity-I2C1中进行配置。Mode选择I2C。I2C Speed Mode选择Standard Mode100kHz或Fast Mode400kHz。MPU6050支持400kHz可以提升数据读取速度。Clock Speed根据你选择的模式自动计算。生成代码配置好工程名、路径、Toolchain后生成代码。CubeMX会自动生成I2C的初始化代码MX_I2C1_Init以及相应的HAL库源文件。4.2 HAL库读写函数封装HAL库提供了阻塞式、中断式和DMA式三种传输方式。对于MPU6050这种读取频率不高通常100Hz的应用使用简单的阻塞式传输就足够了。我们需要封装几个基本的读写函数。单字节写函数使用HAL_I2C_Mem_Write函数非常方便它集成了发送设备地址、寄存器地址和写入数据的过程。HAL_StatusTypeDef MPU6050_WriteReg_HAL(uint8_t reg, uint8_t data) { return HAL_I2C_Mem_Write(hi2c1, // I2C外设句柄 MPU6050_ADDR_W, // 设备写地址 (0xD0) reg, // 寄存器地址 I2C_MEMADD_SIZE_8BIT, // 寄存器地址长度8位 data, // 要写入的数据指针 1, // 数据长度 100); // 超时时间ms }单字节读函数使用HAL_I2C_Mem_Read。HAL_StatusTypeDef MPU6050_ReadReg_HAL(uint8_t reg, uint8_t *data) { return HAL_I2C_Mem_Read(hi2c1, MPU6050_ADDR_R, // 设备读地址 (0xD1) reg, I2C_MEMADD_SIZE_8BIT, data, 1, 100); }连续字节读函数同样使用HAL_I2C_Mem_Read只需修改数据长度。HAL_StatusTypeDef MPU6050_ReadRegs_HAL(uint8_t reg, uint8_t *buf, uint16_t len) { return HAL_I2C_Mem_Read(hi2c1, MPU6050_ADDR_R, reg, I2C_MEMADD_SIZE_8BIT, buf, len, 100); }可以看到HAL库的封装让代码变得非常简洁。初始化流程和软件I2C版本完全一样只是底层读写函数换成了上述的HAL版本。4.3 硬件I2C的稳定性优化技巧硬件I2C虽然强大但配置不当容易出问题。以下是一些提升稳定性的关键点上拉电阻是必须的I2C总线是开漏结构必须依靠上拉电阻将总线拉至高电平。即使STM32的IO可以配置为内部上拉其阻值通常较大约40kΩ在长导线或高速模式下可能不足以提供稳定的上升沿。强烈建议在SCL和SDA线上各接一个4.7kΩ的外部上拉电阻到VCC3.3V。时钟配置检查确保你的系统时钟HCLK和I2C外设时钟PCLK1配置正确。在CubeMX的Clock Configuration标签页下检查。I2C的时钟频率由PCLK1分频得到需要满足标准模式或快速模式的要求。适当增加超时时间HAL库的读写函数都有超时参数。如果总线上有干扰或从设备响应慢可能导致超时。可以适当增加这个值比如从100ms增加到500ms尤其是在初始化阶段。处理总线错误在实际代码中应该检查HAL函数的返回值HAL_OK,HAL_ERROR,HAL_BUSY,HAL_TIMEOUT。如果发生错误或超时可以进行重试或者复位I2C总线。#define MAX_RETRY 3 HAL_StatusTypeDef status; uint8_t retry 0; do { status MPU6050_WriteReg_HAL(reg, data); retry; if (status ! HAL_OK) { HAL_Delay(1); // 可选在此处加入I2C总线复位函数 // HAL_I2C_DeInit(hi2c1); // HAL_I2C_Init(hi2c1); } } while (status ! HAL_OK retry MAX_RETRY);注意总线冲突如果系统中还有其他I2C设备要确保地址不冲突。MPU6050的地址可以通过AD0引脚改变这是一个有用的特性。5. 数据滤波与校准从原始数据到可用数据直接从MPU6050读出的原始数据是没法直接用的噪声很大而且存在零偏。我们需要进行校准和滤波。5.1 传感器校准校准的目的是消除传感器的静态误差主要是零偏Bias。对于加速度计当传感器静止且水平放置时理论上Z轴输出应为1g16384 LSBX、Y轴输出应为0。对于陀螺仪静止时三轴输出都应为0。但实际上它们都会有偏差。加速度计校准将MPU6050水平静止放置采集数百个样本计算每个轴的平均值。这个平均值就是该轴的零偏。在后续读数中减去这个零偏即可。注意Z轴的平均值减去16384才是零偏因为重力加速度。// 简易加速度计零偏校准 void MPU6050_CalibrateAccel(int16_t *accel_bias) { int32_t sum[3] {0}; int16_t accel[3]; for (int i 0; i 500; i) { MPU6050_GetData(accel, NULL, NULL); sum[0] accel[0]; sum[1] accel[1]; sum[2] accel[2]; HAL_Delay(2); } accel_bias[0] sum[0] / 500; accel_bias[1] sum[1] / 500; accel_bias[2] (sum[2] / 500) - 16384; // 减去1g的理论值 }陀螺仪校准将MPU6050静止放置采集数百个样本计算每个轴的平均值。这个平均值就是陀螺仪的零偏。后续读数直接减去此零偏。// 简易陀螺仪零偏校准 void MPU6050_CalibrateGyro(int16_t *gyro_bias) { int32_t sum[3] {0}; int16_t gyro[3]; for (int i 0; i 500; i) { MPU6050_GetData(NULL, gyro, NULL); sum[0] gyro[0]; sum[1] gyro[1]; sum[2] gyro[2]; HAL_Delay(2); } gyro_bias[0] sum[0] / 500; gyro_bias[1] sum[1] / 500; gyro_bias[2] sum[2] / 500; }校准后的数据读取int16_t raw_accel[3], raw_gyro[3], temp; int16_t accel_bias[3] { -123, 45, 205 }; // 示例零偏值需实际校准得出 int16_t gyro_bias[3] { 32, -18, 12 }; // 示例零偏值 MPU6050_GetData(raw_accel, raw_gyro, temp); float accel_x_g (raw_accel[0] - accel_bias[0]) / 16384.0f; float gyro_x_dps (raw_gyro[0] - gyro_bias[0]) / 131.0f; // ±250dps时灵敏度为131 LSB/(°/s)5.2 软件滤波算法即使校准后数据依然会有高频噪声。常用的简单滤波算法有均值滤波连续采样N次取平均值。能平滑噪声但会引入滞后。滑动平均滤波维护一个长度为N的队列新数据入队旧数据出队始终计算队列平均值。实时性比一次性均值滤波好。一阶低通滤波指数加权平均这是最常用且计算量小的方法。filtered_data α * raw_data (1-α) * filtered_data_prev。其中α是滤波系数0α1α越大新数据权重越高响应越快但噪声大α越小滤波效果越好但滞后越严重。通常取0.1到0.3之间。一阶低通滤波C语言实现float alpha 0.2; // 滤波系数 float filtered_accel_x 0; float filtered_gyro_x 0; void MPU6050_FilterData(float raw_accel, float raw_gyro) { filtered_accel_x alpha * raw_accel (1 - alpha) * filtered_accel_x; filtered_gyro_x alpha * raw_gyro (1 - alpha) * filtered_gyro_x; // 同理处理其他轴 }对于要求更高的应用如姿态解算通常会将滤波算法融合进解算算法本身如互补滤波、卡尔曼滤波而不是单独对原始数据滤波。6. 常见问题排查与调试心得调试MPU6050的过程就是与各种奇怪现象斗争的过程。下面是我总结的一些常见问题及解决方法。6.1 通信失败读不到ID或数据全为零这是最常见的问题。首先进行系统性排查硬件连接检查电源确保VCC接3.3VGND接地。用万用表测量MPU6050的VCC引脚电压是否稳定。上拉电阻SCL和SDA线是否接了4.7kΩ上拉到3.3V这是硬件I2C和软件I2C都强烈建议的。地址引脚检查AD0引脚的电平确认你代码中使用的I2C地址0x68或0x69与之匹配。焊接与线缆检查是否有虚焊、短路杜邦线是否接触不良。尝试更换一组线。软件I2C排查时序延时这是软件I2C的命门。用逻辑分析仪或示波器抓取SCL和SDA的波形对照I2C时序图检查起始、停止、数据位、应答位的时序是否满足要求特别是SCL高电平时间。如果没有仪器最简单的方法是逐步增大delay_us中的延时比如从5us增加到10us、20us看是否能通信成功。引脚方向切换在读取应答和读取数据时SDA必须切换为输入模式且切换前后要保证SCL为低电平。检查SDA_IN()和SDA_OUT()函数是否正确配置了GPIO的输入/输出模式。起始/停止信号确保起始信号中SDA下降沿发生在SCL高电平期间停止信号中SDA上升沿发生在SCL高电平期间。硬件I2C排查CubeMX配置重新检查CubeMX中I2C的引脚配置、模式I2C、时钟速度是否正确。确认生成的代码中hi2c1实例被正确初始化。HAL库状态单步调试检查HAL_I2C_Mem_Read/Write函数的返回值。如果是HAL_TIMEOUT尝试增大超时时间。如果是HAL_ERROR可能总线被锁死。总线锁死这是一个经典问题。当通信意外中断如从机无应答却继续发时钟硬件I2C可能会卡在BUSY状态。解决方法是在初始化序列或错误处理中加入总线复位。// 强制复位I2C总线 void I2C1_ResetBus(void) { HAL_I2C_DeInit(hi2c1); HAL_Delay(10); HAL_I2C_Init(hi2c1); }地址问题确保调用HAL函数时传入的设备地址是7位地址左移1位后的值即MPU6050_ADDR_W0xD0MPU6050_ADDR_R0xD1。HAL库的Mem_Read/Write函数要求传入这个格式的地址。6.2 数据跳动大或不准确未校准这是最主要的原因。务必进行静态校准获取并减去零偏。电源噪声MPU6050对电源噪声比较敏感。确保供电稳定可以在VCC和GND之间并联一个100nF和一个10uF的电容尽量靠近传感器引脚。机械振动如果传感器安装在不稳定的平台上外部振动会直接引入噪声。尝试将传感器放在海棉等减震材料上测试。量程设置不当如果你测量的加速度或角速度超过了设定的量程数据会饱和达到最大值。根据你的应用选择合适量程。滤波参数不当如果使用了一阶低通滤波系数α太大则滤波效果弱噪声大α太小则响应迟钝。需要根据实际数据波形调整。6.3 温度数据异常MPU6050的温度传感器输出的是芯片内部温度并非环境温度。其转换公式为Temperature(°C) (Temp_Out / 340.0) 36.53。其中Temp_Out是读取到的16位有符号温度原始值。如果温度值偏差很大检查数据拼接是否正确高字节在前以及是否使用了有符号数进行计算。6.4 软件I2C与硬件I2C的抉择回顾经过上面的详细拆解我们可以做一个清晰的总结特性软件模拟I2C硬件I2C引脚灵活性极高任意GPIO均可固定需使用指定复用引脚CPU占用高需CPU持续模拟时序极低硬件自动处理通信速率较低受代码效率限制高可达标准/快速模式稳定性高时序完全可控较高依赖硬件和配置代码复杂度较低逻辑清晰较低使用HAL库调试难度较低可逐句调试较高涉及硬件状态适用场景学习、验证、引脚受限、F1系列避坑产品开发、多任务系统、高性能应用对于初学者我建议从软件I2C开始。它能让你深刻理解I2C协议的每一个细节遇到问题时排查思路更清晰。当你完全掌握后在正式项目中转向硬件I2C以获得更好的性能和更低的CPU开销。在STM32F1系列上如果遇到硬件I2C的兼容性问题软件I2C是一个可靠的备选方案。最后无论是软件还是硬件方式成功的核心都在于细致的硬件检查、正确的时序或配置以及必要的数据后处理校准与滤波。把这几步做到位让MPU6050稳定输出数据就只是时间问题了。在实际项目中这些稳定的原始数据将是你进行姿态解算、运动控制等更高级算法的基础。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价