目录
MPU6050传感器——姿态检测
1.姿态检测
1.1 基本认识
1)坐标系
2)姿态角的关系
3)陀螺仪检测的缺陷
4)利用加速度计检测角度
5)利用磁场检测角度
1.2 姿态融合与四元数
1.3传感器工作原理
1.4 MPU6050模块简介
1.5 实践是检验真理的唯一标准
1.5.1 连接引脚确认
1.5.2 代码编写调试并运行
MPU6050传感器——姿态检测
1.姿态检测
1.1 基本认识
1)坐标系
分为载体坐标系、地理坐标系和地球坐标系
载体坐标系:以运载体的质心为原点,一般根据运载体自身结构方向构成坐标系
地理坐标系:原点在地球表面,Z轴沿当地地理垂涎的方向,XY轴沿当地经纬线的切线方向。
地球坐标系:以地球球心为原点,Z轴沿地球自转轴方向,XY轴在赤道平面内的坐标系
2)姿态角的关系
偏航角、俯仰角和横滚角
3)陀螺仪检测的缺陷
陀螺仪测量角度时需要使用积分,会存在一定的积分误差。而根据积分的性质可知,积分时间越小,误差就越小。所以可以用提高陀螺仪传感器的采样频率来减少积分误差。
4)利用加速度计检测角度
一般使用加速度传感器来检测倾角,通过检测器件在各个方向的形变情况而采样得到受力数据,根据F=ma转换,传感器直接输出加速度数据。
而在加速度传感器静止的时候,测出来的是加速度g,表示传感器在该方向作加速度为g的运动
那么是如何检测陀螺仪测出来的角度是否正确呢?
利用各方向的测量结果,根据力的分解原理,可以求出各个坐标轴与重力之间的夹角。因为重力方向是与地理坐标系的“天地”轴固连的,所以通过测量载体坐标系各轴与重力方向的角度即可修正角度
5)利用磁场检测角度
为了弥补加速度传感器无法检测偏航角的问题,通过检测地球磁场可实现指南针的功能。由于地磁场与地理坐标系的南北轴固联,利用磁场检测传感器的指南针功能
1.2 姿态融合与四元数
我们同时使用这两种传感器,并设计一个滤波算法,当物体处于静止状态时,增大加速度数据的权重,当物体处于运动状时,增大陀螺仪数据的权重,从而获得更准确的姿态数据。同理,检测偏航角,当载体在静止状态时,可增大磁场检测器数据的权重,当载体在运动状态时,增大陀螺仪和GPS检测数据的权重。这些采用多种传感器数据来检测姿态的处理算法被称为姿态融合。
1.3传感器工作原理
敏感元件:直接感受被测物理量,并输出与该物理量有确定关系的信号
转换原件:将物理信号转换为电信号量
变换电路:对转换元件输出的电信号进行放大调制,最后输出容易检测的电信号量
1.4 MPU6050模块简介
功能:检测三轴加速度、三轴陀螺仪的运动数据以及温度数据
引脚说明:
如何使用MPU6050传输和计算数据?
可以使用STM32控制器把这些数据读取出来然后进行姿态融合解算,以求出传感器当前的姿态。
也可以使用传感器内部的DMP单元进行解算,可以直接对采样得到的加速度及角速度进行姿态解算。
1.5 实践是检验真理的唯一标准
1.5.1 连接引脚确认
我首先查了MPU每个引脚具体该怎么连接ESP32,在这个博客中看到了这样一句话:
“使用的是IO19与IO20两个引脚,使用杜邦线将开发板的这两个引脚分别接到mpu6050模块的SCL与SDA引脚上,将ADO引脚接到GND。
ADO引脚为从机地址设置引脚,接地或悬空时, 地址为: 0x68;接VCC时,地址为:0x69”
而该博主用的是ESP32-S3-LCD-EV-Board-MB开发板,所以我搜了一下他的引脚:
根据ESP32-DevKitc-1的引脚说明书,找到符合I2C协议的引脚。
得出结论:
名称为21的引脚连接MPU6050的SCL,名称为20连接MPU6050的SDA
1.5.2 代码编写调试并运行
调试代码教程:
烧录的时候出现了以下错误:
结果是自己电脑端口出现了问题...在别人电脑上却能跑通。
点击调试和运行运行代码:
#include <Wire.h>
#include <MPU6050.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#define SDA_PIN 21
#define SCL_PIN 22
MPU6050 mpu6050(0x68); // 使用默认地址 0x68
unsigned long last_sample_time = 0;
int peak_count = 0;
bool condition_met = false;
int16_t ax,ay,az,gx,gy,gz;
void setup() {
Serial.begin(115200);
Wire.begin(SDA_PIN, SCL_PIN);
// 校准陀螺仪偏移
mpu6050.setXGyroOffset(220);
mpu6050.setYGyroOffset(76);
mpu6050.setZGyroOffset(-85);
last_sample_time = millis();
}
void loop() {
mpu6050.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
// 将原始数据转换为实际值
float ax_g = ax * 2.0 / 32768.0;
float ay_g = ay * 2.0 / 32768.0;
float az_g = az * 2.0 / 32768.0;
float gx_rad = gx * 250.0 / 32768.0 * 0.0174533;
float gy_rad = gy * 250.0 / 32768.0 * 0.0174533;
float gz_rad = gz * 250.0 / 32768.0 * 0.0174533;
// 检查加速度是否超过阈值
if (abs(ax_g) > 1.0 || abs(ay_g) > 1.0 || abs(az_g) > 1.0) {
peak_count++;
}
// 检查是否达到采样周期
unsigned long current_time = millis();
if (current_time - last_sample_time >= 1000) { // 1秒采样一次
// 计算峰值频率
float peak_frequency = (peak_count * 60.0) / (current_time - last_sample_time);
peak_count = 0;
// 检查峰值频率是否在指定范围内
if (peak_frequency >= 100 && peak_frequency <= 120) {
condition_met = true;
}
last_sample_time = current_time;
// 如果条件满足,发送完成信息到后端
if (condition_met) {
sendCompletionToBackend(ax_g, ay_g, az_g, gx_rad, gy_rad, gz_rad);
condition_met = false;
}
}
// 打印数据
Serial.print("ax: ");
Serial.print(ax_g);
Serial.print(" g\t");
Serial.print("ay: ");
Serial.print(ay_g);
Serial.print(" g\t");
Serial.print("az: ");
Serial.print(az_g);
Serial.print(" g\t");
Serial.print("gx: ");
Serial.print(gx_rad);
Serial.print(" rad/s\t");
Serial.print("gy: ");
Serial.print(gy_rad);
Serial.print(" rad/s\t");
Serial.print("gz: ");
Serial.println(gz_rad);
Serial.print("\n");
delay(10); // 避免循环过快
}
void sendCompletionToBackend(float ax, float ay, float az, float gx, float gy, float gz) {
Serial.println("Sending data to backend...");
// 连接WiFi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// 创建HTTP客户端请求
HTTPClient http;
http.begin(serverUrl);
http.addHeader("Content-Type", "application/json");
// 构建JSON数据
StaticJsonDocument<200> jsonDoc; // 根据需要调整JSON文档的大小
jsonDoc["ax"] = ax;
jsonDoc["ay"] = ay;
jsonDoc["az"] = az;
jsonDoc["gx"] = gx;
jsonDoc["gy"] = gy;
jsonDoc["gz"] = gz;
String jsonData;
serializeJson(jsonDoc, jsonData); // 序列化JSON
// 发送POST请求
int httpResponseCode = http.POST(jsonData);
if (httpResponseCode > 0) {
String response = http.getString();
Serial.println("Response from server: ");
Serial.println(response);
} else {
Serial.println("Error on sending POST request");
}
http.end();
}