Edge Impulse với ESP32: thu dữ liệu MPU6050, huấn luyện nhận dạng cử chỉ, xuất thư viện Arduino

Quy trình Edge Impulse với ESP32 và MPU6050: gửi dữ liệu gia tốc qua data forwarder, gắn nhãn, cửa sổ và đặc trưng phổ, đọc ma trận nhầm lẫn, xuất thư viện Arduino và chạy nhận dạng cử chỉ.

Edge Impulse là dịch vụ web làm trọn quy trình TinyML: thu dữ liệu từ cảm biến, gắn nhãn, trích đặc trưng, huấn luyện, kiểm thử và xuất mô hình thành thư viện Arduino chạy trên vi điều khiển. Bài này đi qua toàn bộ quy trình với bài toán nhận dạng ba cử chỉ (đứng yên, lắc ngang, vẽ vòng tròn) bằng cảm biến gia tốc MPU6050 và ESP32: chương trình gửi dữ liệu lên máy tính, cách thiết kế "impulse", đọc kết quả huấn luyện, và đoạn code chạy mô hình trên ESP32.

1. Quy trình

Sáu bước: thu dữ liệu ESP32 gửi ax, ay, az qua data forwarder; gắn nhãn mỗi cử chỉ vài phút, chia tập học, tập thử; thiết kế impulse cửa sổ 2 giây, đặc trưng phổ, khối phân loại; huấn luyện xem độ chính xác, ma trận nhầm lẫn; kiểm thử; xuất thư viện Arduino bản lượng tử hóa int8
Bước 1 dùng chương trình kèm bài; bước 2–6 làm trên trang web của Edge Impulse.

Edge Impulse có gói dùng miễn phí cho cá nhân, cần tạo tài khoản; điều khoản và giao diện có thể thay đổi theo thời gian, xem trang chính thức của dịch vụ. Dữ liệu cảm biến sẽ được tải lên máy chủ của họ.

2. Nối MPU6050

Sơ đồ: MPU6050 VCC nối 3V3, GND nối GND, SCL nối D22, SDA nối D21 của ESP32 DevKit V1
MPU6050 giao tiếp I2C, địa chỉ 0x68.

MPU6050 có cảm biến gia tốc 3 trục và con quay 3 trục; bài này chỉ dùng gia tốc. Cố định cảm biến thật chắc vào vật cần nhận cử chỉ, vì cảm biến lỏng tạo dữ liệu nhiễu. Cần thêm ESP32 DevKit V1, breadboard và dây cắm.

3. Thu dữ liệu

Chương trình dưới đây đọc thẳng thanh ghi gia tốc của MPU6050 qua I2C (không cần thư viện), đổi ra m/s² và in đúng 100 dòng mỗi giây, mỗi dòng ba số cách nhau dấu phẩy. Cách đọc thanh ghi I2C: xem I2C là gì.

// PYWORLD.VN - Gửi dữ liệu gia tốc MPU6050 lên máy tính 100 lần mỗi giây cho công cụ data forwarder của Edge Impulse
// PYWORLD.VN - Đọc thẳng thanh ghi MPU6050 qua I2C, không dùng thư viện; mỗi dòng: ax,ay,az (m/s2)
// PYWORLD.VN - Nối: VCC -> 3V3, GND -> GND, SCL -> GPIO22, SDA -> GPIO21

#include <Wire.h>

const uint8_t DIA_CHI_MPU = 0x68;      // chân AD0 nối GND
const uint8_t PWR_MGMT_1 = 0x6B;
const uint8_t ACCEL_CONFIG = 0x1C;
const uint8_t ACCEL_XOUT_H = 0x3B;
const float LSB_MOI_G = 16384.0f;      // thang ±2 g
const float G = 9.80665f;
const uint32_t CHU_KY_US = 10000;      // 100 Hz

uint32_t lucMau = 0;

void ghiThanhGhi(uint8_t thanhGhi, uint8_t giaTri) {
  Wire.beginTransmission(DIA_CHI_MPU);
  Wire.write(thanhGhi);
  Wire.write(giaTri);
  Wire.endTransmission();
}

bool docGiaToc(float &ax, float &ay, float &az) {
  Wire.beginTransmission(DIA_CHI_MPU);
  Wire.write(ACCEL_XOUT_H);
  if (Wire.endTransmission(false) != 0) return false;   // giữ đường truyền để đọc tiếp
  if (Wire.requestFrom(DIA_CHI_MPU, (uint8_t)6) != 6) return false;
  int16_t x = (Wire.read() << 8) | Wire.read();           // byte cao trước
  int16_t y = (Wire.read() << 8) | Wire.read();
  int16_t z = (Wire.read() << 8) | Wire.read();
  ax = x / LSB_MOI_G * G;
  ay = y / LSB_MOI_G * G;
  az = z / LSB_MOI_G * G;
  return true;
}

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22, 400000);
  ghiThanhGhi(PWR_MGMT_1, 0x00);     // đánh thức MPU6050 (mặc định đang ngủ)
  ghiThanhGhi(ACCEL_CONFIG, 0x00);   // thang ±2 g
  delay(100);
  lucMau = micros();
}

void loop() {
  if (micros() - lucMau < CHU_KY_US) return;
  lucMau += CHU_KY_US;                // giữ nhịp đều, không trôi
  float ax, ay, az;
  if (docGiaToc(ax, ay, az)) {
    Serial.printf("%.3f,%.3f,%.3f\n", ax, ay, az);
  }
}
Serial Monitor in các dòng ba số như -0.120,0.041,9.703: ax, ay, az đơn vị m/s2, 100 dòng mỗi giây; khi đứng yên az khoảng 9,81
Định dạng dữ liệu gửi lên máy tính (số là ví dụ).
  1. Cài Node.js, rồi cài bộ công cụ dòng lệnh của Edge Impulse: npm install -g edge-impulse-cli.
  2. Đóng Serial Monitor (để nhả cổng COM), chạy edge-impulse-data-forwarder, đăng nhập, chọn dự án, đặt tên ba trục là ax, ay, az. Công cụ tự nhận tần số 100 Hz.
  3. Trên trang dự án, mục thu dữ liệu: chọn nhãn (ví dụ "lac ngang"), độ dài mẫu (ví dụ 10 giây), bấm bắt đầu rồi làm cử chỉ. Mỗi nhãn thu vài phút, từ nhiều lần làm khác nhau.
  4. Chia khoảng 80% dữ liệu để học, 20% để thử.

4. Thiết kế impulse

Ba đồ thị gia tốc ax, ay, az của đứng yên gần phẳng, lắc ngang dao động mạnh trục x, vẽ vòng tròn dao động đều trục x và y; khung tím là cửa sổ 2 giây và cửa sổ sau dời 0,5 giây
Dữ liệu tổng hợp để minh họa cửa sổ trượt.
  • Cửa sổ thời gian (window size): 2000 ms, đủ dài để chứa vài nhịp cử chỉ. Bước dời (window increase): ví dụ 500 ms, các cửa sổ chồng lên nhau để có nhiều mẫu học hơn.
  • Khối xử lý: phân tích phổ (Spectral Analysis), biến 200 mẫu × 3 trục thành vài chục đặc trưng.
  • Khối học: phân loại (Classification), một mạng nơ-ron nhỏ.
Bảng đặc trưng: đứng yên RMS khoảng 0,14 trên mọi trục, tần số không rõ; lắc ngang RMS ax 5,66 tần số 3 Hz; vẽ vòng tròn RMS ax và ay khoảng 2,8, tần số 1,5 Hz
Đặc trưng tính bằng FFT trên tín hiệu tổng hợp ở hình trên.

Bảng đặc trưng cho thấy vì sao mạng học được: mỗi cử chỉ có "dấu vân tay" riêng về độ lớn dao động và tần số. Muốn hiểu bên trong khối phân loại, xem bài tự huấn luyện mạng nơ-ron nhỏ trong cùng loạt.

5. Huấn luyện và đọc kết quả

Ma trận nhầm lẫn ví dụ: đứng yên đoán đúng 96 phần trăm, lắc ngang 93 phần trăm nhầm sang vẽ vòng tròn 6 phần trăm, vẽ vòng tròn 92 phần trăm nhầm sang lắc ngang 8 phần trăm
Số liệu là ví dụ cách đọc, không phải kết quả huấn luyện thật.

Sau khi huấn luyện, trang dự án hiện độ chính xác và ma trận nhầm lẫn: hàng là cử chỉ thật, cột là mô hình đoán. Đường chéo càng cao càng tốt; ô ngoài đường chéo lớn cho biết hai cử chỉ hay bị nhầm. Khi đó: thu thêm dữ liệu cho hai cử chỉ đó, làm cử chỉ khác nhau rõ hơn, hoặc kéo dài cửa sổ. Luôn kiểm thử thêm trên dữ liệu chưa dùng để học (mục kiểm thử) trước khi xuất thư viện.

6. Xuất thư viện và chạy trên ESP32

  1. Mục triển khai: chọn Arduino library, bản lượng tử hóa int8, tải file .zip.
  2. Arduino IDE: Sketch → Include Library → Add .ZIP Library, chọn file vừa tải.
  3. Viết chương trình: thu đủ một cửa sổ mẫu với đúng tần số lúc thu dữ liệu, rồi gọi hàm phân loại của thư viện.

Đoạn code dưới đây dùng hàm đọc gia tốc của chương trình thu dữ liệu ở trên. Tên file thư viện do Edge Impulse đặt theo tên dự án; các hằng số EI_CLASSIFIER_… nằm trong thư viện đó nên đoạn này chỉ biên dịch được sau khi đã thêm thư viện của dự án bạn:

#include <ten_du_an_inferencing.h>   // đổi theo tên thư viện Edge Impulse xuất cho dự án của bạn

float bangMau[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE];   // đủ một cửa sổ: số mẫu × 3 trục

void nhanDangCuChi() {
  for (size_t i = 0; i < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; i += 3) {
    uint32_t hanChot = micros() + (uint32_t)(EI_CLASSIFIER_INTERVAL_MS * 1000);
    docGiaToc(bangMau[i], bangMau[i + 1], bangMau[i + 2]);
    while ((int32_t)(micros() - hanChot) < 0) {}      // giữ đúng 100 Hz như lúc thu dữ liệu
  }
  signal_t tinHieu;
  numpy::signal_from_buffer(bangMau, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &tinHieu);
  ei_impulse_result_t ketQua = {0};
  if (run_classifier(&tinHieu, &ketQua, false) != EI_IMPULSE_OK) return;
  for (size_t k = 0; k < EI_CLASSIFIER_LABEL_COUNT; k++) {
    Serial.printf("%s: %.2f\n", ketQua.classification[k].label, ketQua.classification[k].value);
  }
}

Gọi nhanDangCuChi() trong loop() (sau khi đã khởi động MPU6050 như chương trình thu dữ liệu). Mỗi lần gọi mất khoảng 2 giây để thu cửa sổ, cộng thời gian suy luận vài chục mili giây. Chỉ coi kết quả là chắc khi xác suất cao (ví dụ trên 0,8).

7. Lỗi hay gặp

Hiện tượngNguyên nhân thường gặpCách xử lý
Data forwarder không thấy dữ liệuSerial Monitor còn mở, sai tốc độ baudĐóng Serial Monitor; dùng 115200
Tần số nhận ra khác 100 HzIn thêm dòng chữ khác, vòng lặp chậmChỉ in dòng số; giữ nhịp bằng micros()
Đọc toàn 0 hoặc lỗi I2CSai dây SDA/SCL, MPU6050 chưa được đánh thứcKiểm tra dây, ghi 0 vào thanh ghi 0x6B
Huấn luyện tốt, chạy thật đoán saiTần số lấy mẫu, cách gắn cảm biến khác lúc thuGiữ nguyên tần số, vị trí, hướng cảm biến
Hai cử chỉ hay nhầmDữ liệu ít, cử chỉ giống nhauThêm dữ liệu, chọn cử chỉ khác biệt hơn

8. Xem thêm

  • Các bài cùng loạt AI trên vi điều khiển: TinyML là gì, tự huấn luyện mạng nơ-ron nhỏ chạy trên ESP32, nhận lệnh giọng nói bằng ESP-SR.

Tin tức liên quan

Thực hành hiệu chuẩn thước điện trở bằng căn mẫu với ADS1115, ESP32: đo tỉ lệ, độ tuyến tính, độ trễ
Thực hành hiệu chuẩn thước điện trở bằng căn mẫu với ADS1115, ESP32: đo tỉ lệ, độ tuyến tính, độ trễ

Hiệu chuẩn thước điện trở 50 mm bằng chồng căn mẫu: ADS1115 đo tỉ lệ, ESP32 ghi điểm đi lên và đi xuống, khớp đa thức, tính sai số tuyến tính, độ trễ và độ không đảm bảo.

GRBL là gì: nạp GRBL cho Arduino, CNC shield, sơ đồ chân và nối động cơ
GRBL là gì: nạp GRBL cho Arduino, CNC shield, sơ đồ chân và nối động cơ

GRBL là firmware biến Arduino Uno, Nano thành bộ điều khiển máy CNC, laser: sơ đồ chân GRBL 1.1, CNC shield V3, năm bước nạp GRBL bằng Arduino IDE, kiểm tra và lỗi thường gặp.

Jack Type-C sạc pin 1S loại 4 dây có LED: màu dây, cách hàn và nạp code ESP32 qua vỏ hộp
Jack Type-C sạc pin 1S loại 4 dây có LED: màu dây, cách hàn và nạp code ESP32 qua vỏ hộp

Jack Type-C sạc pin 1S loại 4 dây có LED: dây đỏ ra khoảng 4,2 V, trắng là D+, xanh dương là D−; cách hàn sang đầu Type-C đực để nạp code ESP32 qua cổng trên vỏ hộp và nối pin.

Liên kết chuẩn đo lường (traceability): chuỗi hiệu chuẩn từ đơn vị SI tới thiết bị hiện trường
Liên kết chuẩn đo lường (traceability): chuỗi hiệu chuẩn từ đơn vị SI tới thiết bị hiện trường

Liên kết chuẩn đo lường là gì: chuỗi hiệu chuẩn không đứt đoạn từ đơn vị SI, chuẩn quốc gia tới thiết bị hiện trường, CIPM MRA, ILAC MRA, VILAS, các trường hợp chuỗi bị đứt và cách kiểm tra.

Hiệu chuẩn load cell tại hiện trường: tải thật, mô phỏng mV/V, thế chỗ, ISO 376 và ASTM E74
Hiệu chuẩn load cell tại hiện trường: tải thật, mô phỏng mV/V, thế chỗ, ISO 376 và ASTM E74

Hiệu chuẩn hệ load cell tại hiện trường: chuỗi đo và nguồn sai số, tải thật so với mô phỏng mV/V, thế chỗ cho cân bồn, lưu ý lắp đặt, so sánh ISO 376 và ASTM E74.

Cảm biến ánh sáng: quang trở, photodiode, BH1750 – cấu tạo, nguyên lý, chế tạo và đo lux bằng ESP32
Cảm biến ánh sáng: quang trở, photodiode, BH1750 – cấu tạo, nguyên lý, chế tạo và đo lux bằng ESP32

Cảm biến ánh sáng hoạt động thế nào: độ rọi và lux, quang trở CdS, photodiode, phototransistor, cảm biến số BH1750, cách chế tạo và đo lux bằng BH1750, quang trở với ESP32.

Số nhị phân cho trẻ: đếm bằng 5 thẻ chấm, giải mật thư như máy tính
Số nhị phân cho trẻ: đếm bằng 5 thẻ chấm, giải mật thư như máy tính

Dạy trẻ số nhị phân bằng 5 thẻ chấm 1, 2, 4, 8, 16: viết số, đếm và tìm quy luật, giải mật thư chữ cái, liên hệ với bit, màn hình và mạch ESP32. Hoạt động không cần máy tính.

HTTPS trên ESP32: nhúng chứng chỉ gốc đúng cách và vì sao setInsecure() nguy hiểm
HTTPS trên ESP32: nhúng chứng chỉ gốc đúng cách và vì sao setInsecure() nguy hiểm

HTTPS bảo vệ được gì, chuỗi tin cậy của chứng chỉ, nhúng chứng chỉ gốc ISRG Root X1 vào ESP32, vì sao setInsecure() mở đường cho tấn công xen giữa, chương trình thử ba trường hợp.


Bình luận
Đã thêm vào giỏ hàng