简洁版本 MPU6886是一款6轴IMU单元,具有3轴重力加速度计和3轴陀螺仪。它采用16位ADC,内置可编程数字滤波器和片上温度传感器,并通过I2C接口(地址为0x68)与上位机通信。MPU6886支持低功耗模式,并具有高性能规格,包括陀螺仪灵敏度误差±1%、陀螺仪噪声±4 mdps/√Hz、加速度计噪声100 μg/√Hz等。此外,它还支持EIS同步,可以应用于可穿戴设备、运动跟踪、无人机姿态确定、智能手机和平板电脑、物联网应用、基于运动的游戏控制器,以及用于互联网连接的DTV和机顶盒、3D鼠标等领域。
(MPU6886)6轴IMU单元是带有3轴重力加速度计和3轴陀螺仪的6轴姿态传感器,可以实时计算倾斜角度和加速度。该芯片采用mpu6886,具有16位ADC,内置可编程数字滤波器和片上温度传感器,采用I2C接口(addr:0x68)与上位机通信,并支持低功耗模式。
M5AtomS3官方示例代码:
/*
*******************************************************************************
* Copyright (c) 2021 by M5Stack
* Equipped with AtomS3 sample source code
* 配套 AtomS3 示例源代码
* Visit for more information: https://docs.m5stack.com/en/core/AtomS3
* 获取更多资料请访问:https://docs.m5stack.com/zh_CN/core/AtomS3
*
* Describe: MPU6886. 姿态传感器示例
* Date: 2022/12/19
*******************************************************************************
*/
#include "M5AtomS3.h"
/* After AtomS3 is started or reset the program in the setUp ()
function will be run, and this part will only be run once.
在 AtomS3 启动或者复位后,即会开始执行setup()函数中的程序,该部分只会执行一次。
*/
void setup() {
M5.begin(true, true, true,
false); // Init AtomS3(Initialize LCD, serial port).
// 初始化 AtomS3(初始化LCD、串口)
M5.IMU.begin(); // Init IMU sensor. 初始化姿态传感器
USBSerial.printf("whoAmI() = 0x%02x\n", M5.IMU.whoAmI());
}
/* After the program in setup() runs, it runs the program in loop()
The loop() function is an infinite loop in which the program runs repeatedly
在setup()函数中的程序执行完后,会接着执行loop()函数中的程序
loop()函数是一个死循环,其中的程序会不断的重复运行 */
float ax, ay, az, gx, gy, gz, t;
void loop() {
M5.Lcd.setCursor(0, 40);
M5.Lcd.clear(); // Delay 100ms 延迟100ms
M5.IMU.getAccel(&ax, &ay, &az); // Read tri-axial accel 读取三轴加速度
M5.IMU.getGyro(&gx, &gy, &gz); // Read gyroscope data 读取陀螺仪数据
M5.IMU.getTemp(&t); // Read temperature data 读取温度数据
USBSerial.printf("%f,%f,%f,%f,%f,%f,%f\n", ax, ay, az, gx, gy, gz,
t); // serial port output the formatted string. 串口输出
M5.Lcd.printf("IMU:\r\n");
M5.Lcd.printf("%0.2f %0.2f %0.2f\r\n", ax, ay, az);
M5.Lcd.printf("%0.2f %0.2f %0.2f\r\n", gx, gy, gz);
delay(500);
}
arduino中获取MPU6886常规代码如下:
#include <Wire.h>
#define MPU6886_ADDRESS 0x68
byte int16_array[14] ;
float posture[3] ;
void setup() {
Wire.begin();
Wire.beginTransmission(MPU6886_ADDRESS);
Wire.write(0x6B); // PWR_MGMT_1 register
Wire.write(0); // set to zero (reset)
Wire.endTransmission(false);
Serial.begin(9600);
}
void loop() {
Wire.beginTransmission(MPU6886_ADDRESS);
Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU6886_ADDRESS, 14, true); // request 14 bytes of data
for (int i = 0; i < 14; i++) { // read data into array
int16_array[i] = Wire.read() << 8 | Wire.read();
}
posture[0] = (float)int16_array[0] / 16384.0; // convert x-axis acceleration data to float
posture[1] = (float)int16_array[1] / 16384.0; // convert y-axis acceleration data to float
posture[2] = (float)int16_array[2] / 16384.0; // convert z-axis acceleration data to float
Serial.print("Posture X: ");
Serial.print(posture[0]);
Serial.print(" | Y: ");
Serial.print(posture[1]);
Serial.print(" | Z: ");
Serial.println(posture[2]);
delay(100);
}
这个示例代码通过I2C接口与MPU6886通信,并读取加速度和角速度数据,然后将其转换为浮点数并输出到串口监视器中。在设置中,通过Wire.beginTransmission()和Wire.endTransmission()函数设置MPU6886的地址,并将其重置为默认设置。在循环中,通过Wire.requestFrom()函数从MPU6886请求数据,并将其读取到一个字节数组中。然后,将加速度数据转换为浮点数,并将其存储在一个浮点数数组中,最后将数据输出到串口监视器中。在示例代码中,延迟100毫秒,以便以适当的速率读取传感器数据。
新代码如下:
M5.IMU.getAccel(&ax, &ay, &az); // Read tri-axial accel 读取三轴加速度
M5.IMU.getGyro(&gx, &gy, &gz); // Read gyroscope data 读取陀螺仪数据
M5.IMU.getTemp(&t); // Read temperature data 读取温度数据
具体如何实现?
MPU6886.h
#ifndef __MPU6886_H__
#define __MPU6886_H__
#include <Wire.h>
#define MPU6886_DEFAULT_ADDRESS 0x68
class MPU6886 {
public:
MPU6886(uint8_t deviceAddress = MPU6886_DEFAULT_ADDRESS,
TwoWire& i2cPort = Wire1);
int begin(void);
uint8_t whoAmI();
void getAccel(float* ax, float* ay, float* az);
void getGyro(float* gx, float* gy, float* gz);
void getTemp(float* t);
private:
uint8_t readByte(uint8_t address);
void writeByte(uint8_t address, uint8_t data);
void bitOn(uint8_t address, uint8_t bit);
void bitOff(uint8_t address, uint8_t bit);
TwoWire* _i2cPort;
int _deviceAddress;
};
#endif
MPU6886.c
#include "MPU6886.h"
MPU6886::MPU6886(uint8_t deviceAddress, TwoWire& i2cPort) {
_deviceAddress = deviceAddress;
_i2cPort = &i2cPort;
}
uint8_t MPU6886::readByte(uint8_t address) {
_i2cPort->beginTransmission(_deviceAddress);
_i2cPort->write(address);
_i2cPort->endTransmission();
_i2cPort->requestFrom(_deviceAddress, 1);
uint8_t val = _i2cPort->read();
ESP_LOGD("MPU6886", "readByte(%02X) = %02X", address, val);
return val;
}
void MPU6886::writeByte(uint8_t address, uint8_t data) {
_i2cPort->beginTransmission(_deviceAddress);
_i2cPort->write(address);
_i2cPort->write(data);
_i2cPort->endTransmission();
ESP_LOGD("MPU6886", "writeByte(%02X) = %02X", address, data);
}
void MPU6886::bitOn(uint8_t address, uint8_t bit) {
uint8_t add = address;
uint8_t val = readByte(add) | bit;
writeByte(add, val);
}
void MPU6886::bitOff(uint8_t address, uint8_t bit) {
uint8_t add = address;
uint8_t val = readByte(add) & ~bit;
writeByte(add, val);
}
int MPU6886::begin(void) {
// WHO_AM_I : IMU Check
if (whoAmI() != 0x19) {
return -1;
}
delay(1);
// PWR_MGMT_1(0x6b)
writeByte(0x6b, 0x00);
delay(10);
// PWR_MGMT_1(0x6b)
writeByte(0x6b, 1 << 7);
delay(10);
// PWR_MGMT_1(0x6b)
writeByte(0x6b, 1 << 0);
delay(10);
// ACCEL_CONFIG(0x1c) : +-8G
writeByte(0x1c, 0x10);
delay(1);
// GYRO_CONFIG(0x1b) : +-2000dps
writeByte(0x1b, 0x18);
delay(1);
// CONFIG(0x1a)
writeByte(0x1a, 0x01);
delay(1);
// SMPLRT_DIV(0x19)
writeByte(0x19, 0x05);
delay(1);
// INT_ENABLE(0x38)
writeByte(0x38, 0x00);
delay(1);
// ACCEL_CONFIG 2(0x1d)
writeByte(0x1d, 0x00);
delay(1);
// USER_CTRL(0x6a)
writeByte(0x6a, 0x00);
delay(1);
// FIFO_EN(0x23)
writeByte(0x23, 0x00);
delay(1);
// INT_PIN_CFG(0x37)
writeByte(0x37, 0x22);
delay(1);
// INT_ENABLE(0x38)
writeByte(0x38, 0x01);
delay(100);
return 0;
}
uint8_t MPU6886::whoAmI(void) {
return readByte(0x75);
}
void MPU6886::getAccel(float* ax, float* ay, float* az) {
float aRes = 8.0 / 32768.0;
*ax = (int16_t)((readByte(0x3b) << 8) | readByte(0x3c)) * aRes;
*ay = (int16_t)((readByte(0x3d) << 8) | readByte(0x3e)) * aRes;
*az = (int16_t)((readByte(0x3f) << 8) | readByte(0x40)) * aRes;
}
void MPU6886::getGyro(float* gx, float* gy, float* gz) {
float gRes = 2000.0 / 32768.0;
*gx = (int16_t)((readByte(0x43) << 8) | readByte(0x44)) * gRes;
*gy = (int16_t)((readByte(0x45) << 8) | readByte(0x46)) * gRes;
*gz = (int16_t)((readByte(0x47) << 8) | readByte(0x48)) * gRes;
}
void MPU6886::getTemp(float* t) {
*t = 25.0 + ((readByte(0x41) << 8) | readByte(0x42)) / 326.8;
}
都是一些固定流程。底层代码类似驱动,规范性是很重要的。
下段代码是一个使用ESP32-S3开发板的程序,通过连接M5AtomS3库来进行传感器数据的读取和显示。
代码主要包括两个函数:setup()
和loop()
。
setup()
函数是程序启动后首先执行的函数,它进行一些初始化的操作,包括初始化AtomS3(LCD和串口)和IMU传感器,然后延迟100毫秒,最后通过USB串口输出IMU传感器的信息。
loop()
函数是一个死循环,其中的程序会不断的重复运行。在每次循环中,程序通过M5AtomS3库的函数读取IMU传感器的数据,包括三轴加速度、陀螺仪数据和温度数据。然后通过USB串口输出这些数据,并在LCD屏幕上显示IMU传感器的信息,包括加速度、陀螺仪和温度。每次循环后,程序会延迟20毫秒。
整体来说,这段代码的功能是不断读取并显示IMU传感器的数据,包括加速度、陀螺仪和温度,并通过串口输出。同时,它还在LCD屏幕上显示了IMU传感器的信息。
#include "M5AtomS3.h"
/* After AtomS3 is started or reset the program in the setUp ()
function will be run, and this part will only be run once.
在 AtomS3 启动或者复位后,即会开始执行setup()函数中的程序,该部分只会执行一次。
*/
void setup() {
M5.begin(true, true, true,
false); // Init AtomS3(Initialize LCD, serial port).
// 初始化 AtomS3(初始化LCD、串口)
M5.IMU.begin(); // Init IMU sensor. 初始化姿态传感器
M5.Lcd.clear(); // Delay 100ms 延迟100ms
USBSerial.printf("whoAmI() = 0x%02x\n", M5.IMU.whoAmI());
}
/* After the program in setup() runs, it runs the program in loop()
The loop() function is an infinite loop in which the program runs repeatedly
在setup()函数中的程序执行完后,会接着执行loop()函数中的程序
loop()函数是一个死循环,其中的程序会不断的重复运行 */
float ax, ay, az, gx, gy, gz, t;
void loop() {
M5.Lcd.setCursor(0, 40);
M5.IMU.getAccel(&ax, &ay, &az); // Read tri-axial accel 读取三轴加速度
M5.IMU.getGyro(&gx, &gy, &gz); // Read gyroscope data 读取陀螺仪数据
M5.IMU.getTemp(&t); // Read temperature data 读取温度数据
USBSerial.printf("%f,%f,%f,%f,%f,%f,%f\n", ax, ay, az, gx, gy, gz,
t); // serial port output the formatted string. 串口输出
M5.Lcd.printf("IMU:Accel\r\n");
M5.Lcd.printf("%0.2f %0.2f %0.2f\r\n", ax, ay, az);
M5.Lcd.printf("IMU:Gyro\r\n");
M5.Lcd.printf("%0.2f %0.2f %0.2f\r\n", gx, gy, gz);
M5.Lcd.printf("IMU:Temp\r\n");
M5.Lcd.printf("%0.2f \r\n", t);
delay(20);
}
为何做这样的修改呢?其实串口部分代码也可以去掉。
很明显温度等不太合适嘛?
AI给出注意事项如下:
在使用MPU6886传感器连接到ESP32单片机时,需要注意以下事项:
以上是使用MPU6886连接到ESP32单片机时的一些注意事项。根据具体应用和硬件配置,可能还有其他需要注意的事项。建议参考相关文档和资料,以确保正确和可靠的使用。
MPU6886和MPU6050都是六轴惯性测量单元(IMU),用于测量姿态、加速度和角速度等运动参数。它们的主要区别在于芯片结构和连接方式。
MPU6886采用I2C接口,内置了3轴加速度计和3轴陀螺仪,并提供了数字运动处理器(DMP)和可编程数字滤波器。它采用2.5V至5.5V的电源供应,具有低功耗模式,并支持快速唤醒。MPU6886的主要特点包括高精度、低功耗、快速启动和低噪声。
MPU6050是一个整合感应器,内含3轴加速度计和3轴陀螺仪,采用I2C接口。它具有131 LSBs/°的角速度全格感测范围,并内置了数字运动处理器(DMP)。MPU6050的工作电压为2.5V至5.5V,具有低功耗模式,并能唤醒快速。主要特点包括高精度、低功耗、快速启动和低噪声。
总体而言,MPU6886和MPU6050在功能和性能上非常相似,都具有高精度、低功耗、快速启动和低噪声等特点。主要区别在于连接方式和芯片结构。具体选择哪个取决于具体应用的需求和预算。
ESP32-S3是一款基于Xtensa LX7架构的32位Wi-Fi SoC,具有高性能和低功耗的特点。它集成了2.4 GHz Wi-Fi、蓝牙和NFC功能,并提供了丰富的外设接口,如SD卡接口、ADC、DAC、SPI、I2C、UART等。ESP32-S3还支持神经网络加速器和TensorFlow Lite,可用于机器学习和人工智能应用。
以下是ESP32-S3的一些主要特点:
ESP32-S3适用于各种物联网应用,如智能家居、智能城市、智能医疗、工业自动化等。它具有高性能、低功耗和丰富的外设接口,可为各种应用提供可靠的解决方案。