ESP32 điều khiển động cơ bước NEMA 17 với A4988: vi bước, chỉnh dòng VREF, tăng tốc mượt

Hướng dẫn điều khiển động cơ bước NEMA 17 bằng ESP32 qua driver A4988: nối dây, chỉnh dòng VREF, chọn vi bước 1/16, tăng tốc giảm tốc hình thang và thí nghiệm STEM.

Động cơ bước NEMA 17 với driver A4988 là bộ đôi có mặt trong máy in 3D, máy CNC mini, máy vẽ và máy khắc laser loại nhỏ. So với động cơ 28BYJ-48, NEMA 17 khỏe và nhanh hơn nhiều, còn A4988 cho phép chia mỗi bước thành 16 vi bước để động cơ chạy êm. ESP32 chỉ cần gửi hai tín hiệu: STEP (mỗi xung là một bước) và DIR (chiều quay).

Bài viết hướng dẫn nối dây, chỉnh dòng điện bằng VREF, chọn vi bước, chương trình tăng tốc và giảm tốc hình thang để động cơ không bị trượt bước, cùng gợi ý thí nghiệm STEM.

1. A4988 và động cơ NEMA 17

Thông số chính
Thông sốGiá trị
Điện áp động cơ (VMOT) của A49888–35 V, thường dùng 12 V
Dòng mỗi cuộnkhoảng 1 A khi không tản nhiệt, tới 2 A khi có tản nhiệt tốt
Logic (VDD)3–5,5 V, dùng 3,3 V của ESP32
Vi bướcbước đầy, 1/2, 1/4, 1/8, 1/16
Động cơ NEMA 17 thông dụng1,8° mỗi bước (200 bước một vòng), mặt bích 42 × 42 mm, hai cuộn dây, 4 dây ra
  • Bốn dây của động cơ chia làm hai cặp: 1A–1B là cuộn A, 2A–2B là cuộn B. Hai dây cùng cuộn đo được điện trở vài ohm; hai dây khác cuộn thì không thông mạch.
  • Chân EN ở mức thấp thì driver cấp điện cho cuộn dây. Ở mức cao thì trục quay tự do.
  • Chân RST phải nối với SLP. Để hở RST thì driver không chạy.

2. Vi bước, tăng tốc và chỉnh dòng VREF

Bảng chọn vi bước A4988 theo MS1 MS2 MS3 từ bước đầy 200 bước một vòng tới 1/16 là 3200 bước một vòng, đồ thị tốc độ hình thang và công thức chỉnh dòng VREF
Hình minh họa: bảng vi bước, đồ thị tốc độ hình thang và cách tính VREF.
  • Vi bước: ở chế độ 1/16, một vòng trục cần 3200 xung STEP. Động cơ chạy êm và mịn hơn nhưng ESP32 phải phát nhiều xung hơn cho cùng tốc độ.
  • Tăng tốc hình thang: động cơ bước không thể đang đứng yên mà nhảy ngay lên tốc độ cao; làm vậy rôto không theo kịp và bị trượt bước. Chương trình tăng tốc dần, chạy đều, rồi giảm tốc trước khi dừng.
  • Chỉnh dòng VREF: dòng tối đa mỗi cuộn bằng VREF / (8 × Rs). Rs là điện trở cảm biến dòng in trên mạch: R100 là 0,1 Ω, R068 là 0,068 Ω. Đặt khoảng 70–80 % dòng định mức của động cơ.

Cách đo VREF: cấp nguồn logic (VDD) cho A4988, để que đen của đồng hồ vạn năng ở GND, que đỏ chạm vào con chạy của biến trở nhỏ trên mạch. Dùng tua vít nhựa vặn từ từ đến đúng giá trị.

3. Linh kiện cần chuẩn bị

4. Sơ đồ nối dây

Sơ đồ nối ESP32 với A4988: EN vào D21, MS1 MS2 MS3 vào D19 D18 D5, STEP vào TX2, DIR vào RX2, RST nối SLP, VDD vào 3V3; VMOT và GND vào nguồn 12 V có tụ 100 µF; hai cuộn động cơ NEMA 17 vào 1A 1B 2A 2B
Hình minh họa: sơ đồ nối ESP32, A4988, nguồn 12 V và động cơ NEMA 17.
  • Cắm A4988 lên breadboard theo đúng chiều in trên mạch. Các mạch A4988 cùng thứ tự chân, nhưng chiều biến trở và tản nhiệt có thể khác.
  • Tụ 100 µF đặt sát chân VMOT và GND để chặn xung điện áp khi cấp nguồn. Thiếu tụ có thể làm hỏng driver.
  • Không cắm hoặc rút dây động cơ khi driver đang có điện. Cuộn dây sinh điện áp cao làm cháy A4988.
  • GND của nguồn 12 V và GND của ESP32 phải nối chung. Hai chân GND trên A4988 đã nối với nhau bên trong mạch.

5. Chương trình: vi bước và tăng tốc hình thang

Chương trình nhận lệnh trên Serial Monitor (115200 baud, kiểu xuống dòng "New Line"):

Các lệnh
LệnhTác dụng
q 1Quay 1 vòng; q -0.5 quay ngược nửa vòng
m 16Chọn vi bước 1/16 (nhận 1, 2, 4, 8, 16)
v 2Tốc độ tối đa 2 vòng/s
a 4Gia tốc 4 vòng/s²
e 0, e 1Tắt driver (thả trục), bật lại
/*
  PYWORLD.VN - ESP32 điều khiển động cơ bước NEMA 17 qua A4988: chọn vi bước, tăng tốc và giảm tốc hình thang
  A4988: EN -> GPIO21, MS1 -> GPIO19, MS2 -> GPIO18, MS3 -> GPIO5, STEP -> GPIO17, DIR -> GPIO16, RST nối SLP
  Lệnh (115200, New Line): q 1 = quay 1 vòng (âm là quay ngược), m 16 = vi bước 1/16, v 2 = tốc độ 2 vòng/s, a 4 = gia tốc 4 vòng/s2, e 0 / e 1
*/

#define EN_PIN   21    // mức thấp: driver cấp điện cho cuộn dây
#define MS1_PIN  19
#define MS2_PIN  18
#define MS3_PIN  5
#define STEP_PIN 17    // mỗi xung lên là một bước (hoặc một vi bước)
#define DIR_PIN  16    // chiều quay

const int BUOC_DAY_MOI_VONG = 200;    // động cơ 1,8 độ mỗi bước
int viBuoc = 16;                      // 1, 2, 4, 8 hoặc 16
float vMaxVong = 2.0;                 // tốc độ tối đa, vòng/s
float giaTocVong = 4.0;               // gia tốc, vòng/s2

long buocMoiVong() {
  return (long)BUOC_DAY_MOI_VONG * viBuoc;
}

// Bảng chọn vi bước của A4988: MS1 MS2 MS3
bool chonViBuoc(int n) {
  int ms1, ms2, ms3;
  switch (n) {
    case 1:  ms1 = 0; ms2 = 0; ms3 = 0; break;
    case 2:  ms1 = 1; ms2 = 0; ms3 = 0; break;
    case 4:  ms1 = 0; ms2 = 1; ms3 = 0; break;
    case 8:  ms1 = 1; ms2 = 1; ms3 = 0; break;
    case 16: ms1 = 1; ms2 = 1; ms3 = 1; break;
    default: return false;
  }
  digitalWrite(MS1_PIN, ms1);
  digitalWrite(MS2_PIN, ms2);
  digitalWrite(MS3_PIN, ms3);
  viBuoc = n;
  return true;
}

// Chạy soBuoc bước. Tốc độ tại mỗi bước tính theo v = căn(2 x gia tốc x quãng đường),
// lấy theo đầu gần hơn (đầu tăng tốc hoặc đầu giảm tốc) và không vượt vMax: được hình thang.
void chay(long soBuoc, float vMax, float giaToc) {
  digitalWrite(DIR_PIN, soBuoc >= 0 ? HIGH : LOW);
  delayMicroseconds(5);
  long n = labs(soBuoc);
  unsigned long t = micros();
  for (long i = 0; i < n; i++) {
    long k = min(i + 1, n - i);
    float v = sqrtf(2.0f * giaToc * k);
    if (v > vMax) v = vMax;
    if (v < 20.0f) v = 20.0f;
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(3);                    // A4988 cần xung rộng tối thiểu 1 micro giây
    digitalWrite(STEP_PIN, LOW);
    t += (unsigned long)(1000000.0f / v);
    while ((long)(micros() - t) < 0) {
    }
  }
}

// Thời gian lý thuyết của chuyển động hình thang (hoặc tam giác nếu quãng ngắn)
float thoiGian(long n, float v, float a) {
  float sTang = v * v / (2 * a);
  if (2 * sTang <= n) return n / v + v / a;
  return 2 * sqrtf(n / a);
}

void inTrangThai() {
  Serial.printf("Vi buoc 1/%d (%ld buoc/vong), vmax %.1f vong/s, gia toc %.1f vong/s2\n",
                viBuoc, buocMoiVong(), vMaxVong, giaTocVong);
}

void setup() {
  Serial.begin(115200);
  int chan[] = {EN_PIN, MS1_PIN, MS2_PIN, MS3_PIN, STEP_PIN, DIR_PIN};
  for (int p : chan) pinMode(p, OUTPUT);
  digitalWrite(STEP_PIN, LOW);
  digitalWrite(EN_PIN, LOW);
  chonViBuoc(16);
  delay(500);
  Serial.println("A4988: q <vong>, m <1|2|4|8|16>, v <vong/s>, a <vong/s2>, e <0|1>");
  inTrangThai();
}

void loop() {
  if (!Serial.available()) return;
  String s = Serial.readStringUntil('\n');
  s.trim();
  if (s.length() < 1) return;
  char c = tolower(s.charAt(0));
  float so = s.substring(1).toFloat();

  if (c == 'q') {
    long n = lroundf(so * buocMoiVong());
    float v = vMaxVong * buocMoiVong();
    float a = giaTocVong * buocMoiVong();
    Serial.printf("Quay %.2f vong = %ld buoc, du kien %.2f s\n", so, n, thoiGian(labs(n), v, a));
    unsigned long t0 = millis();
    chay(n, v, a);
    Serial.printf("Xong sau %lu ms\n", millis() - t0);
  } else if (c == 'm') {
    if (!chonViBuoc((int)so)) Serial.println("Chi nhan 1, 2, 4, 8, 16");
    inTrangThai();
  } else if (c == 'v' && so > 0) {
    vMaxVong = so;
    inTrangThai();
  } else if (c == 'a' && so > 0) {
    giaTocVong = so;
    inTrangThai();
  } else if (c == 'e') {
    digitalWrite(EN_PIN, so > 0 ? LOW : HIGH);   // e 1: bật giữ lực, e 0: thả trục
    Serial.println(so > 0 ? "Driver bat" : "Driver tat, truc quay tu do");
  } else {
    Serial.println("Lenh khong hop le");
  }
}
Hình minh họa Serial Monitor khi gõ q 1, m 4, q -2, v 4, q 1: in chế độ vi bước, số bước và thời gian dự kiến của mỗi lần quay
Hình minh họa: kết quả in ra sau từng lệnh.

6. Giải thích các lệnh chính

  • chonViBuoc() đặt MS1, MS2, MS3 theo bảng ở mục 2. Đổi vi bước khi động cơ đang đứng yên.
  • chay() phát từng xung STEP. Tốc độ ở mỗi bước tính theo v = √(2 × a × s), với s là số bước tính từ đầu gần hơn (đầu tăng tốc hoặc đầu giảm tốc). Tốc độ không vượt vMax. Kết quả là đồ thị hình thang, hoặc hình tam giác khi quãng đường ngắn.
  • Khoảng cách giữa hai xung là 1 000 000 / v micro giây. Biến t cộng dồn thời điểm đích, nên thời gian chạy lệnh digitalWrite không làm chậm dần chuyển động.
  • thoiGian() tính thời gian theo lý thuyết để so với thời gian đo được sau mỗi lần quay.

Hàm chay() chiếm CPU trong lúc quay. Muốn vừa quay vừa làm việc khác (đọc nút, Wi-Fi), có thể phát xung bằng timer phần cứng hoặc chạy hàm trên lõi thứ hai của ESP32 bằng FreeRTOS.

7. Gợi ý dùng trong giờ học STEM

Mục tiêu: học sinh hiểu điều khiển vị trí bằng đếm bước, quan hệ giữa vận tốc, gia tốc và quãng đường, và giới hạn của động cơ thật.

  1. So sánh vi bước. Quay 1 vòng ở chế độ bước đầy rồi ở 1/16, cùng tốc độ. Nghe tiếng ồn, sờ độ rung. Vì sao vi bước êm hơn?
  2. Tìm gia tốc lớn nhất. Gắn một đĩa nặng lên trục. Tăng dần a tới khi động cơ trượt bước (kêu, không về đúng vạch đánh dấu sau 10 vòng). Nhận xét: tải nặng hơn thì gia tốc tối đa thay đổi ra sao?
  3. Kiểm chứng công thức chuyển động. So thời gian dự kiến với thời gian đo được, rồi giải thích chênh lệch. Đây là bài tập về chuyển động biến đổi đều trong Vật lý.
  4. Trục vít me. Gắn động cơ với trục vít bước 8 mm. Tính số bước để bàn trượt đi đúng 10 mm, đo bằng thước kẹp.

8. Xử lý lỗi thường gặp

Lỗi thường gặp
Hiện tượngNguyên nhân thường gặpCách xử lý
Động cơ không quay, không giữ lựcRST để hở; EN ở mức cao; chưa có nguồn VMOTNối RST với SLP; gõ e 1; kiểm tra nguồn 12 V
Động cơ rung tại chỗ, không quaySai cặp cuộn dây; VREF quá thấpĐo điện trở để tìm đúng cặp; tăng VREF
Chạy được một lúc thì trượt bước, kêu lạch cạchGia tốc hoặc tốc độ quá cao so với tảiGiảm a, v; tăng dòng (VREF) trong giới hạn
A4988 rất nóng, tự ngắtDòng đặt quá cao, thiếu tản nhiệtGiảm VREF; gắn tản nhiệt, thêm quạt
Quay ngược chiềuĐảo cặp dây cuộn A hoặc cuộn BĐổi dấu số vòng hoặc đảo hai dây của một cuộn khi đã tắt nguồn

9. Xem thêm

Cùng loạt: động cơ bước 28BYJ-48 với ULN2003, động cơ DC với L298N.


Tin tức liên quan

Hướng dẫn dùng PWM trên ESP32: điều chỉnh độ sáng LED bằng analogWrite và LEDC
Hướng dẫn dùng PWM trên ESP32: điều chỉnh độ sáng LED bằng analogWrite và LEDC

Hướng dẫn tạo PWM trên ESP32 bằng Arduino IDE: analogWrite, ledcAttach và ledcWrite của gói esp32 3.x, chỉnh độ sáng LED bằng biến trở, chọn tần số và độ phân giải.

Hướng dẫn làm đồng hồ Internet với ESP32, NTP và màn hình OLED 0.96 inch
Hướng dẫn làm đồng hồ Internet với ESP32, NTP và màn hình OLED 0.96 inch

Hướng dẫn ESP32 lấy giờ Việt Nam từ Internet bằng NTP trên Arduino IDE, in ra Serial Monitor và làm đồng hồ hiển thị thứ, ngày, giờ trên màn hình OLED 0.96 inch SSD1306.

Xe tránh vật cản với ESP32: cảm biến siêu âm HC-SR04 trên servo quét, tự chọn đường
Xe tránh vật cản với ESP32: cảm biến siêu âm HC-SR04 trên servo quét, tự chọn đường

Làm xe robot tự tránh vật cản với ESP32: cảm biến siêu âm HC-SR04 gắn trên servo quét trái phải, cầu phân áp cho chân ECHO, thuật toán chọn đường, lưu đồ và thí nghiệm STEM.

Hướng dẫn dùng màn hình OLED 0.96 inch SSD1306 với Arduino Nano
Hướng dẫn dùng màn hình OLED 0.96 inch SSD1306 với Arduino Nano

Hướng dẫn nối màn hình OLED 0.96 inch SSD1306 (I2C) với Arduino Nano, cài thư viện Adafruit, hiện chữ nhiều cỡ, vẽ thanh mức theo điện áp và lưu ý về bộ nhớ RAM.

Hướng dẫn dùng màn hình OLED SSD1306 với ESP8266
Hướng dẫn dùng màn hình OLED SSD1306 với ESP8266

Hướng dẫn nối OLED SSD1306 với ESP8266, quét địa chỉ I2C, cài thư viện và hiển thị thời gian bằng mã Arduino mẫu.

ESP-NOW nhiều node với ESP32: nhiều mạch gửi về một trạm thu, hiển thị trên OLED
ESP-NOW nhiều node với ESP32: nhiều mạch gửi về một trạm thu, hiển thị trên OLED

Hướng dẫn dựng mô hình ESP-NOW nhiều node: tối đa bốn ESP32 gửi số đo về một trạm thu, trạm thu hiện điện áp, RSSI và tình trạng từng node trên màn hình OLED 0.96 inch.

Hướng dẫn dùng LoRa SX1278 (Ra-02) với ESP32: nối dây SPI, gửi và nhận gói tin đầu tiên
Hướng dẫn dùng LoRa SX1278 (Ra-02) với ESP32: nối dây SPI, gửi và nhận gói tin đầu tiên

Hướng dẫn nối module LoRa SX1278 Ra-02 433 MHz với ESP32 qua SPI, cài thư viện LoRa trên Arduino IDE, viết chương trình gửi và nhận gói tin, đọc RSSI, SNR và xử lý lỗi thường gặp.

Hướng dẫn bắt đầu với Wemos D1 R2 (ESP8266) trên Arduino IDE
Hướng dẫn bắt đầu với Wemos D1 R2 (ESP8266) trên Arduino IDE

Hướng dẫn dùng Wemos D1 R2 (ESP8266 khung Arduino UNO) với Arduino IDE 2.x: sơ đồ chân, cài driver CH340 và gói board ESP8266, nạp code nháy LED, kết nối WiFi và xử lý lỗi thường gặp.


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