0968140191Miền Nam
0975897066Miền Bắc

Điều khiển động cơ bước Arduino: thư viện, code mẫu và cách tránh lỗi thường gặp

Viết bởi: Vũ Hồng Phúc
Vũ Hồng Phúc
Vũ Hồng Phúc, sinh năm 1985, sau khi tốt nghiệp cử nhân tại Đại Học Bách Khoa Hà Nội, Vũ Hồng Phúc đã tự mình khám phá thế giới qua việc du học tại EF Language School London và nhiều trường đại học khác. Tích lũy kinh nghiệm trong nhiều năm, anh quyết định trở về đất nước. Vũ Hồng Phúc đã hướng đến mục tiêu phát triển Dongco3pha.com là thương hiệu "Động cơ điện" hàng đầu Việt Nam. Trong nhiều năm liền danh liên tục mang lại nhiều thành tựu cho doanh nghiệp và đóng góp nhiều giải pháp tối ưu về chế tạo máy, chế tạo động cơ giảm tốc, động cơ điện.
16 thg 10 2026 16:50

Điều khiển động cơ bước Arduino là dùng board Arduino (Uno, Nano, Mega, ESP32…) phát xung STEP và mức logic DIR tới một driver như A4988, DRV8825, TMC2208 hoặc TB6600; mỗi xung làm motor quay một bước (1,8° với motor 200 bước/vòng ở chế độ bước đủ), còn mức DIR quyết định chiều quay. Arduino không cấp dòng cho motor, nó chỉ ra lệnh; dòng điện vào cuộn dây do driver và nguồn riêng 12–36V đảm nhiệm.

Phần khó không nằm ở đấu dây mà ở phần mềm: chọn thư viện nào, viết code sao cho motor chạy mượt khi chương trình còn phải đọc nút nhấn, cảm biến, Serial, và board có phát đủ nhanh hay không. Một Arduino Uno chạy AccelStepper chỉ đạt khoảng 4.000 bước/giây; với vi bước 1/16 con số đó chỉ còn 75 vòng/phút. Đổi sang FastAccelStepper dùng timer phần cứng, cùng board đó lên tới khoảng 50.000 bước/giây.

Dưới đây là cách đấu nối tối thiểu, so sánh các thư viện phổ biến, đoạn code mẫu ngắn cho từng tình huống (chạy thử, biến trở chỉnh tốc, nút nhấn, lệnh Serial, nhiều motor), cách dùng CNC Shield với GRBL và danh sách lỗi lập trình hay gặp nhất.

Điều khiển động cơ bước Arduino với driver và motor NEMA 17

  • Hệ điều khiển động cơ bước Arduino gồm board Arduino phát xung, driver khuếch đại dòng, nguồn riêng cho motor và động cơ bước.

1. Arduino làm gì trong hệ điều khiển động cơ bước

Một hệ chạy động cơ bước bằng Arduino luôn có bốn khối: nguồn, Arduino (bộ phát xung), driver và motor. Arduino chỉ xuất tín hiệu vài mA ở mức 5V hoặc 3,3V. Một motor NEMA 17 thường cần 1–2A mỗi pha, nên không bao giờ nối cuộn dây motor thẳng vào chân Arduino.

Hai kiểu giao tiếp giữa Arduino và driver

  • Kiểu STEP/DIR: dùng cho A4988, DRV8825, TMC2208/2209, TB6600, DM542 và hầu hết driver công nghiệp. Arduino chỉ cần 2 chân cho mỗi motor (thêm 1 chân ENABLE nếu muốn tắt dòng giữ). Đây là kiểu nên dùng cho mọi dự án mới.
  • Kiểu 4 chân điều khiển trực tiếp từng pha: dùng cho module ULN2003 với motor 28BYJ-48 hoặc cầu H L298N. Arduino phải tự xuất chuỗi đóng cắt pha, tốn chân và không có vi bước. Chi tiết loại motor 5 dây này xem tại bài động cơ bước 5 dây.

Quan hệ giữa xung và tốc độ quay

Tốc độ (vòng/phút) = tần số xung STEP (bước/giây) × 60 ÷ (số bước/vòng × hệ số vi bước).

Ví dụ motor 200 bước/vòng, driver đặt vi bước 1/8: muốn chạy 300 vòng/phút cần 300 × 1.600 ÷ 60 = 8.000 xung/giây. Đây là con số dùng để chọn thư viện và board ở mục 3. Ảnh hưởng của tốc độ đến mô-men và hiện tượng cộng hưởng được phân tích riêng trong bài điều khiển tốc độ động cơ bước.

Vi bướcSố xung/vòng (motor 1,8°)Xung/giây để chạy 60 vòng/phútXung/giây để chạy 300 vòng/phút
Bước đủ2002001.000
1/24004002.000
1/81.6001.6008.000
1/163.2003.20016.000
1/326.4006.40032.000
  • Vi bước càng cao, motor càng êm nhưng Arduino phải phát xung càng nhanh.
  • Vượt quá khả năng của thư viện, motor không nhanh thêm mà chạy giật, kêu hoặc dừng hẳn.
  • Với Uno, vi bước 1/8 thường là điểm cân bằng tốt giữa độ êm và tốc độ.

2. Đấu nối Arduino với driver STEP/DIR

Sơ đồ dưới đây áp dụng cho module A4988/DRV8825 dạng Pololu, loại driver được dùng nhiều nhất với Arduino. Driver lớn như TB6600, DM542 đấu tương tự nhưng ngõ vào là opto (PUL+, PUL−, DIR+, DIR−, ENA+, ENA−).

Chân ArduinoChân driverGhi chú
D3STEPMỗi xung lên = 1 bước (hoặc 1 vi bước)
D2DIRMức HIGH/LOW quyết định chiều quay
D8 (tùy chọn)ENABLELOW = có dòng, HIGH = nhả motor
5VVDDNguồn logic của driver
GNDGND (logic)Bắt buộc chung mass với Arduino
Không nốiVMOTNối nguồn motor 12–35V riêng
Không nốiRESET – SLEEPNối tắt với nhau nếu không dùng

Sơ đồ cấu hình điều khiển động cơ bước Arduino với driver A4988

  • Sơ đồ đấu nối Arduino với driver STEP/DIR: chân STEP, DIR từ Arduino, nguồn motor riêng cấp vào VMOT, mass chung giữa các khối.

Cấp nguồn riêng, chung mass

Motor luôn lấy điện từ nguồn riêng (adapter hoặc nguồn tổ ong 12V, 24V), không lấy từ chân 5V hay VIN của Arduino. Cổng USB chỉ cấp được khoảng 500mA, còn ổn áp trên board Uno nóng và sụt áp khi tải lớn, khiến Arduino reset liên tục mỗi lần motor khởi động. Mass của nguồn motor, driver và Arduino phải nối chung; thiếu dây mass chung, xung STEP không có mức tham chiếu và motor chạy loạn hoặc đứng yên.

Một số lưu ý khi cấp nguồn:

  • Cấp nguồn motor trước hoặc cùng lúc với Arduino; tránh để driver nhận xung khi VMOT chưa có điện.
  • Không rút, cắm dây motor khi driver đang có điện; điện áp cảm ứng có thể phá hỏng driver ngay lập tức.
  • Đặt dòng giới hạn của driver (Vref) trước khi chạy code; cách tính Vref cho từng board có trong bài điều khiển động cơ bước bằng A4988.

Mức logic 5V và 3,3V

Uno, Nano, Mega và Uno R4 xuất tín hiệu 5V. ESP32, ESP8266, Raspberry Pi Pico (RP2040), Arduino Nano ESP32, Due xuất 3,3V. Với A4988, DRV8825, TMC2208, chỉ cần cấp VDD của driver bằng 3,3V từ board là mức logic tương thích, không cần chuyển mức.

Driver opto công nghiệp (TB6600, DM542, DM556…) thường yêu cầu tín hiệu 4,5–5V để ngõ vào nhận mức cao chắc chắn. Nối thẳng 3,3V từ ESP32 thì có bộ chạy, có bộ không, hoặc chạy được ở tốc độ thấp nhưng mất xung khi tăng tốc. Cách xử lý ổn định:

  • Dùng IC đệm/chuyển mức một chiều như 74HCT245 hoặc 74AHCT125 cấp nguồn 5V; ngõ vào HCT nhận 3,3V là mức cao.
  • Hoặc đấu kiểu chung dương: PUL+, DIR+ nối 5V, PUL−, DIR− nối cực C của transistor NPN (2N2222, BC547) do chân 3,3V điều khiển qua điện trở 1kΩ; lưu ý kiểu này đảo mức logic, cần đảo lại trong code.
  • Module chuyển mức hai chiều dùng MOSFET (loại BSS138 phổ biến) chạy ổn ở tần số thấp nhưng sườn xung chậm, không phù hợp khi phát xung tần số cao. Điện áp ngõ vào và điện trở hạn dòng khi dùng tín hiệu 12V, 24V được trình bày trong bài mạch phát xung điều khiển động cơ bước.

Video dưới đây cho thấy một động cơ bước được đấu điện và chạy thực tế, giúp hình dung rõ chuyển động theo từng bước của trục.

3. So sánh các thư viện điều khiển động cơ bước Arduino

Chọn sai thư viện là nguyên nhân phổ biến nhất khiến motor chạy chậm, giật hoặc làm treo cả chương trình. Bảng sau tóm tắt bốn thư viện được dùng nhiều nhất.

Thư việnTăng/giảm tốcChặn chương trìnhTốc độ tối đa trên UnoPhù hợp
Stepper.hKhôngCó (hàm step chặn)Thấp, phụ thuộc delayMotor 28BYJ-48, bài học cơ bản
AccelStepperCóKhông (nếu dùng run)Khoảng 4.000 bước/giâyĐa số dự án nhỏ, 1–3 motor
MobaTools (MoToStepper)CóKhông (chạy ngắt)Mặc định 2.500 bước/giâyNhiều motor chậm, mô hình, cơ cấu tự động
FastAccelStepperCóKhông (timer phần cứng)Khoảng 50.000 bước/giây (1 motor)Tốc độ cao, vi bước lớn, ESP32
  • Con số tốc độ là giới hạn phát xung của thư viện, không phải tốc độ motor thực sự đạt được dưới tải.
  • FastAccelStepper trên Uno chỉ phát được trên chân 9 và 10 (tối đa 2 motor, khoảng 37.000 bước/giây khi chạy cả hai).
  • MobaTools trên ESP32 đạt khoảng 30.000 bước/giây, Uno R4 khoảng 12.000 bước/giây.

a. Stepper.h – thư viện có sẵn trong Arduino IDE

Stepper.h được cài sẵn, viết cho motor điều khiển trực tiếp 2 hoặc 4 dây pha (qua ULN2003, L298N). Hàm setSpeed nhận đơn vị vòng/phút, hàm step(n) quay n bước rồi mới trả về. Trong lúc step đang chạy, Arduino không làm được việc gì khác: không đọc nút, không nhận Serial. Thư viện cũng không có tăng tốc, nên motor lớn khởi động thẳng ở tốc độ cao rất dễ trượt bước. Stepper.h chỉ nên dùng để học hoặc chạy motor nhỏ 28BYJ-48.

b. AccelStepper – lựa chọn mặc định cho đa số dự án

AccelStepper hỗ trợ cả driver STEP/DIR (khai báo kiểu AccelStepper::DRIVER) lẫn motor 4 dây, có tăng/giảm tốc dạng hình thang, đếm vị trí tuyệt đối và điều khiển nhiều motor. Điểm mấu chốt: hàm run() mỗi lần gọi chỉ phát tối đa một bước, nên phải gọi run() liên tục trong loop(). Thư viện tính thời gian bằng số thực, nên trên chip 8-bit 16MHz tốc độ thực tế dừng ở khoảng 4.000 bước/giây; vượt ngưỡng này xung bắt đầu không đều.

c. MobaTools – phát xung bằng ngắt, dễ dùng

MobaTools (lớp MoToStepper) phát xung trong ngắt timer nên motor vẫn chạy đều kể cả khi loop() có delay ngắn hoặc đang in Serial. Thư viện quản lý tới 6 motor cùng lúc, có tăng tốc, có hàm quay theo góc. Đổi lại, trần tốc độ trên AVR thấp (mặc định 2.500 bước/giây), hợp với cơ cấu chậm như bàn xoay, cửa, mô hình tàu điện, máy cấp liệu.

d. FastAccelStepper – khi cần tốc độ cao

FastAccelStepper dùng timer phần cứng (AVR) hoặc khối RMT/MCPWM (ESP32), PIO (RP2040) để phát xung, CPU gần như rảnh. Trên ESP32 và Raspberry Pi Pico đạt tới khoảng 200.000 bước/giây, đủ cho vi bước 1/32 ở tốc độ cao. Hạn chế: trên AVR chỉ dùng được một số chân cố định (Uno: chân 9, 10; Mega: mặc định chân 6, 7, 8), và cú pháp hơi khác AccelStepper.

4. Code mẫu điều khiển động cơ bước Arduino

Các đoạn code dưới đây viết cho driver STEP/DIR với STEP ở chân 3, DIR ở chân 2. Mỗi dòng là một dòng lệnh trong Arduino IDE.

Chạy thử không dùng thư viện

Đoạn code này chỉ dùng để kiểm tra đấu nối: motor quay 1 vòng (200 bước ở chế độ bước đủ), dừng 1 giây rồi quay ngược lại.

const int stepPin = 3; const int dirPin = 2;

void setup() { pinMode(stepPin, OUTPUT); pinMode(dirPin, OUTPUT); }

void loop() {

digitalWrite(dirPin, HIGH);

for (int i = 0; i < 200; i++) { digitalWrite(stepPin, HIGH); delayMicroseconds(800); digitalWrite(stepPin, LOW); delayMicroseconds(800); }

delay(1000); digitalWrite(dirPin, LOW);

for (int i = 0; i < 200; i++) { digitalWrite(stepPin, HIGH); delayMicroseconds(800); digitalWrite(stepPin, LOW); delayMicroseconds(800); }

delay(1000);

}

Chu kỳ 1.600 µs tương ứng khoảng 625 bước/giây, tức 187 vòng/phút ở bước đủ, đủ chậm để motor nào cũng khởi động được. Nếu motor chỉ rung mà không quay, tăng thời gian delayMicroseconds lên 1.500–2.000 µs để loại trừ lỗi tốc độ trước khi kiểm tra dây. Vòng for này chặn toàn bộ chương trình, nên chỉ dùng để thử.

Code không chặn với AccelStepper

#include <AccelStepper.h>

AccelStepper motor(AccelStepper::DRIVER, 3, 2);

void setup() { motor.setMaxSpeed(2000); motor.setAcceleration(1000); motor.moveTo(3200); }

void loop() {

if (motor.distanceToGo() == 0) { motor.moveTo(-motor.currentPosition()); }

motor.run();

}

Motor tăng tốc tới 2.000 bước/giây, đi tới vị trí 3.200 (1 vòng ở vi bước 1/16), giảm tốc dừng rồi chạy ngược về −3.200. Trong loop() có thể thêm đọc cảm biến, nút nhấn, miễn là không có delay() và không có đoạn code nào mất nhiều hơn khoảng thời gian giữa hai bước (0,5 ms ở 2.000 bước/giây).

Chỉnh tốc độ bằng biến trở

Biến trở 10kΩ nối A0. Dùng runSpeed() để chạy tốc độ không đổi, không cần vị trí đích:

void loop() {

if (millis() - tDoc > 50) { tDoc = millis(); int v = analogRead(A0); motor.setSpeed(map(v, 0, 1023, -1500, 1500)); }

motor.runSpeed();

}

Biến tDoc khai báo kiểu unsigned long ở đầu chương trình, và setup() cần gọi setMaxSpeed(1500). Chỉ đọc biến trở mỗi 50 ms vì analogRead mất khoảng 100 µs; đọc mỗi vòng loop sẽ làm giảm tốc độ phát xung. Biến trở ở giữa thì motor dừng, vặn sang hai phía thì quay hai chiều. Lưu ý runSpeed() không có tăng tốc: vặn biến trở quá nhanh với motor tải nặng sẽ bị trượt bước.

Điều khiển bằng nút nhấn

Nút nhấn nối giữa chân 4 và GND, khai báo pinMode(4, INPUT_PULLUP) để không cần điện trở ngoài. Mỗi lần nhấn cho motor đi thêm 1 vòng:

bool nut = digitalRead(4);

if (nut == LOW && nutCu == HIGH && millis() - tNhan > 30) { tNhan = millis(); motor.move(3200); }

nutCu = nut; motor.run();

Biến nutCu (bool, giá trị đầu HIGH) và tNhan (unsigned long) khai báo ở đầu chương trình. Điều kiện so sánh trạng thái cũ và mới chỉ bắt sườn nhấn, còn mốc 30 ms lọc rung tiếp điểm. Thiếu lọc rung, một lần nhấn có thể bị đếm thành 3–5 lần và motor đi quá quãng đường.

Nhận lệnh từ Serial Monitor

Gõ một số (ví dụ 1600 hoặc −800) vào Serial Monitor để motor đi tương đối số bước đó:

if (Serial.available()) { long n = Serial.parseInt(); if (n != 0) motor.move(n); }

motor.run();

Hàm parseInt mặc định chờ tới 1 giây nếu dữ liệu chưa kết thúc, làm motor khựng lại giữa chừng. Đặt Serial.setTimeout(10) trong setup() và chọn kiểu kết thúc dòng "Newline" ở Serial Monitor. Với giao thức phức tạp hơn (nhiều tham số, nhiều motor), nên đọc từng ký tự vào bộ đệm và chỉ xử lý khi gặp ký tự xuống dòng.

Tốc độ cao với FastAccelStepper

#include <FastAccelStepper.h>

FastAccelStepperEngine engine = FastAccelStepperEngine();

FastAccelStepper *stepper = NULL;

void setup() {

engine.init(); stepper = engine.stepperConnectToPin(9);

if (stepper) { stepper->setDirectionPin(2); stepper->setSpeedInHz(20000); stepper->setAcceleration(40000); stepper->moveTo(32000); }

}

void loop() { }

Trên Uno, chân STEP phải là chân 9 hoặc 10. Từ lúc moveTo() được gọi, timer phần cứng tự phát xung tới khi xong, loop() có thể làm việc khác hoàn toàn, kể cả delay(). 20.000 bước/giây ở vi bước 1/16 tương đương 375 vòng/phút, mức AccelStepper trên cùng board không đạt được.

5. Chạy nhiều động cơ bước cùng lúc

Nhiều motor độc lập

Với AccelStepper, khai báo mỗi motor một đối tượng và gọi run() của tất cả trong loop(). Tổng tốc độ bị chia: Uno với 3 motor cùng chạy chỉ còn khoảng 1.000–1.500 bước/giây mỗi motor. MobaTools và FastAccelStepper ít bị ảnh hưởng hơn vì xung phát trong ngắt hoặc phần cứng.

Nhiều motor đi đồng thời tới đích (nội suy)

Khi cần hai trục X, Y cùng xuất phát và cùng đến đích (vẽ đường chéo, máy vẽ), dùng lớp MultiStepper đi kèm AccelStepper: thêm các motor bằng addStepper(), gọi moveTo() với mảng vị trí rồi gọi run(). MultiStepper tự tính tốc độ từng trục để về đích cùng lúc, nhưng không có tăng/giảm tốc, nên tốc độ đặt phải thấp hơn tốc độ khởi động an toàn của motor. Khi cần nội suy có tăng tốc, nội suy cung tròn, đó là việc của firmware CNC như GRBL ở mục 6.

Hai motor chạy song song trên một trục

Trục Y của máy CNC hoặc máy in 3D cỡ lớn hay dùng hai motor. Cách đơn giản nhất là nối chung chân STEP và DIR của hai driver vào cùng một chân Arduino (một chân xuất được tín hiệu cho 2–3 ngõ vào driver dạng Pololu). Nếu một motor cần quay ngược chiều, đảo một cặp cuộn dây của motor đó thay vì sửa code.

Đồng bộ chính xác vị trí giữa các trục

Khi các trục phải đồng bộ tuyệt đối và tự lấy lại gốc sau khi mất điện, cần thêm công tắc hành trình và quy trình về gốc; nội dung này thuộc bài điều khiển vị trí động cơ bước.

6. Dùng Arduino CNC Shield và GRBL

CNC Shield V3 cắm thẳng lên Arduino Uno, có 4 khe cắm driver dạng Pololu (X, Y, Z, A), jumper chọn vi bước MS1–MS3 dưới mỗi driver, cổng công tắc hành trình và cầu đấu nguồn motor 12–36V. Shield này thiết kế cho firmware GRBL, nên dù có thể tự viết code, cách dùng hiệu quả nhất là nạp GRBL và gửi lệnh G-code.

Chức năngTrục XTrục YTrục Z
STEPD2D3D4
DIRD5D6D7
ENABLE (chung)D8D8D8
Công tắc hành trìnhD9D10D12 (GRBL 1.1)
  • Muốn tự viết code AccelStepper trên CNC Shield, phải khai báo đúng chân theo bảng và kéo D8 xuống LOW, nếu không driver không cấp dòng.
  • Trục A dùng jumper để nhân bản tín hiệu của một trục khác (thường là Y) hoặc lấy từ chân D12, D13.
  • Bản GRBL 1.1 dùng D11 cho PWM trục chính, nên công tắc trục Z chuyển sang D12.

Cài đặt GRBL cơ bản

Sau khi nạp GRBL vào Uno, mở chương trình gửi G-code (UGS, Candle, bCNC…) hoặc Serial Monitor ở tốc độ 115200, gõ $$ để xem toàn bộ tham số. Ba nhóm cần chỉnh đầu tiên:

  • $100, $101, $102: số bước/mm của X, Y, Z. Ví dụ vít me bước 8 mm, motor 200 bước, vi bước 1/16: 3.200 ÷ 8 = 400 bước/mm.
  • $110, $111, $112: tốc độ tối đa (mm/phút); $120, $121, $122: gia tốc (mm/s²). Bắt đầu thấp rồi tăng dần tới khi motor bắt đầu trượt bước, sau đó lùi lại khoảng 20–30%.
  • $3: đảo chiều trục theo bit (1 = X, 2 = Y, 4 = Z, cộng lại nếu đảo nhiều trục); $1: thời gian giữ dòng sau khi dừng, đặt 255 để motor luôn giữ.

GRBL trên Uno phát được khoảng 30.000 xung/giây, đủ cho máy CNC mini, máy khắc laser, máy vẽ. Máy cỡ lớn cần nhiều trục hơn hoặc tốc độ cao hơn nên dùng bản GRBL cho ESP32 hoặc board 32-bit chuyên dụng.

7. Giới hạn tốc độ thực tế theo từng board

Tần số xung không chỉ phụ thuộc thư viện mà còn phụ thuộc vi điều khiển. Bảng dưới đây là mức tham khảo khi dùng thư viện phù hợp nhất cho từng board.

BoardMức logicPhát xung tối đa (thư viện phù hợp)Ghi chú
Uno, Nano (ATmega328P)5VKhoảng 50.000 bước/giây (FastAccelStepper, 1 motor)AccelStepper chỉ khoảng 4.000
Mega 25605VKhoảng 50.000 bước/giâyNhiều chân, hợp nhiều trục
Uno R45VKhoảng 12.000 bước/giây (MobaTools)Chip 32-bit, vẫn logic 5V
ESP323,3VKhoảng 200.000 bước/giây (FastAccelStepper)Cần chuyển mức với driver opto
Raspberry Pi Pico (RP2040)3,3VKhoảng 200.000 bước/giâyDùng PIO phát xung
  • Tần số tối đa của driver cũng là giới hạn: TB6600 bản phổ thông thường ghi khoảng 20 kHz, trong khi driver số loại tốt nhận 200 kHz trở lên.
  • Xung STEP phải đủ rộng: A4988 cần mức cao tối thiểu 1 µs; driver opto thường cần vài µs, xem datasheet từng loại.
  • Motor có tần số khởi động riêng; vượt qua nó mà không có tăng tốc thì motor không quay được dù board phát xung đủ nhanh.

Nếu đã đạt giới hạn mà máy vẫn chậm, hãy nhớ rằng mô-men động cơ bước giảm mạnh khi tốc độ tăng. Khi tải cần lực lớn ở tốc độ thấp, gắn motor qua hộp giảm tốc sẽ hiệu quả hơn ép Arduino phát xung nhanh hơn. Khi cần tốc độ cao, mô-men ổn định và biết chắc vị trí trục (phản hồi encoder), motor servo AC nhận cùng tín hiệu xung STEP/DIR từ Arduino nên không cần viết lại logic chương trình.

8. Lỗi lập trình thường gặp và cách xử lý

Motor chạy chậm hơn nhiều so với setMaxSpeed

  • Trong loop() có delay(), Serial.print() liên tục hoặc đọc cảm biến chậm (DHT11, cảm biến siêu âm dùng pulseIn). Mỗi lần như vậy run() bị bỏ lỡ và motor chậm lại. Gom việc in Serial và đọc cảm biến theo chu kỳ bằng millis(), tăng tốc độ Serial lên 115200.
  • Đặt setMaxSpeed vượt khả năng thư viện (ví dụ 10.000 với AccelStepper trên Uno). Giảm vi bước hoặc đổi sang FastAccelStepper.
  • Gia tốc quá nhỏ nên motor chưa kịp đạt tốc độ tối đa đã phải giảm tốc trên quãng đường ngắn.

Gọi run() nhưng motor không quay

  • Chưa gọi setMaxSpeed(): giá trị mặc định là 1 bước/giây, nhìn như motor đứng yên.
  • Gọi setSpeed() rồi dùng run(): run() tự tính lại tốc độ theo gia tốc và bỏ qua setSpeed. Muốn chạy tốc độ không đổi thì dùng runSpeed(), muốn đi tới đích thì dùng moveTo() + run().
  • Khai báo nhầm kiểu motor: viết AccelStepper motor(3, 2) thì số 3 được hiểu là kiểu motor 3 dây, không phải chân STEP. Luôn ghi AccelStepper::DRIVER ở tham số đầu.
  • Chân ENABLE để hở hoặc mức HIGH trên CNC Shield.

Chương trình bị treo khi motor chạy

Hàm runToPosition() và Stepper.step() là hàm chặn: chạy xong mới trả về, mọi nút nhấn dừng khẩn cấp vô tác dụng trong lúc đó. Nút dừng khẩn cấp thật sự phải cắt nguồn motor hoặc chân ENABLE bằng phần cứng, không nên chỉ dựa vào code.

Motor rung tại chỗ, kêu nhưng không quay

Nếu code chạy thử ở tốc độ thấp vẫn rung, lỗi nằm ở đấu cuộn dây (hai dây của một cuộn bị tách sang hai cổng) hoặc dòng đặt quá thấp. Nếu chỉ rung ở tốc độ cao, đó là vượt tần số khởi động: tăng gia tốc từ từ, hạ tốc độ tối đa.

Motor quay sai số vòng

Thường do quên nhân hệ số vi bước: driver đặt 1/16 mà code tính 200 bước/vòng thì motor chỉ quay 1/16 vòng. Kiểm tra lại jumper MS1–MS3 (hoặc công tắc DIP trên TB6600) và hằng số trong code.

Đảo chiều bị lệch vài bước

Đổi mức DIR và phát xung STEP ngay lập tức có thể khiến driver chưa kịp nhận chiều mới. A4988 cần DIR ổn định trước sườn STEP ít nhất 200 ns, driver opto cần lâu hơn (vài µs). Với code tự viết, thêm delayMicroseconds(5) sau khi đổi DIR; AccelStepper có hàm setMinPulseWidth() để kéo dài độ rộng xung khi dùng driver opto.

Arduino tự reset khi motor khởi động

Nguyên nhân gần như luôn là chung nguồn: Arduino lấy điện từ cùng nguồn với motor qua ổn áp yếu, hoặc dây mass mảnh khiến dòng motor đi qua board. Tách nguồn, đi dây mass hình sao về một điểm, thêm tụ 100 µF sát VMOT của driver.

9. Khi nào nên dùng động cơ khác thay vì động cơ bước

Động cơ bước hợp với bài toán định vị theo số bước, chi phí thấp. Một số trường hợp loại động cơ khác gọn hơn:

  • Chỉ cần quay liên tục và chỉnh tốc độ, không cần biết vị trí (băng tải nhỏ, máy khuấy, cuộn dây): một motor 12V DC điều khiển bằng PWM qua mạch cầu H đơn giản hơn nhiều, Arduino chỉ cần một chân analogWrite.
  • Cần mô-men lớn ở tốc độ thấp, chạy liên tục nhiều giờ: động cơ giảm tốc mini cho lực kéo lớn, không nóng như động cơ bước luôn giữ dòng.
  • Cần tốc độ trên 1.000 vòng/phút với mô-men gần như không đổi, hoặc không chấp nhận mất bước: motor servo có encoder, ví dụ motor servo 400W, vẫn nhận xung STEP/DIR như động cơ bước.

10. Câu hỏi thường gặp về điều khiển động cơ bước Arduino

  • Arduino Uno điều khiển được tối đa bao nhiêu động cơ bước? Về số chân, Uno có thể điều khiển 6–8 motor STEP/DIR (mỗi motor 2 chân). Giới hạn thật nằm ở tốc độ phát xung: với AccelStepper, tổng khoảng 4.000 bước/giây chia cho các motor đang chạy. Nhiều hơn 3–4 trục chạy đồng thời nên dùng Mega, ESP32 hoặc firmware chuyên dụng.
  • Nên dùng AccelStepper hay FastAccelStepper? AccelStepper dễ dùng, chạy trên gần như mọi board và đủ cho tốc độ dưới khoảng 3.000 bước/giây. FastAccelStepper phát xung bằng phần cứng nên đạt tới khoảng 50.000 bước/giây trên Uno và 200.000 bước/giây trên ESP32, nhưng bị giới hạn chân phát xung. Dự án vi bước 1/16 trở lên cần chạy nhanh nên chọn FastAccelStepper.
  • Vì sao setMaxSpeed(10000) mà motor vẫn chạy chậm? AccelStepper trên chip 16MHz không phát nổi 10.000 bước/giây, và mỗi lệnh delay hay Serial.print trong loop() còn làm chậm thêm. Hãy giảm vi bước, bỏ code chặn trong loop() hoặc đổi thư viện phát xung bằng timer.
  • Có thể cấp nguồn motor từ chân 5V hay VIN của Arduino không? Không. Chân 5V và cổng USB chỉ cấp khoảng 500mA, không đủ cho motor và làm Arduino reset. Motor phải dùng nguồn riêng 12–24V cấp vào driver, chỉ nối chung mass với Arduino.
  • Làm sao chạy hai động cơ bước cùng lúc mà không cái nào phải chờ cái nào? Dùng code không chặn: khai báo hai đối tượng AccelStepper và gọi run() của cả hai trong loop(), không dùng delay() hay runToPosition(). Nếu hai trục cần về đích cùng lúc, dùng MultiStepper hoặc chuyển sang GRBL.
  • CNC Shield có tự viết code Arduino được không, hay bắt buộc dùng GRBL? Tự viết được. Khai báo STEP X/Y/Z ở chân 2, 3, 4, DIR ở chân 5, 6, 7 và kéo chân 8 (ENABLE) xuống LOW trong setup(). GRBL chỉ cần thiết khi muốn chạy G-code và nội suy nhiều trục.
  • Vì sao motor quay đúng ở tốc độ thấp nhưng tăng tốc thì kêu và dừng? Motor vượt quá tần số khởi động hoặc mô-men không đủ ở tốc độ cao. Đặt setAcceleration nhỏ hơn để motor tăng tốc từ từ, giảm tốc độ tối đa hoặc tăng điện áp nguồn motor trong giới hạn của driver.
  • Code chạy được với A4988 nhưng sang TB6600 thì mất bước, vì sao? Driver opto cần xung rộng hơn và thời gian thiết lập DIR dài hơn. Đặt setMinPulseWidth(5) đến 10 trong AccelStepper, kiểm tra tần số tối đa của TB6600 (thường khoảng 20 kHz) và cách đấu chung dương hay chung âm.
  • Tính tốc độ vòng/phút từ số bước/giây như thế nào? Lấy bước/giây × 60 rồi chia cho số bước mỗi vòng nhân hệ số vi bước. Ví dụ 4.000 bước/giây, motor 200 bước, vi bước 1/16: 4.000 × 60 ÷ 3.200 = 75 vòng/phút.
  • Có nên dùng thư viện Stepper.h có sẵn trong Arduino IDE không? Chỉ nên dùng để học hoặc chạy motor nhỏ 28BYJ-48. Hàm step() chặn chương trình, không có tăng tốc và không được thiết kế cho driver STEP/DIR, nên dự án thực tế nên dùng AccelStepper hoặc MobaTools.
  • Làm sao dừng khẩn cấp động cơ bước khi đang chạy bằng code? Với AccelStepper, gọi stop() để motor giảm tốc dừng theo gia tốc đã đặt, hoặc gọi setCurrentPosition() với vị trí hiện tại để dừng ngay. Với FastAccelStepper dùng forceStop(). Tuy vậy dừng khẩn cấp an toàn thật sự phải cắt chân ENABLE hoặc nguồn motor bằng nút phần cứng.
3.793 reviews

Tin tức liên quan

Mô Tơ Điện 1 Pha, 3 Pha 220V/380V: Bảng Giá Theo kW

Mô Tơ Điện 1 Pha, 3 Pha 220V/380V: Bảng Giá Theo kW

06 thg 11 2026 13:03

Mô tơ điện 3 pha 380V 4 cực giá 920.000 – 17.440.000 đ (0.37 – 30kW); mô tơ 1 pha 220V YL, YC giá 1.070.000 – 5.840.000 đ (0.37 – 3.7kW). Kèm cách chọn 1 pha hay 3 pha, số cực theo máy.
Đọc tiếp
Hộp giảm tốc harmonic: thông số, model CSF, SHF và cách chọn

Hộp giảm tốc harmonic: thông số, model CSF, SHF và cách chọn

14 thg 10 2026 15:12

Hộp giảm tốc harmonic (strain wave) size 14 – 32, tỉ số 1/50 – 1/120, mô men 5,4 – 137 Nm. Cách đọc tem, phân loại CSF, CSG, SHF-2UH, SHF-2UJ, SHF-2SO, SHD-2SH và cách chọn theo servo.
Đọc tiếp
Khám phá Bí Quyết Điều Khiển Động Cơ RC Servo Chính Xác Bằng STM32F4

Khám phá Bí Quyết Điều Khiển Động Cơ RC Servo Chính Xác Bằng STM32F4

15 thg 4 2025 20:44

Điều khiển động cơ RC Servo bằng STM32F4 mang đến độ chính xác cao và khả năng tùy chỉnh tín hiệu PWM tối ưu. Bài viết này hướng dẫn từ cấu hình bộ định thời, lập trình tín hiệu PWM, đến tối ưu hóa hiệu suất động cơ. Đây là giải pháp lý tưởng cho kỹ sư điện, kỹ sư cơ khí và các doanh nghiệp công nghiệp.
Đọc tiếp
Điều khiển động cơ RC servo bằng PWM: chu kỳ, độ rộng xung và cách tạo xung bằng timer

Điều khiển động cơ RC servo bằng PWM: chu kỳ, độ rộng xung và cách tạo xung bằng timer

10 thg 10 2026 17:36

Điều khiển động cơ RC servo bằng PWM: chu kỳ 20 ms, độ rộng xung 500–2500 µs, tính prescaler cho AVR, STM32, ESP32, PCA9685, mạch 555 và cách đo kiểm.
Đọc tiếp
Cách Điều Khiển Động Cơ DC Servo Chính Xác Bằng Giải Thuật PID

Cách Điều Khiển Động Cơ DC Servo Chính Xác Bằng Giải Thuật PID

12 thg 10 2026 08:32

Điều khiển động cơ DC Servo bằng giải thuật PID mang lại sự ổn định và hiệu suất cao cho hệ thống công nghiệp. Tìm hiểu cách áp dụng Proportional-Integral-Derivative, vi điều khiển và encoder để tối ưu hóa tốc độ và vị trí của động cơ. Phương pháp này được sử dụng rộng rãi trong robot, dây chuyền sản xuất và các hệ thống tự động hóa.
Đọc tiếp