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ố Sampling | 4Hz ~ 1kHz |
| Điện áp nguồn | 3.3V (giới hạn 3.9V) |
| Protocols | I2C (địa chỉ mặc định 0x68/0x69) |
| Nhiệt độ làm việc | -40℃ ~ 85℃ |
| Cảm biến tích hợp | Cả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 ý |
|---|---|---|
| VCC | Nguồn vào | Chỉ accepts 3.3V, đấu 5V sẽ hỏng |
| GND | Địa | Phải接地 chung với main controller |
| SDA | Chân dữ liệu I2C | Đấu với chân SDA của Arduino (A4) |
| SCL | Chân时钟 I2C | Đấu với chân SCL của Arduino (A5) |
| AD0 | Chân chọn địa chỉ | Đấu接地 = 0x68 (mặc định), đấu VCC = 0x69 |
| INT | Chân output interrupt | Output高电平 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 |
|---|---|---|
| VCC | 3.3V | Không đấu 5V! Module không có LDO sẽ hỏng |
| GND | GND | Giảm nhiễu dữ liệu |
| SDA | A4 | Chân dữ liệu I2C |
| SCL | A5 | Chân时钟 I2C |
| AD0 | GND | Chọn địa chỉ mặc định 0x68 |
| INT | Khô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