Community project

High-Speed Line-Following Car

Arduino
Photo of High-Speed Line-Following Car
Generated with AI

huy lê

Published October 3, 2026

This high-speed line-following car uses an 8-channel analog sensor array to detect and track a black line on a white surface, with an Arduino Uno running a PID control algorithm to steer two micro metal gear motors at speeds up to 220 RPM. The TB6612FNG motor driver provides independent speed and direction control for each motor, while dual 18650 cells with protection circuitry deliver stable 5V logic power and motor drive voltage.

This guide provides a complete wiring diagram, detailed parts list, and step-by-step assembly instructions for mounting all components on a chassis frame. You'll also get the full Arduino firmware with PID tuning parameters, calibration routines, and motor control logic ready to upload. The assembly section covers proper capacitor placement for noise filtering, sensor alignment for accurate line detection, and pre-flight checks to ensure reliable operation before your first test run.

Wiring diagram

Wiring diagram for High-Speed Line-Following Car

Gather all the parts

QtyComponent
1

Mạch lái hai động cơ TB6612FNG

Mạch công suất hai kênh nhận lệnh từ Nano để đổi chiều và điều chỉnh tốc độ hai động cơ N20.

1

N20-6V-300RPM Micro Metal Gear Motor

N20 hộp số kim loại 500 RPM @ 6 V

N20 form-factor brushed DC micro metal gear motor rated 6V with about 300 RPM no-load speed. Two bare motor terminals connect directly to a motor driver output channel such as DRV8833 AOUT1/AOUT2 or BOUT1/BOUT2. Direction and speed are controlled by the motor driver. No firmware library is required for the motor itself.

1

N20-6V-300RPM Micro Metal Gear Motor

N20 hộp số kim loại 500 RPM @ 6 V

N20 form-factor brushed DC micro metal gear motor rated 6V with about 300 RPM no-load speed. Two bare motor terminals connect directly to a motor driver output channel such as DRV8833 AOUT1/AOUT2 or BOUT1/BOUT2. Direction and speed are controlled by the motor driver. No firmware library is required for the motor itself.

1

18650 Li-ion Cell

Li-ion 18650, ≥5C

18650 lithium-ion cell, nominal 3.7 V, ~2500 mAh. Common for higher-capacity portable / battery-bank style projects; needs a holder and protection / charger circuit.

1

18650 Li-ion Cell

Li-ion 18650, ≥5C

18650 lithium-ion cell, nominal 3.7 V, ~2500 mAh. Common for higher-capacity portable / battery-bank style projects; needs a holder and protection / charger circuit.

1

Rocker Switch

Công tắc nguồn ≥3 A

Classic compact panel-mount rocker switch for on/off power control in enclosures.

1

Mảng cảm biến dò line 8 kênh analog dạng thẳng 5 V

Bo mạch thẳng có tám mắt hồng ngoại, tạo điện áp theo độ sáng để Nano xác định vị trí vạch đen.

1

Mạch bảo vệ pin Li-ion 2S có cổng P+/P-

Bo mạch bảo vệ hai cell Li-ion mắc nối tiếp khỏi quá xả và quá dòng.

1

Tụ điện phân 10 µF 25 V

10 µF 25 V

Tụ có cực giúp giảm sụt áp và nhiễu trên nguồn động cơ của TB6612FNG.

1

Tụ gốm mã 104, 0,1 µF 50 V

104 (0,1 µF), 50 V

Tụ không phân cực giúp lọc nhiễu cao tần trên nguồn động cơ của TB6612FNG.

1

Tụ điện phân 10 µF 25 V

10 µF 25 V

Tụ có cực giúp giữ nguồn logic 5 V ổn định cho TB6612FNG.

1

Tụ gốm mã 104, 0,1 µF 50 V

104 (0,1 µF), 50 V

Tụ không phân cực giúp lọc nhiễu cao tần trên nguồn logic 5 V của TB6612FNG.

Assemble it in 8 steps

1. Bố trí các phần trên khung

Nhìn từ trên xuống: đặt line_sensor_8 chạy ngang sát mép đầu xe, tám mắt quay xuống mặt đường. Đặt bánh tự lựa ngay sau hoặc ngay dưới vùng giữa của cảm biến nhưng không che mắt. Đặt motor_left ở bên trái và motor_right ở bên phải, ngang trục bánh. Đặt Arduino Nano ở giữa thân xe, đặt tb6612_1 sát phía sau Nano để bảy dây điều khiển ngắn nhất có thể. Đặt cell_1, cell_2 và bms_2s thấp sát sàn ở cuối xe để xe cân bằng.

  • Đo chiều dài thật của mảng cảm biến trước khi khoan; loại thẳng thường dài khoảng 85–95 mm.
  • Giữ mặt mắt cảm biến cách mặt đường khoảng 2,5–3 mm để nó phân biệt rõ vạch đen và nền sáng.
  • Đặt cảm biến quá thấp có thể làm nó cạ mặt đường; đặt quá cao khiến tín hiệu yếu và xe khó bám vạch.

2. Nối hai cell với mạch bảo vệ

Khi công tắc đang tắt, mắc cell_1 và cell_2 nối tiếp: cell_1 GND → bms_2s B- (đầu âm của bộ pin), cell_1 +V → cell_2 GND và bms_2s B1 (điểm giữa hai pin), cell_2 +V → bms_2s B+ (đầu dương của bộ pin). Đây là bộ pin 2S: khoảng 7,4 V danh định và có thể lên 8,4 V khi vừa sạc đầy.

  • Dùng dây nguồn đủ to và bọc kín mọi mối nối pin.
  • Không được đảo B-, B1 và B+; đấu sai pin Li-ion có thể làm dây hoặc mạch bảo vệ nóng rất nhanh.

3. Tạo đường nguồn sau công tắc

Nối bms_2s P+ → power_switch T1 (nguồn được bảo vệ vào công tắc). Nối power_switch T2 → VIN của Arduino Nano và → VM của tb6612_1; đây là đường đỏ 7,4–8,4 V. Nối bms_2s P- → GND Nano → GND tb6612_1 → GND line_sensor_8; đây là bus GND chung màu đen. Đi dây VM và GND tới tb6612_1 ngắn và dày hơn các dây tín hiệu.

  • Tạo một điểm chia ngay sau công tắc rồi đi một nhánh tới VIN Nano và một nhánh tới VM driver để sơ đồ gọn, dễ kiểm tra.
  • Chỉ nối nguồn pin sau công tắc vào VIN của Nano, không nối vào chân 5V; 7,4–8,4 V ở chân 5V có thể làm hỏng Nano, cảm biến và driver.

4. Nối nguồn logic 5 V

Nối chân 5V của Arduino Nano → VCC của tb6612_1 (nguồn logic) và → VCC của line_sensor_8 (nguồn cho cảm biến). Vẫn giữ các chân GND của Nano, driver và cảm biến nối chung với P- của bms_2s. Nếu board cảm biến thực tế có chân LEDON hoặc EN, nối LEDON/EN → 5V để bật đèn hồng ngoại.

  • Đi cặp dây 5V và GND của cảm biến cùng nhau, sát thân xe và tránh chạy song song dài với dây động cơ.
  • Nguồn 5V này lấy từ ổn áp trên Nano. Nếu Nano nóng nhanh khi chạy, tắt công tắc ngay; không tự nối thêm nguồn 5V khác vào đường này khi Nano đang nhận nguồn qua VIN.

5. Đặt đúng bốn tụ lọc sát TB6612

Hàn cap_vm_10u và cap_vm_100n song song giữa VM và GND ngay sát chân nguồn của tb6612_1: cap_vm_10u chân + → VM, chân có sọc - → GND; cap_vm_100n chân 1 → VM, chân 2 → GND. Hàn cap_vcc_10u và cap_vcc_100n song song giữa VCC và GND ngay sát chân logic của tb6612_1: cap_vcc_10u chân + → VCC, chân có sọc - → GND; cap_vcc_100n chân 1 → VCC, chân 2 → GND. Tụ gốm 104 là 0,1 µF và không có chiều.

  • Bốn tụ không mắc nối tiếp: mỗi cặp có hai chân cùng chạm vào cùng hai đường nguồn/mass.
  • Tụ 10 µF 25 V dùng ở cả VM 7,4–8,4 V và VCC 5 V đều có mức chịu áp dư an toàn.
  • Đảo cực tụ điện phân có thể làm tụ rò, nóng hoặc hỏng. Không dùng dây dài để kéo tụ đi xa driver vì sẽ giảm tác dụng chống nhiễu.

6. Nối động cơ và bảy dây điều khiển

Nối tb6612_1 AO1 → motor_left M+ và AO2 → motor_left M- (đầu ra động cơ trái). Nối BO1 → motor_right M+ và BO2 → motor_right M- (đầu ra động cơ phải). Nối Nano D8 → STBY (bật driver), D4 → AIN1 và D5 → AIN2 (đặt chiều động cơ trái), D9 → PWMA (đặt tốc độ trái), D6 → BIN1 và D7 → BIN2 (đặt chiều động cơ phải), D10 → PWMB (đặt tốc độ phải).

  • Xoắn nhẹ từng cặp dây ra động cơ để giảm nhiễu; giữ chúng xa các dây OUT1–OUT8 của cảm biến.
  • Nếu một bánh quay ngược sau thử nghiệm, tắt nguồn rồi đảo hai dây của riêng động cơ đó.
  • Không để AO1/AO2 hoặc BO1/BO2 chạm nhau khi pin đang nối; điều đó có thể làm driver quá dòng.

7. Nối tám tín hiệu cảm biến theo thứ tự

Nối line_sensor_8 VCC → 5V (nguồn), GND → GND (mass), OUT1 → A0 (tín hiệu), OUT2 → A1 (tín hiệu), OUT3 → A2 (tín hiệu), OUT4 → A3 (tín hiệu), OUT5 → A4 (tín hiệu), OUT6 → A5 (tín hiệu), OUT7 → A6 (tín hiệu), OUT8 → A7 (tín hiệu). Đi tám dây tín hiệu thành một bó từ cảm biến về Nano và tránh bó chung với dây động cơ.

  • Trước khi cố định dây, xác định OUT1 nằm ở đầu trái hay đầu phải của board khi nhìn từ phía trước xe.
  • A6 và A7 trên Nano chỉ dùng để đọc analog; đó chính là chức năng cần cho OUT7 và OUT8.
  • Không cắm nhầm VCC vào GND; cấp nguồn ngược có thể làm hỏng board cảm biến.

8. Kiểm tra trước khi cho xe chạy

Khi công tắc tắt, kiểm tra cực tụ hóa, B-/B1/B+, VIN Nano, VM driver và một bus GND chung. Nhấc bánh xe khỏi mặt bàn, cắm Nano qua USB và nhấn Deploy trong Schematik. Khi bật công tắc, đèn Nano sáng khoảng 2,5 giây; trong thời gian đó cầm xe quét tám mắt qua cả nền sáng lẫn vạch đen để hiệu chuẩn.

  • Sau vài lần chạy ngắn, tắt nguồn rồi chạm nhanh vùng ổn áp Nano và TB6612: chúng chỉ nên ấm nhẹ.
  • Nếu xe bẻ sai phía, kiểm tra thứ tự OUT1–OUT8 trước; sau đó mới xem xét đảo dây động cơ.
  • Bộ pin 2S đầy có 8,4 V. Dừng thử ngay nếu Nano, TB6612, dây nguồn hoặc tụ điện nóng bất thường.

Review all connections

1. Connections between "cell_1" and "Arduino"

Functioncell_1Arduino
groundGND → Mạch bảo vệ pin Li-ion 2S có cổng P+/P- B-EXT
power+V → 18650 Li-ion Cell GNDEXT

2. Connections between "cell_2" and "Arduino"

Functioncell_2Arduino
power+V → Mạch bảo vệ pin Li-ion 2S có cổng P+/P- B+EXT

3. Connections between "bms_2s" and "Arduino"

Functionbms_2sArduino
analogB1 → 18650 Li-ion Cell +VEXT
powerP+ → Rocker Switch T1EXT
groundP-GND

4. Connections between "tb6612_1" and "Arduino"

Functiontb6612_1Arduino
groundGNDGND
powerVCC5V
digitalSTBYGPIO 8
digitalAIN1GPIO 4
digitalAIN2GPIO 5
pwmPWMAGPIO 9
digitalBIN1GPIO 6
digitalBIN2GPIO 7
pwmPWMBGPIO 10
powerVMVIN

5. Connections between "motor_left" and "Arduino"

Functionmotor_leftArduino
dataM+ → Mạch lái hai động cơ TB6612FNG AO1EXT
dataM- → Mạch lái hai động cơ TB6612FNG AO2EXT

6. Connections between "motor_right" and "Arduino"

Functionmotor_rightArduino
dataM+ → Mạch lái hai động cơ TB6612FNG BO1EXT
dataM- → Mạch lái hai động cơ TB6612FNG BO2EXT

7. Connections between "line_sensor_8" and "Arduino"

Functionline_sensor_8Arduino
powerVCC5V
groundGNDGND
analogOUT1GPIO 14
analogOUT2GPIO 15
analogOUT3GPIO 16
analogOUT4GPIO 17
analogOUT5GPIO 18
analogOUT6GPIO 19
dataOUT7GPIO 20
dataOUT8GPIO 21

8. Connections between "cap_vm_10u" and "Arduino"

Functioncap_vm_10uArduino
power+ → Mạch lái hai động cơ TB6612FNG VMEXT
ground-GND

9. Connections between "cap_vm_100n" and "Arduino"

Functioncap_vm_100nArduino
power1 → Mạch lái hai động cơ TB6612FNG VMEXT
ground2GND

10. Connections between "cap_vcc_10u" and "Arduino"

Functioncap_vcc_10uArduino
power+ → Mạch lái hai động cơ TB6612FNG VCCEXT
ground-GND

11. Connections between "cap_vcc_100n" and "Arduino"

Functioncap_vcc_100nArduino
power1 → Mạch lái hai động cơ TB6612FNG VCCEXT
ground2GND

12. Connections between "power_switch" and "Arduino"

Functionpower_switchArduino
powerT2VIN

Deploy the firmware

#include <Arduino.h>
#include <QTRSensors.h>

constexpr uint8_t SENSOR_COUNT = 8;
constexpr uint16_t LINE_CENTER = 3500;

constexpr uint8_t STBY_PIN = 8;
constexpr uint8_t AIN1_PIN = 4;
constexpr uint8_t AIN2_PIN = 5;
constexpr uint8_t PWMA_PIN = 9;
constexpr uint8_t BIN1_PIN = 6;
constexpr uint8_t BIN2_PIN = 7;
constexpr uint8_t PWMB_PIN = 10;

constexpr int BASE_SPEED = 150;
constexpr int MAX_SPEED = 220;
constexpr int REVERSE_MAX_SPEED = 100;

float kp = 0.07f;
float ki = 0.0f;
float kd = 0.6f;

QTRSensors qtr;
uint16_t sensorValues[SENSOR_COUNT];
int lastError = 0;
float integral = 0.0f;

void driveMotor(int speed, uint8_t in1, uint8_t in2, uint8_t pwmPin) {
  if (speed >= 0) {
    digitalWrite(in1, HIGH);
    digitalWrite(in2, LOW);
  } else {
    digitalWrite(in1, LOW);
    digitalWrite(in2, HIGH);
    speed = -speed;
  }
  analogWrite(pwmPin, constrain(speed, 0, 255));
}

void setup() {
  const uint8_t sensorPins[SENSOR_COUNT] = {A0, A1, A2, A3, A4, A5, A6, A7};
  qtr.setTypeAnalog();
  qtr.setSensorPins(sensorPins, SENSOR_COUNT);

  pinMode(STBY_PIN, OUTPUT);
  pinMode(AIN1_PIN, OUTPUT);
  pinMode(AIN2_PIN, OUTPUT);
  pinMode(PWMA_PIN, OUTPUT);
  pinMode(BIN1_PIN, OUTPUT);
  pinMode(BIN2_PIN, OUTPUT);
  pinMode(PWMB_PIN, OUTPUT);
  digitalWrite(STBY_PIN, HIGH);

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);
  for (uint16_t i = 0; i < 250; ++i) {
    qtr.calibrate();
    delay(10);  // khoảng 2,5 giây để lắc xe qua nền trắng và vạch đen
  }
  digitalWrite(LED_BUILTIN, LOW);
}

void loop() {
  const int position = qtr.readLineBlack(sensorValues);
  const int error = position - LINE_CENTER;

  integral += error;
  integral = constrain(integral, -3000.0f, 3000.0f);
  const int derivative = error - lastError;
  const float correction = kp * error + ki * integral + kd * derivative;
  lastError = error;

  const int leftSpeed = constrain(static_cast<int>(BASE_SPEED + correction), -REVERSE_MAX_SPEED, MAX_SPEED);
  const int rightSpeed = constrain(static_cast<int>(BASE_SPEED - correction), -REVERSE_MAX_SPEED, MAX_SPEED);

  driveMotor(leftSpeed, AIN1_PIN, AIN2_PIN, PWMA_PIN);
  driveMotor(rightSpeed, BIN1_PIN, BIN2_PIN, PWMB_PIN);
}

Remix this project

Make it yours in one click

Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.

Open in Schematik