2WD robot car chassis kit with ESP32-S3, TB6612FNG motor driver, and 5-channel IR line sensor array following a black line

ระดับกลาง

สร้างหุ่นยนต์เดินตามเส้น

หุ่นยนต์เซ็นเซอร์การเคลื่อนไหว

ขั้นต่อไปที่เหนือกว่ารถยนต์หุ่นยนต์พื้นฐาน คือการอ่านพื้นแบบเรียลไทม์และขับเคลื่อนไปตามเส้นโดยอัตโนมัติ

รวมชิ้นส่วนจริง 7 รายการ

ราคารวมชุดนี้: 1,684.00 ฿

ยังไม่รวมส่วนลดคำสั่งซื้อที่คุณอาจได้รับตอนชำระเงิน

สิ่งที่คุณต้องใช้

เป้าหมายของโครงการ

โครงการนี้ต่อยอดจากฐานหุ่นยนต์สองล้อแบบเดียวกับที่ใช้ในรถหุ่นยนต์พื้นฐาน โดยเพิ่มอาร์เรย์เซ็นเซอร์ที่หันลงด้านล่างเพื่อให้หุ่นยนต์สามารถอ่านพื้นด้านล่างและควบคุมตัวเองให้เคลื่อนที่ไปตามเส้นได้โดยอัตโนมัติ ซึ่งเป็นการก้าวไปอีกขั้นจากการขับขี่ด้วยมือหรือที่ตั้งโปรแกรมไว้ล่วงหน้าไปสู่การควบคุมแบบวงปิด

คอนโทรลเลอร์ทำอะไร

ESP32-S3 ทำงานวนลูปควบคุม: อ่านอาร์เรย์เซ็นเซอร์เส้น, ตัดสินใจว่าหุ่นยนต์อยู่ห่างจากจุดศูนย์กลางเท่าใด, คำนวณการแก้ไขการบังคับเลี้ยว, และส่งคำสั่งความเร็วที่อัปเดตไปยังแต่ละล้อผ่านไดรเวอร์มอเตอร์ ลูปนี้จะวนซ้ำอย่างต่อเนื่องและเร็วพอที่หุ่นยนต์จะสามารถตอบสนองต่อเส้นแบบเรียลไทม์ขณะเคลื่อนที่

แชสซีและมอเตอร์ทำอะไร

ชุดแชสซี 2WD มีชุดขับเคลื่อนทางกายภาพ ซึ่งประกอบด้วยล้อสองล้อที่ขับเคลื่อนอิสระ โดยแต่ละล้อหมุนด้วยมอเตอร์เกียร์ DC ของตัวเอง เนื่องจากล้อเป็นอิสระ หุ่นยนต์จึงบังคับทิศทางโดยการใช้มอเตอร์ทั้งสองที่ความเร็วต่างกัน ไม่ใช่โดยการหมุนชุดล้อ ซึ่งคล้ายกับรถถัง พลังงานสำหรับมอเตอร์มาจากแบตเตอรี่ 18650 ซึ่งแยกจากแหล่งจ่ายไฟลอจิกของคอนโทรลเลอร์ที่ไดรเวอร์มอเตอร์ต้องการ

ไดรเวอร์มอเตอร์ทำอะไร

TB6612FNG อยู่ระหว่างคอนโทรลเลอร์และมอเตอร์ พินของคอนโทรลเลอร์ไม่สามารถจ่ายกระแสไฟฟ้าที่มอเตอร์ DC ดึงได้อย่างปลอดภัย ดังนั้นไดรเวอร์จะรับสัญญาณลอจิกกำลังต่ำจากคอนโทรลเลอร์และใช้เพื่อเปิดและปิดแหล่งจ่ายไฟมอเตอร์ที่มีกระแสไฟฟ้าสูงกว่า (และในทิศทางใด) ซึ่งทำหน้าที่เป็นเครื่องขยายกระแสและสวิตช์ทิศทางสำหรับมอเตอร์ทั้งสองอย่างอิสระ

อาร์เรย์เซ็นเซอร์เส้นทำอะไร

อาร์เรย์ติดตามเส้น IR 5 ช่องติดตั้งโดยหันหน้าไปทางพื้น เซ็นเซอร์ทั้งห้าตัวแต่ละตัวจะรายงานโดยอิสระว่ากำลังมองเห็นเส้นสีเข้มหรือพื้นผิวที่สว่างกว่าอยู่ข้างใต้หรือไม่ เมื่ออ่านรวมกัน รูปแบบที่เกิดขึ้นบนเซ็นเซอร์ทั้งห้าตัว ซึ่งได้แก่ เซ็นเซอร์ตัวใดมองเห็นเส้นและตัวใดไม่เห็น จะบอกคอนโทรลเลอร์ได้อย่างแม่นยำว่าหุ่นยนต์อยู่ห่างจากจุดศูนย์กลางเมื่อเทียบกับเส้นเป็นระยะทางเท่าใด ไม่ใช่แค่ว่าอยู่บนเส้นหรือหลุดจากเส้นเท่านั้น

การบังคับเลี้ยวแบบสัดส่วน

แนวคิดการควบคุมหลักในโครงการนี้คือการบังคับเลี้ยวแบบสัดส่วน แทนที่จะเป็นการบังคับเลี้ยวแบบบิ๊กแบง (เลี้ยวซ้ายสุด / เลี้ยวขวาสุด) แทนที่จะตอบสนองในลักษณะเดียวกันกับการเบี่ยงเบนใดๆ คอนโทรลเลอร์จะคำนวณว่ารูปแบบเซ็นเซอร์แสดงว่าหุ่นยนต์เบี่ยงออกจากจุดศูนย์กลางไปเท่าใด และปรับการแก้ไขให้เหมาะสม: การเบี่ยงเบนเล็กน้อยจะได้รับการแก้ไขที่เล็กน้อยและนุ่มนวล และการเบี่ยงเบนที่ใหญ่ขึ้นจะได้รับการแก้ไขที่แรงขึ้น ซึ่งจะผ่อนคลายลงอีกครั้งเมื่อหุ่นยนต์กลับมาอยู่ตรงกลางเส้น สิ่งนี้ทำให้การติดตามเส้นราบรื่นและเร็วกว่าวิธีการแบบทั้งหมดหรือไม่มีเลย

แนวคิดซอฟต์แวร์และไลบรารี

จัดโครงสร้างโค้ดของคุณเป็นสามขั้นตอนที่ชัดเจนในแต่ละลูป: อ่านค่าเซ็นเซอร์ทั้งห้าค่าลงในอาร์เรย์, คำนวณค่า "ข้อผิดพลาด" เดียวที่แสดงว่ารูปแบบนั้นเบี่ยงเบนจากจุดศูนย์กลางเท่าใด, จากนั้นแปลงข้อผิดพลาดนั้นเป็นคำสั่งความเร็วของมอเตอร์ซ้าย/ขวาแต่ละตัวที่ส่งผ่านไลบรารีไดรเวอร์มอเตอร์ การแยกสามขั้นตอนเหล่านี้ออกจากกันในโค้ดจะทำให้การแก้จุดบกพร่องแต่ละขั้นตอนเป็นอิสระได้ง่ายขึ้นมาก เช่น การพิมพ์รูปแบบเซ็นเซอร์ดิบและค่าข้อผิดพลาดที่คำนวณได้ก่อนที่คุณจะแตะมอเตอร์ด้วยซ้ำ

การทดสอบและการแก้ไขปัญหา

  • หุ่นยนต์ไม่ตรวจจับเส้นเลย — ตรวจสอบความสูงและระยะห่างของอาร์เรย์เซ็นเซอร์จากพื้น และยืนยันว่าเส้นมีคอนทราสต์เพียงพอเมื่อเทียบกับสีพื้นเพื่อให้เซ็นเซอร์ IR แยกแยะได้
  • หุ่นยนต์แกว่งไปมาอย่างรุนแรงแทนที่จะติดตามอย่างราบรื่น — การแก้ไขการบังคับเลี้ยวรุนแรงเกินไปสำหรับระยะห่างของเซ็นเซอร์และความเร็วปัจจุบัน สิ่งนี้ต้องมีการปรับแต่ง โดยทั่วไปคือการลดความแรงของค่าข้อผิดพลาดที่ถูกปรับขนาดเป็นการแก้ไข
  • หุ่นยนต์จะเคลื่อนที่ไปด้านใดด้านหนึ่งอย่างสม่ำเสมอแม้ในส่วนตรงของเส้น — ตรวจสอบมอเตอร์ที่ต่อสายผิดหรือทำงานได้ไม่ดีในด้านนั้นก่อนที่จะสันนิษฐานว่ามีปัญหาเซ็นเซอร์ การทดสอบง่ายๆ คือการใช้งานมอเตอร์ทั้งสองที่ความเร็วคงที่เท่ากันโดยไม่มีอินพุตจากเซ็นเซอร์ และดูว่าหุ่นยนต์ยังคงเคลื่อนที่ไปด้านใดด้านหนึ่งหรือไม่
  • หุ่นยนต์หลุดจากเส้นทั้งหมดเมื่อเลี้ยวหักศอก — นี่มักเป็นสัญญาณว่าการแก้ไขตามสัดส่วนถูกจำกัดไว้ต่ำเกินไปที่จะตอบสนองได้ทันเวลา ยืนยันว่าโค้ดของคุณอนุญาตให้มีการแก้ไขสูงสุดที่แรงพอสำหรับค่าข้อผิดพลาดขนาดใหญ่

การอัปเกรดในอนาคตแบบเลือกได้: การตรวจจับสิ่งกีดขวางด้านหน้า

เมื่อการติดตามเส้นเชื่อถือได้แล้ว ให้ดูโครงการระบบเตือนระยะทางสำหรับการเพิ่มการตรวจจับสิ่งกีดขวางด้านหน้าโดยใช้แนวคิดเซ็นเซอร์ตรวจจับระยะทางอัลตราโซนิกประเภท HC-SR04 เดียวกัน ซึ่งเป็นการเพิ่มเติมที่เป็นธรรมชาติที่ช่วยให้หุ่นยนต์หยุดหรือเปลี่ยนเส้นทางแทนที่จะขับชนสิ่งกีดขวางเส้น

การเดินสาย

  • ตัวยึดแบตเตอรี่ 18650 (2 ช่อง, การเดินสายอนุกรม, ~7.4V เล็กน้อย) → TB6612FNG VM ผ่านสวิตช์บนบอร์ดของตัวยึด
  • GND ของชุดแบตเตอรี่ → TB6612FNG GND และเชื่อมต่อกับกราวด์ร่วมกับ ESP32-S3 และอาร์เรย์ IR
  • ESP32-S3 3.3V → TB6612FNG VCC — แหล่งจ่ายไฟลอจิก
  • ESP32-S3 GPIO9 → TB6612FNG STBY (`MOTOR_STBY_PIN`) — ต้องขับเป็น HIGH เพื่อเปิดใช้งานเอาต์พุตไดรเวอร์
  • ESP32-S3 GPIO10 → TB6612FNG AIN1 (`AIN1_PIN`)
  • ESP32-S3 GPIO11 → TB6612FNG AIN2 (`AIN2_PIN`)
  • ESP32-S3 GPIO12 → TB6612FNG PWMA (`PWMA_PIN`)
  • ESP32-S3 GPIO13 → TB6612FNG BIN1 (`BIN1_PIN`)
  • ESP32-S3 GPIO14 → TB6612FNG BIN2 (`BIN2_PIN`)
  • ESP32-S3 GPIO21 → TB6612FNG PWMB (`PWMB_PIN`)
  • TB6612FNG A01/A02 → ขั้วมอเตอร์ DC ซ้าย
  • TB6612FNG B01/B02 → ขั้วมอเตอร์ DC ขวา
  • VCC ของอาร์เรย์เซ็นเซอร์ IR → 5V, GND → GND (ตรวจสอบโมดูลของคุณ — อาร์เรย์ IR 5 ช่องส่วนใหญ่ต้องการ 5V เพื่อความสว่างของตัวปล่อยที่สม่ำเสมอ บางตัวทำงานที่ 3.3V)
  • เอาต์พุดดิจิทัล 5 ตัวของอาร์เรย์ IR → ESP32-S3 GPIO1, GPIO2, GPIO4, GPIO5, GPIO6 (`IR_PINS[0..4]`)

รายการชิ้นส่วนนี้ไม่มีตัวแปลง buck แยกสำหรับแหล่งจ่ายไฟลอจิกของ ESP32-S3 เอง — บอร์ดพัฒนา S3 จำนวนมากมีตัวควบคุมบนบอร์ดบนพิน 5V/VIN ที่รองรับอินพุตที่สูงกว่า ดังนั้นคุณอาจสามารถจ่ายแรงดันแบตเตอรี่ดิบที่นั่นได้หากตัวควบคุมของบอร์ดเฉพาะของคุณรองรับ (ตรวจสอบเอกสารข้อมูลก่อน) มิฉะนั้นให้จ่ายไฟให้ S3 จาก USB-C ผ่านพาวเวอร์แบงก์ขนาดเล็กในขณะที่ทดสอบแบบไร้สาย GPIO0 และ GPIO3 เป็นพินสำหรับ strapping บน ESP32-S3 และหลีกเลี่ยงโดยตั้งใจ หากบอร์ดพัฒนาเฉพาะของคุณสงวน GPIO อื่นๆ สำหรับแฟลช/PSRAM บนบอร์ด ให้ทำการแมป `#define` ใหม่ให้เป็นสิ่งที่มีการต่อออกมาจริง โมดูลเซ็นเซอร์ IR แต่ละตัวมักจะมีโพเทนชิออมิเตอร์บนบอร์ดของตัวเองเพื่อปรับเกณฑ์แสง/มืด — ทำเช่นนั้นบนพื้นผิวแทร็กจริงของคุณก่อนที่จะเชื่อถือเอาต์พุตดิจิทัล HIGH/LOW และยืนยันเสมอว่า STBY เป็น HIGH ก่อนที่จะคาดหวังการตอบสนองของมอเตอร์ใดๆ

แผนภาพการต่อสาย

VM GND 3.3V → VCC GPIO9 → STBY GPIO10 → AIN1 GPIO11 → AIN2 GPIO12 → PWMA GPIO13 → BIN1 GPIO14 → BIN2 GPIO21 → PWMB A01/A02 B01/B02 VCC GND GPIO1 ESP32-S3 TB6612FNG IR array 5 digital outputs 18650 battery holder Battery pack left DC motor terminals right DC motor terminals 5V IR sensor array GND

โค้ดเริ่มต้น

// Line-following robot: 5-channel IR array + TB6612FNG dual motor driver

#define MOTOR_STBY_PIN 9
#define AIN1_PIN 10
#define AIN2_PIN 11
#define PWMA_PIN 12
#define BIN1_PIN 13
#define BIN2_PIN 14
#define PWMB_PIN 21

const int IR_PINS[5] = {1, 2, 4, 5, 6}; // far-left, left, center, right, far-right

const int BASE_SPEED = 150;   // 0-255
const int MAX_SPEED = 255;
const int TURN_GAIN = 60;     // how hard to correct per unit of error

void setMotor(int in1Pin, int in2Pin, int pwmPin, int speed) {
  speed = constrain(speed, -MAX_SPEED, MAX_SPEED);
  if (speed >= 0) {
    digitalWrite(in1Pin, HIGH);
    digitalWrite(in2Pin, LOW);
  } else {
    digitalWrite(in1Pin, LOW);
    digitalWrite(in2Pin, HIGH);
    speed = -speed;
  }
  analogWrite(pwmPin, speed); // Arduino-ESP32 core 3.x supports analogWrite() directly on PWM-capable pins
}

void setup() {
  Serial.begin(115200);

  pinMode(MOTOR_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);

  for (int i = 0; i < 5; i++) {
    pinMode(IR_PINS[i], INPUT);
  }

  digitalWrite(MOTOR_STBY_PIN, HIGH); // enable driver outputs

  Serial.println("Line follower ready.");
}

void loop() {
  int sensorVal[5];
  for (int i = 0; i < 5; i++) {
    sensorVal[i] = digitalRead(IR_PINS[i]); // assume HIGH = line detected; flip if your array is inverted
  }

  // Weighted position error: -2 (far left) ... 0 (centered) ... +2 (far right)
  int weights[5] = {-2, -1, 0, 1, 2};
  int weightedSum = 0;
  int activeCount = 0;

  for (int i = 0; i < 5; i++) {
    if (sensorVal[i] == HIGH) {
      weightedSum += weights[i];
      activeCount++;
    }
  }

  if (activeCount == 0) {
    // Line lost — stop rather than guess
    setMotor(AIN1_PIN, AIN2_PIN, PWMA_PIN, 0);
    setMotor(BIN1_PIN, BIN2_PIN, PWMB_PIN, 0);
    return;
  }

  int error = weightedSum; // simple proportional error, no averaging needed for 5 discrete sensors
  int correction = error * TURN_GAIN;

  int leftSpeed = BASE_SPEED + correction;
  int rightSpeed = BASE_SPEED - correction;

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

ไม่แน่ใจขั้นตอนไหน? ถามเรา