Hướng dẫn đầy đủ về MPU6050: Từ đấu dây đến giải thuật tư thế

1. Giới thiệu

MPU6050 là một bộ cảm biến chuyển động 6 trục tích hợp cảm biến gia tốc 3 trục và cảm biến gyro 3 trục. Với ưu điểm giá rẻ, kích thước nhỏ và tích hợp cao, MPU6050 trở thành lựa chọn hàng đầu cho các dự án IoT, robot và thiết bị đeo. Bộ cảm biến này hỗ trợ giao tiếp I2C và cung cấp dữ liệu chuyển động chính xác, cho phép đo gia tốc, tốc độ góc và tính toán các góc nghiêng như Pitch và Roll.

Bài viết này sẽ hướng dẫn chi tiết cách sử dụng MPU6050 trên nền tảng Arduino, bao gồm các phần như: kiến trúc硬件, đấu dây, sử dụng thư viện, đọc dữ liệu trực tiếp và tính toán tư thế. Nội dung phù hợp cho cả người mới bắt đầu và các developer có kinh nghiệm.

2. Thông số kỹ thuật và kiến trúc hardware

2.1. Thông số chính

Tính năng Thông số
Bán kính gia tốc±2G/±4G/±8G/±16G (cài đặt được)
Bán kính gyro±250°/s/±500°/s/±1000°/s/±2000°/s (cài đặt được)
Tần số Sampling4Hz ~ 1kHz
Điện áp nguồn3.3V (giới hạn 3.9V)
ProtocolsI2C (địa chỉ mặc định 0x68/0x69)
Nhiệt độ làm việc-40℃ ~ 85℃
Cảm biến tích hợpCảm biến gia tốc (ADC 16 bit), Cảm biến gyro (ADC 16 bit), Cảm biến nhiệt

2.2. Định nghĩa chân接线

Chân cảm biến Chức năng Lưu ý
VCCNguồn vàoChỉ accepts 3.3V, đấu 5V sẽ hỏng
GNDĐịaPhải接地 chung với main controller
SDAChân dữ liệu I2CĐấu với chân SDA của Arduino (A4)
SCLChân时钟 I2CĐấu với chân SCL của Arduino (A5)
AD0Chân chọn địa chỉĐấu接地 = 0x68 (mặc định), đấu VCC = 0x69
INTChân output interruptOutput高电平 khi dữ liệu sẵn sàng

3. Chuẩn bị hardware và đấu dây

3.1. Thành phần cần thiết

  • Bo mạch chủ: Arduino UNO/Nano hoặc ESP32, STM32
  • Module MPU6050 (ưu tiên module có convert电压)
  • Đầu nối Dupont: 4-6 sợi
  • Ban nhạc (tùy chọn): thuận tiện cho việc đấu dây
  • Nguồn 5V (tùy chọn): phải đảm bảo nguồn 3.3V ổn định

3.2. Table đấu dây (ví dụ với Arduino UNO)

Chân MPU6050 Chân Arduino Giải thích
VCC3.3VKhông đấu 5V! Module không có LDO sẽ hỏng
GNDGNDGiảm nhiễu dữ liệu
SDAA4Chân dữ liệu I2C
SCLA5Chân时钟 I2C
AD0GNDChọn địa chỉ mặc định 0x68
INTKhông đấu / bất kỳ chân kỹ thuật sốTùy chọn sử dụng chức năng中断

Lưu ý: Với ESP32, SDA=GPIO21 và SCL=GPIO22. Đối với STM32, cần kiểm tra chân I2C theo model cụ thể (ví dụ STM32F103c8t6: SDA=PB7, SCL=PB6).

4. Thực hiện driver code (3 phương án)

Phương án 1: Sử dụng thư viện Adafruit (phù hợp cho người mới)

Bước 1: Install thư viện

Mở Arduino IDE → Sketch → Include Library → Manage Libraries:

  • Tìm và cài đặt "Adafruit MPU6050"
  • Tìm và cài đặt "Adafruit Unified Sensor"

Bước 2: Code mẫu đọc dữ liệu:


#include 
#include 

Adafruit_MPU6050 sensor; // Khởi tạo object cảm biến

void setup() {
    Serial.begin(115200);
    while (!Serial) delay(10);
    
    if (!sensor.begin()) {
        Serial.println("Không tìm thấy MPU6050! Kiểm tra:");
        Serial.println("1. Điện áp VCC phải 3.3V");
        Serial.println("2. Địa chỉ MPU6050 là 0x68");
        
        while (1) {
            delay(500);
            digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
        }
    }
    
    Serial.println("MPU6050 đã khởi động!");
    sensor.setAccelerometerRange(MPU6050_RANGE_8_G);
    sensor.setGyroRange(MPU6050_RANGE_500_DEG);
    sensor.setFilterBandwidth(MPU6050_BAND_44_HZ);
    delay(100);
}

void loop() {
    sensors_event_t a, g, temp;
    sensor.getEvent(&a, &g, &temp);
    
    Serial.print("Gia tốc [m/s²]: X: "); Serial.print(a.acceleration.x, 2);
    Serial.print(", Y: "); Serial.print(a.acceleration.y, 2);
    Serial.print(", Z: "); Serial.print(a.acceleration.z, 2);
    
    Serial.print(" | Gyro [rad/s]: X: "); Serial.print(g.gyro.x, 2);
    Serial.print(", Y: "); Serial.print(g.gyro.y, 2);
    Serial.print(", Z: "); Serial.print(g.gyro.z, 2);
    
    Serial.print(" | Nhiệt độ: "); Serial.print(temp.temperature, 1); Serial.println("℃");
    delay(200);
}

Phương án 2: Đọc dữ liệu trực tiếp từ寄存器

Code mẫu:


#include 

#define MPU6050_ADDR 0x68
#define PWR_MGMT_1 0x6B
#define ACCEL_XOUT_H 0x3B
#define GYRO_XOUT_H 0x43

int16_t giaTocX, giaTocY, giaTocZ;
int16_t gyroX, gyroY, gyroZ;
float temperature;

void kiemTraMPU6050() {
    Wire.begin();
    Wire.beginTransmission(MPU6050_ADDR);
    Wire.write(PWR_MGMT_1);
    Wire.write(0x00);
    Wire.endTransmission();
    
    // Cấu hình gia tốc
    Wire.beginTransmission(MPU6050_ADDR);
    Wire.write(0x1C);
    Wire.write(0x10);
    Wire.endTransmission();
    
    // Cấu hình gyro
    Wire.beginTransmission(MPU6050_ADDR);
    Wire.write(0x1B);
    Wire.write(0x08);
    Wire.endTransmission();
}

void docDuLieu() {
    Wire.beginTransmission(MPU6050_ADDR);
    Wire.write(ACCEL_XOUT_H);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU6050_ADDR, 14);
    
    giaTocX = Wire.read() << 8 | Wire.read();
    giaTocY = Wire.read() << 8 | Wire.read();
    giaTocZ = Wire.read() << 8 | Wire.read();
    
    temperature = (Wire.read() << 8 | Wire.read()) / 340.0 + 36.53;
    
    gyroX = Wire.read() << 8 | Wire.read();
    gyroY = Wire.read() << 8 | Wire.read();
    gyroZ = Wire.read() << 8 | Wire.read();
    
    float giaTocXThuc = giaTocX / 4096.0;
    float giaTocYThuc = giaTocY / 4096.0;
    float giaTocZThuc = giaTocZ / 4096.0;
    
    float gyroXThuc = gyroX / 65.5;
    float gyroYThuc = gyroY / 65.5;
    float gyroZThuc = gyroZ / 65.5;
    
    Serial.print("Gia tốc [g]: X: "); Serial.print(giaTocXThuc, 2);
    Serial.print(", Y: "); Serial.print(giaTocYThuc, 2);
    Serial.print(", Z: "); Serial.print(giaTocZThuc, 2);
    
    Serial.print(" | Gyro [°/s]: X: "); Serial.print(gyroXThuc, 2);
    Serial.print(", Y: "); Serial.print(gyroYThuc, 2);
    Serial.print(", Z: "); Serial.print(gyroZThuc, 2);
    
    Serial.print(" | Nhiệt độ: "); Serial.print(temperature, 1); Serial.println("℃");
}

void setup() {
    Serial.begin(115200);
    kiemTraMPU6050();
    Serial.println("MPU6050 đã khởi động!");
}

void loop() {
    docDuLieu();
    delay(200);
}

Phương án 3: Tính toán tư thế bằng bộ lọc Kalman

Code mẫu:


#include 
#include 

Adafruit_MPU6050 sensor;
sensors_event_t a, g, temp;

float Q_angle = 0.001;
float Q_gyro = 0.003;
float R_angle = 0.5;
float angle = 0.0;
float bias = 0.0;
float P[2][2] = {{1, 0}, {0, 1}};

float kiemTraAttitude(float angleMeasure, float gyroMeasure, float deltaTime) {
    float anglePredict = angle - bias * deltaTime;
    float P_predict[2][2] = {
        {P[0][0] + Q_angle - P[0][1] * P[1][0] / (P[1][1] + Q_gyro), -P[0][1] / (P[1][1] + Q_gyro)},
        {-P[1][0] / (P[1][1] + Q_gyro), P[1][1] + Q_gyro}
    };
    
    float K[2] = {
        P_predict[0][0] / (P_predict[0][0] + R_angle),
        P_predict[1][0] / (P_predict[0][0] + R_angle)
    };
    
    angle = anglePredict + K[0] * (angleMeasure - anglePredict);
    bias = bias + K[1] * (angleMeasure - anglePredict);
    
    float P_update[2][2] = {
        {(1 - K[0]) * P_predict[0][0], (1 - K[0]) * P_predict[0][1]},
        {(1 - K[1]) * P_predict[1][0], P_predict[1][1] + K[1] * P_predict[0][0]}
    };
    
    P[0][0] = P_update[0][0];
    P[0][1] = P_update[0][1];
    P[1][0] = P_update[1][0];
    P[1][1] = P_update[1][1];
    
    return angle;
}

void setup() {
    Serial.begin(115200);
    while (!Serial) delay(10);
    
    if (!sensor.begin()) {
        Serial.println("Không tìm thấy MPU6050!");
        while (1) delay(500);
    }
    
    sensor.setAccelerometerRange(MPU6050_RANGE_8_G);
    sensor.setGyroRange(MPU6050_RANGE_500_DEG);
    sensor.setFilterBandwidth(MPU6050_BAND_44_HZ);
    delay(100);
}

void loop() {
    static unsigned long lastTime = millis();
    unsigned long currentTime = millis();
    float deltaTime = (currentTime - lastTime) / 1000.0;
    lastTime = currentTime;
    
    sensor.getEvent(&a, &g, &temp);
    
    float pitchMeasure = atan2(a.acceleration.x, a.acceleration.z) * 180 / PI;
    float pitchGyro = g.gyro.y * deltaTime;
    
    float pitchFiltered = kiemTraAttitude(pitchMeasure, pitchGyro, deltaTime);
    
    Serial.print("Góc nghiêng thô: "); Serial.print(pitchMeasure, 1);
    Serial.print("° | Góc nghiêng lọc: "); Serial.print(pitchFiltered, 1);
    Serial.println("°");
    delay(50);
}

5. Giải pháp cho các vấn đề thường gặp

  • Không nhận diện được MPU6050: Kiểm tra điện áp VCC, chân I2C và địa chỉ MPU6050
  • Dữ liệu rung lắc: Tăng band filter, cố định cảm biến và kiểm tra nhiễu môi trường
  • Giá trị Z trục gia tốc không chính xác: Calibrate cảm biến và kiểm tra cài đặt ban kính
  • Chức năng中断 không hoạt động: Kiểm tra chân INT và cấu hình寄存器errupt

6.Ứng dụng nâng cao và mở rộng

  • Ứng dụng điển hình: Kiểm soát UAV, điều khiển体感, đếm bước đi, phát hiện rung động
  • Xuất khẩu đến các platform khác: ESP32, STM32, Raspberry Pi
  • Mở rộng chức năng: Thêm cảm biến HMC5883L cho 9 trục, lưu trữ dữ liệu, tối ưu low power

Thẻ: Arduino MPU6050 Cảm biến gyro Cảm biến gia tốc Tính toán tư thế

Đăng vào ngày 1 tháng 6 lúc 03:00