Lập trình

Hàm và thư viện Arduino - viết code robot gọn, sạch, tái sử dụng

7 phút đọc05/07/2026HocLapTrinhRobot
Hàm và thư viện Arduino - viết code robot gọn, sạch, tái sử dụng

Cách viết hàm có tham số và giá trị trả về cho robot, quy tắc đặt tên, rồi cài và dùng thư viện Arduino đúng cách - kèm tiêu chí chọn thư viện tốt. Trong bài viết này, chúng ta sẽ cùng tìm hiểu chi tiết và ứng dụng thực tế trong robot.

Vì sao cần hàm? Câu chuyện code mì sợi

Robot tránh vật cản phiên bản đầu tay của hầu hết người học: 120 dòng dồn hết vào loop(), đoạn điều khiển motor lặp lại 6 lần chỉ khác vài con số, sửa tốc độ phải tìm sửa 6 chỗ. Thêm tính năng thứ ba thì chính tác giả cũng lạc trong code của mình — hiện tượng "mì spaghetti" kinh điển.

Hàm là cách gói một việc thành khối có tên gọi được nhiều lần. Nó biến 120 dòng hỗn độn thành 15 dòng kể chuyện:

cpp
void loop() {
  long d = readDistanceCm();
  if (d < SAFE_CM) {
    avoidObstacle();
  } else {
    driveForward(NORMAL_SPEED);
  }
}

Đọc loop này như đọc văn — ai cũng hiểu robot làm gì mà chưa cần xem ruột từng hàm.

Giải phẫu một hàm

cpp
//  kiểu trả về   tên hàm      tham số
long          readDistanceCm()          {
  digitalWrite(TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG, LOW);
  long duration = pulseIn(ECHO, HIGH, 30000);
  return duration * 0.0343 / 2;    // trả kết quả về nơi gọi
}
  • Kiểu trả về: long — hàm "đưa lại" một số; void — hàm chỉ làm, không trả gì
  • Tham số: đầu vào tùy biến mỗi lần gọi
  • return: kết thúc hàm và gửi giá trị về

Tham số làm hàm trở nên mạnh

So sánh hai thế hệ:

cpp
// Thế hệ 1: mỗi hành vi một hàm cứng
void goSlowly()  { ledcWrite(ENA, 100); ledcWrite(ENB, 100); }
void goNormal()  { ledcWrite(ENA, 150); ledcWrite(ENB, 150); }
void goFast()    { ledcWrite(ENA, 230); ledcWrite(ENB, 230); }

// Thế hệ 2: MỘT hàm, tham số quyết định
void drive(int left, int right) {
  digitalWrite(IN1, left >= 0);  digitalWrite(IN2, left < 0);
  digitalWrite(IN3, right >= 0); digitalWrite(IN4, right < 0);
  ledcWrite(ENA, abs(left));
  ledcWrite(ENB, abs(right));
}

drive(150, 150) đi thẳng, drive(80, 150) rẽ trái mềm, drive(-120, 120) xoay tại chỗ, drive(0, 0) dừng — một hàm 6 dòng thay cả chục hàm cứng, và là hàm nền của mọi thuật toán chuyển động sau này (dò line PID gọi chính drive(BASE + output, BASE - output)).

Quy tắc đặt tên đáng theo từ ngày đầu

  • Hàm là hành động → bắt đầu bằng động từ: readDistance, driveForward, calibrateSensors
  • camelCase cho hàm/biến, HẰNG_VIẾT_HOA cho hằng
  • Tên nói thật: hàm tên readDistance mà lại điều khiển motor là gài bẫy đồng đội
  • Một hàm một việc; hàm dài quá màn hình là ứng viên tách đôi

Thư viện - đứng trên vai người khổng lồ

Thư viện (library) là bộ hàm ai đó đóng gói sẵn cho một linh kiện hay bài toán. Điều khiển servo tử tế cần code xung khá tinh tế — hoặc hai dòng với thư viện:

cpp
#include <ESP32Servo.h>

Servo myServo;

void setup() {
  myServo.attach(4);
  myServo.write(90);     // quay đến 90 độ - xong!
}

Cài thư viện 3 cách

  1. Library Manager (chính thống): Sketch - Include Library - Manage Libraries, gõ tên, Install — tự xử lý cập nhật
  2. File ZIP: Add .ZIP Library — cho thư viện ngoài kho chính thức (GitHub)
  3. Đi kèm gói board: cài gói ESP32 là có sẵn WiFi.h, Wire.h, BluetoothSerial.h — không phải cài riêng

Đọc hiểu thư viện qua cú pháp chấm

myServo.write(90) — dấu chấm nghĩa là "gọi hàm write của đối tượng myServo". Mỗi thư viện định nghĩa một "loài" đối tượng (Servo, Adafruit_MPU6050...) với bộ hàm riêng; khai một con là có một cá thể. Chưa cần học sâu lập trình hướng đối tượng — nhận diện được mẫu đối_tượng.hàm(tham_số) là dùng được 95% thư viện Arduino.

Bộ thư viện quen mặt trên robot ESP32

Thư việnViệcGhi chú
ESP32ServoServo trên ESP32Servo.h gốc không chạy ESP32
Adafruit MPU6050Đọc gia tốc/gyroKèm Adafruit Unified Sensor
DHT sensor libraryDHT11/DHT22Của Adafruit
Adafruit SSD1306Màn OLED I2CKèm Adafruit GFX
PubSubClientMQTTChuẩn cho IoT
ESP32EncoderĐọc encoder bằng phần cứng PCNTĐếm triệu xung/giây

Tiêu chí chọn thư viện tốt

Cùng một cảm biến có thể có 5 thư viện — chọn theo: có ví dụ đi kèm chạy được ngay (File - Examples xuất hiện sau khi cài); còn được cập nhật (xem GitHub); ghi rõ hỗ trợ ESP32 (thư viện viết cho AVR/Uno có thể lỗi biên dịch hoặc lỗi ngầm về timing); và nhiều người dùng (sao GitHub, được Library Manager gợi ý đầu).

Xung đột và lỗi thư viện thường gặp

  • "Multiple libraries were found for X.h": hai thư viện trùng tên file — gỡ bớt trong thư mục libraries, giữ bản đúng cho ESP32
  • Biên dịch lỗi cả trăm dòng sau khi thêm thư viện: thường thư viện không hỗ trợ ESP32 — tìm bản thay thế có chữ ESP32
  • Servo giật loạn khi thêm thư viện khác: tranh chấp timer phần cứng giữa các thư viện (Servo, tone, LEDC) — ESP32Servo cho phép chỉ định timer để né
  • Include rồi mà "was not declared": thiếu thư viện phụ thuộc (Adafruit hay cần Unified Sensor + BusIO) — đọc mục Dependencies khi cài

Tự đóng gói: từ hàm đến file dùng lại

Nấc cuối của kỹ năng này: bộ hàm motor của bạn dùng tốt qua 3 dự án → tách thành motor.h (tab mới trong sketch) → chép sang dự án mới là chạy. Đây chính là "thư viện cá nhân" phôi thai — đội thi đấu nào cũng có kho như vậy, và là bước đệm tự nhiên lên viết class C++ thật khi bạn sẵn sàng.

Câu hỏi thường gặp

Hàm nên viết trước hay sau loop()?

Trên Arduino IDE: đâu cũng chạy (IDE tự sinh khai báo trước). Thói quen tốt: hằng số và biến toàn cục trên cùng, setup/loop giữa, hàm tự viết dưới cùng — người đọc thấy bức tranh lớn trước chi tiết.

Tham số truyền vào hàm có bị hàm sửa mất không?

Kiểu cơ bản (int, float, bool) được chép vào hàm — sửa bản chép, bản gốc nguyên vẹn. Mảng thì ngược lại: hàm nhận địa chỉ và sửa là sửa thật. Biết ranh giới này tránh được nhóm bug khó chịu khi bắt đầu truyền mảng cảm biến vào hàm.

Thư viện có làm code chậm đi không?

Không đáng kể với thư viện tử tế — trình biên dịch loại phần không dùng. Cái giá thật của thư viện là hộp đen: khi lỗi nằm trong thư viện, bạn khó thấy. Vì vậy nên hiểu nguyên lý linh kiện (đọc các bài cảm biến ở mục Kiến thức) ngay cả khi dùng thư viện cho nhanh.

Khi nào nên TỰ viết thay vì dùng thư viện?

Học nguyên lý (tự viết đọc HC-SR04 một lần cho hiểu, rồi dùng gì cũng được); thư viện quá nặng cho nhu cầu (kéo cả framework chỉ để nháy LED); hoặc cần kiểm soát timing tuyệt đối (vòng PID tốc độ cao). Còn lại — servo, màn hình, MQTT — cứ để người khổng lồ cõng.

Tài nguyên tải về

Tải bản PDF của bài viết để in giáo án hoặc gửi trước cho học viên.

Tải PDF
Chia sẻ bài viết