搜尋程式碼

第28/31課:汽車-6 SunFounder自動駕駛Arduino汽車使用 | Robojax

第28/31課:汽車-6 SunFounder自動駕駛Arduino汽車使用 | Robojax

喺呢個項目入面,我哋會用Arduino、一個超聲波感應器同兩個紅外線感應器,整一部基本嘅自動駕駛車。呢個係一個好正嘅入門項目,可以學到自主導航、感應器融合同決策邏輯。架車可以向前、向後行,仲可以轉彎避開障礙物,自己搵到一條暢通嘅路。呢個項目係基於SunFounder 3合1 Arduino套件,亦都係Robojax嘅Arduino課程一部分。

28-SunFounder-Car-6-Self-Driving-path

呢個項目唔單止係整一件玩具,佢係一個實用嘅入門,帶你認識自主機械人背後嘅核心概念。同樣嘅邏輯同感應器,喺現實世界嘅應用入面都有用到,例如機械人吸塵機、倉庫入面嘅自動導引車,甚至更加複雜嘅機械人導航系統。透過了解點樣將距離感應同簡單嘅導航規則結合,你可以整到好多唔同嘅項目,例如:

  • 整一部可以喺房間入面走動同避開傢俬嘅小型機械人。
  • 整一部可以跟住簡單路線行或者巡邏一個區域嘅自動車。
  • 學習點樣為更大嘅機械人項目實現基本嘅避障演算法。

硬件組件

呢個項目用咗SunFounder 3合1套件入面嘅組件。主要嘅零件包括:

  • Arduino Uno板
  • SunFounder 2WD或者3合1車架連摩打
  • 摩打驅動模組(例如L298N或者類似嘅)
  • HC-SR04超聲波距離感應器
  • 兩個紅外線障礙感應器
  • 杜邦線同埋摩打嘅電源

接線指南

car_7_8_28_self_driving

接線係令你部自動駕駛車郁得嘅關鍵第一步。啲連接好直接,但係你一定要逐條檢查清楚,避免整壞啲零件。接線背後嘅邏輯係將Arduino嘅控制腳駁去摩打驅動器同感應器,等Arduino可以讀取數據同發送指令。

  • 摩打驅動器腳(A-1B、A-1A、B-1B、B-1A):呢啲腳控制兩個摩打嘅速度同方向。佢哋駁去Arduino嘅第5、6、9同10腳,呢啲腳支援PWM,可以做到變速控制。
  • 超聲波感應器(Trig同Echo):Trig腳負責發射超聲波脈衝,Echo腳就接收反射返嚟嘅訊號。Trig腳駁去Arduino第3腳,Echo腳駁去第4腳。
  • 紅外線感應器(左同右):呢啲感應器用嚟偵測正前方有冇障礙物。左邊紅外線感應器駁去Arduino第8腳,右邊就駁去第7腳。佢哋用嚟檢查架車兩邊嘅空間。

如果想睇詳細嘅視覺指南,請參考下面嘅接線圖,佢清楚標示咗每一條連接。

程式碼解釋

段程式碼係用Arduino程式語言(C++)寫嘅。完整程式可以喺影片描述入面連結嘅資源頁面下載。等我哋拆解一下呢個草稿入面最關鍵、用戶可以設定嘅部分。

腳位定義

喺程式碼最頂部,你會定義Arduino連接去各個組件嘅腳位。如果你用嘅係板上唔同嘅腳,你可以改呢啲設定。

const int A_1B = 5;
const int A_1A = 6;
const int B_1B = 9;
const int B_1A = 10;

const int echoPin = 4;
const int trigPin = 3;

const int rightIR = 7;
const int leftIR = 8;

A_1BA_1AB_1BB_1A呢啲腳控制H橋摩打驅動器。透過將呢啲腳設為HIGH或者LOW嘅唔同組合,你可以控制每個摩打嘅方向。echoPintrigPin係用嚟接超聲波感應器,而rightIRleftIR就係用嚟接紅外線感應器。

行為變數同邏輯

自動駕駛行為嘅核心邏輯喺loop()函數入面。架車會根據紅外線感應器同超聲波感應器嘅讀數嚟做決定。程式碼定義咗特定嘅距離,觸發唔同嘅動作。例如,distance變數係以厘米嚟量度。邏輯如下:

  • 如果距離大過50厘米:前面條路暢通,所以架車會以速度200向前行。
  • 如果距離係2厘米至10厘米之間:架車太接近障礙物。佢會向後退一秒,然後向左後方轉半秒,去搵一條新路。
  • 如果距離係10厘米至50厘米之間:架車處於「警戒區」。佢會向前行,但係速度慢啲,得150。

呢啲臨界值(50厘米、10厘米同2厘米)同速度(200同150)就係你可以調整嘅主要變數,用嚟改變架車嘅行為。例如,如果你部車行得快啲,你可能會將「安全」距離加到60厘米。

自訂函數

程式碼入面有幾個自訂函數,用嚟控制架車嘅動作。佢哋喺主循環入面成日用,令到程式碼更加整潔同容易理解。

  • moveForward(int speed):呢個函數會設定摩打腳位嚟令車向前行。speed 參數(0-255)控制摩打轉動嘅速度。
  • moveBackward(int speed):同 moveForward 類似,但係會反轉摩打方向嚟令車向後行。
  • backLeft(int speed)backRight(int speed):呢啲函數會透過令一個摩打反轉、另一個停低嚟令車轉彎。呢個係一種原地轉向,幫車有效噉改變方向。
  • stopMove():呢個函數會將所有控制腳位設為 LOW,嚟停低所有摩打。
  • readSensorData():呢個函數會由超聲波感應器發射脈衝,然後量度回聲返嚟嘅時間。之後佢會計算距離(以厘米為單位)並返回呢個數值。

現場項目示範

(影片喺 07:09)喺示範入面,架車被放喺一個有各種障礙物(好似紙箱同牆)嘅環境。架車嘅邏輯好清楚噉顯示出嚟,因為佢喺度導航。當超聲波感應器偵測到牆或者障礙物距離超過 50 厘米,佢會好有信心噉向前行。當佢越嚟越近,兩邊嘅紅外線感應器會檢查有冇空位。

如果偵測到左邊有障礙物,架車會做一個後右轉嚟避開佢,反之亦然。當架車發現自己喺一個狹窄位置,好似枱底(影片喺 07:49),佢會用後退同轉彎功能嚟脫身,搵到一條清晰嘅路。架車會持續噉讀取環境並做決定,展示出一種反應式控制系統,唔依賴預先規劃嘅路線。

影片章節

  • [00:00] 自駕車項目簡介
  • [00:28] 關於 SunFounder 3-in-1 套件
  • [01:32] 打開程式碼同概覽
  • [02:02] 程式碼結構同新函數嘅解釋
  • [03:11] 喺 Setup 函數入面設定腳位
  • [03:28] Loop 入面嘅主要決策邏輯
  • [05:41] 現場示範:架車運作中
  • [07:09] 有障礙物同跟牆嘅示範
  • [09:58] 總結同最後諗法

圖片

28 SunFounder Car 6 self-driving path
28 SunFounder Car 6 self-driving path
Car 7 8 28 self driving
Car 7 8 28 self driving
897-Lesson 28/31: Car-6 SunFounder self Driving Arduino car
語言: C++
/*
Lesson 28/31: Car-6 SunFounder self Driving Arduino car
Get this code and watch video Download and resource page https://robojax.com/RJT611
https://www.youtube.com/watch?v=IyninXUcsn0
*/
const int A_1B = 5;
const int A_1A = 6;
const int B_1B = 9;
const int B_1A = 10;

const int echoPin = 4;
const int trigPin = 3;

const int rightIR = 7;
const int leftIR = 8;

float readSensorData() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  float distance = pulseIn(echoPin, HIGH) / 58.00; //Equivalent to (340m/s*1us)/2
  return distance;
}


void moveForward(int speed) {
  analogWrite(A_1B, 0);
  analogWrite(A_1A, speed);
  analogWrite(B_1B, speed);
  analogWrite(B_1A, 0);
}

void moveBackward(int speed) {
  analogWrite(A_1B, speed);
  analogWrite(A_1A, 0);
  analogWrite(B_1B, 0);
  analogWrite(B_1A, speed);
}


void backLeft(int speed) {
  analogWrite(A_1B, speed);
  analogWrite(A_1A, 0);
  analogWrite(B_1B, 0);
  analogWrite(B_1A, 0);
}

void backRight(int speed) {
  analogWrite(A_1B, 0);
  analogWrite(A_1A, 0);
  analogWrite(B_1B, 0);
  analogWrite(B_1A, speed);
}

void stopMove() {
  analogWrite(A_1B, 0);
  analogWrite(A_1A, 0);
  analogWrite(B_1B, 0);
  analogWrite(B_1A, 0);
}

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

  //motor
  pinMode(A_1B, OUTPUT);
  pinMode(A_1A, OUTPUT);
  pinMode(B_1B, OUTPUT);
  pinMode(B_1A, OUTPUT);

  //ultrasonic
  pinMode(echoPin, INPUT);
  pinMode(trigPin, OUTPUT);

  //IR obstacle
  pinMode(leftIR, INPUT);
  pinMode(rightIR, INPUT);
}

void loop() {

  int left = digitalRead(leftIR);  // 0: Obstructed   1: Empty
  int right = digitalRead(rightIR);

  if (!left && right) {
    backLeft(150);
  } else if (left && !right) {
    backRight(150);
  } else if (!left && !right) {
    moveBackward(150);
  } else {
    float distance = readSensorData();
    Serial.println(distance);
    if (distance > 50) { // Safe
      moveForward(200);
    } else if (distance < 10 && distance > 2) { // Attention
      moveBackward(200);
      delay(1000);
      backLeft(150);
      delay(500);
    } else {
      moveForward(150);
    }
  }
}

資源與參考資料

文件📁

Arduino 函式庫 (zip)