搜尋程式碼

第26/31課:智能小車 第4部分:使用超聲波傳感器避障 | SunFounder Robojax

第26/31課:智能小車 第4部分:使用超聲波傳感器避障 | SunFounder Robojax

喺呢一課,我哋會幫你嘅智能車升級,等佢可以用超聲波感應器睇到同埋對周圍環境作出反應。通過量度前面物件嘅距離,架車可以做出聰明嘅決定:當條路暢通嘅時候就向前行,當有物件喺警戒區內就停低,而當有障礙物太近嘅時候就會向後退。呢個項目係建基於你已經學過嘅核心摩打控制同感應器基礎,最後會整到一架真正嘅自動駕駛車輛。

26-SunFounder-Car-4-Ultrasonic.mp4_snapshot_00.09.009

呢個唔單止係一件玩具;佢係邁向整更加複雜機械人項目嘅基本一步。你喺度會實現嘅邏輯——感應、思考、行動——同機械人吸塵機以至工業自動化所用嘅邏輯係一樣嘅。以下有幾個諗法可以啟發你自己嘅創作:

  • 自動探測車:整一架可以探索房間或者走廊而唔會撞到牆或者傢俬嘅機械人。
  • 近距離警報系統:將超聲波感應器裝喺伺服摩打上面,用嚟掃描一個區域,當有入侵者進入指定範圍嘅時候就觸發警報或者燈光。
  • 智能泊車輔助:整一個系統,用距離讀數嚟引導車輛入狹窄嘅車位,提供視覺或者聲音提示。

呢個指南係根據 SunFounder 3-in-1 Arduino 套件同埋佢嘅「Play with Ultrasonic Module」項目嚟寫嘅。我哋會逐步講解接線、解釋決策代碼,同埋示範架車嘅實際運作。

26-SunFounder-Car-4-Ultrasonic.mp4_snapshot_02.26.146

避障邏輯點樣運作

呢個項目嘅核心係一個簡單但強勁嘅決策樹。超聲波感應器會不斷量度正前方物件嘅距離。然後呢個距離值就用嚟控制架車嘅摩打,如下圖所示。

  • 如果距離 > 25 厘米:條路暢通,所以架車會向前行。
  • 如果 10 厘米 < 距離 <= 25 厘米:偵測到有物件喺「警戒區」入面,所以架車會停低以避免碰撞。
  • 如果 2 厘米 < 距離 <= 10 厘米:有物件離得太近。架車會向後退以製造更多空間。
  • 如果距離 <= 2 厘米:呢個讀數好可能係錯誤(太近而量度唔準確),所以架車會停低作為安全措施。

硬件組件

要整呢個項目,你需要以下組件,全部都有包括喺 SunFounder 3-in-1 套件入面。

  • 1x Arduino Uno(或者兼容板)
  • 1x 配備兩個齒輪摩打嘅智能車底盤
  • 1x L298N 摩打驅動模組
  • 1x HC-SR04 超聲波距離感應器
  • 1x 麵包板
  • 跳線
  • 架車嘅電源(例如電池盒)
26-SunFounder-Car-4-Ultrasonic.mp4_snapshot_00.00.000

接線指南

接線會連接摩打驅動器、超聲波感應器同埋 Arduino。摩打驅動器控制架車嘅車輪,而超聲波感應器就充當佢嘅「眼睛」。

以下係 SunFounder 文檔入面嘅連接圖:

等我哋拆解吓啲連接。首先,將麵包板嘅正負電軌由 Arduino 嘅 5V 同 GND 針腳供電。然後超聲波感應器嘅連接如下:

  • VCC(電源):連接到麵包板上嘅正電軌。
  • GND(接地):連接到麵包板上嘅負電軌。
  • Trig(觸發):連接到 Arduino 上嘅數碼針腳 3。呢個針腳負責發送超聲波脈衝。
  • Echo(接收):連接到 Arduino 上嘅數碼針腳 4。呢個針腳負責接收反射返嚟嘅脈衝。

摩打驅動器嘅連接同之前幾課一樣。四個控制針腳(IN1、IN2、IN3、IN4)連接到 Arduino 嘅數碼針腳 5、6、9 同 10。呢啲針腳控制兩個摩打嘅速度同方向。確保摩打驅動器嘅電源同接地正確連接到電池盒同 Arduino 嘅接地。(喺影片 02:24 位置)

代碼解釋

呢個項目嘅代碼係根據超聲波感應器嘅距離讀數嚟控制架車嘅行為。邏輯好直接,亦都好容易自訂。等我哋睇吓啲關鍵嘅、用戶可以設定嘅部分。

1. 針腳定義

喺程式最頂部,摩打同超聲波感應器嘅針腳已經定義好。如果你將組件接駁到唔同嘅 Arduino 針腳,你可以更改呢啲設定。

const int A_1B = 5;
  const int A_1A = 6;
  const int B_1B = 9;
  const int B_1A = 10;
  
  const int trigPin = 3;
  const int echoPin = 4;

呢度,A_1AA_1BB_1AB_1B 透過 L298N 驅動器控制左邊同右邊嘅摩打。trigPinechoPin 係用嚟連接超聲波感應器。

2. 行為變數同邏輯

主要嘅行為係喺 loop() 函數入面控制。呢度就係你可以調整架車「性格」嘅地方。

void loop() {
    float distance = readSensorData();
    if (distance > 25) {
      moveForward(200);
    }
    else if (distance < 10 && distance > 2) {
      moveBackward(200);
    } else {
      stopMove();
    }
  }

以下係點樣自訂佢:

  • 距離門檻:數字 2510 定義咗「安全」同「危險」區域,單位係厘米。加大 25 可以令架車早啲停,或者減細佢等架車可以行近啲障礙物。個 2 係一個安全緩衝,用嚟忽略太近物件嘅錯誤讀數。
  • 摩打速度:傳畀 moveForward()moveBackward()200 設定咗架車嘅速度。呢個值可以由 0 到 255。較低嘅值,好似 150,會令架車行得慢啲同謹慎啲。

其餘嘅代碼包括 readSensorData() 函數,佢處理超聲波感測器嘅計時嚟計算距離,同埋 moveForward()moveBackward()stopMove() 函數,佢哋控制摩打驅動器嚟執行想要嘅動作。

處理一個常見錯誤

你可能會遇到好似 'moveForward' was not declared in this scope 嘅錯誤。呢個係因為 Arduino IDE 由上到下讀取代碼。當佢去到 loop() 函數嘅時候,佢仲未知道下面定義嘅函數。為咗修正呢個問題,你必須喺 setup() 函數之前加「函數原型」。呢啲只係函數名稱同返回類型嘅聲明,以分號結尾。

void moveForward(int speed);
  void moveBackward(int speed);
  void stopMove();
  float readSensorData();

加咗呢啲行就話畀編譯器知:「呢啲函數存在,遲啲會定義」,咁就解決咗個錯誤。(影片 09:21 度)

改善感測器穩定性

喺測試期間,你可能會注意到即使前面冇障礙物,架車都會停或者窒下窒下。呢個通常係因為個迴圈行得太快,超聲波感測器冇足夠時間接收回聲信號,導致讀數係 0 厘米。為咗修正呢個問題,喺 loop() 函數嘅尾段加一個小延遲,畀感測器時間去工作。

void loop() {
    float distance = readSensorData();
    if (distance > 25) {
      moveForward(200);
    }
    else if (distance < 10 && distance > 2) {
      moveBackward(200);
    } else {
      stopMove();
    }
    delay(100); // 加一個 100ms 延遲嚟穩定讀數
  }

100 毫秒嘅延遲通常已經足夠攞到穩定同一致嘅距離讀數。(影片 10:56 度)

現場項目示範

一旦上傳咗代碼,打開 Serial Monitor。你會見到文字顯示架車嘅狀態,好似「Forward」、「Reverse」或者「Stop」。

喺示範入面,架車放喺面對一個障礙物嘅位置。當障礙物距離超過 25 厘米,架車會向前行。當你將隻手移近,距離跌到低過 25 厘米,架車就會停。如果你將隻手移得好近,喺 10 厘米之內,架車會向後退。呢個行為喺影片入面好清楚見到,確認咗避障邏輯正常運作。(影片 11:53 度)

總結

恭喜!你成功整咗一架可以喺環境入面導航同避開障礙物嘅智能車。呢個項目將感測器輸入、決策邏輯同摩打控制結合成一個完整嘅功能系統。你唔單止學識咗點用超聲波感測器,仲學識咗點實現一個簡單嘅控制演算法,呢個係更加複雜嘅自主機械人嘅基礎。

章節

  • [00:00] 避障簡介
  • [01:16] 項目概覽同先決條件
  • [02:24] 接線超聲波感測器同摩打驅動器
  • [04:56] 打開項目代碼
  • [05:12] 代碼解釋:邏輯同函數
  • [08:34] 上傳代碼同初步測試
  • [09:21] 疑難排解:函數原型
  • [10:56] 疑難排解:加延遲嚟穩定
  • [11:53] 避障現場示範

圖片

27 SunFounder Car 5 follow hand
27 SunFounder Car 5 follow hand
26 SunFounder Car 4 ultrasonic video snapshot 00.09.009
26 SunFounder Car 4 ultrasonic video snapshot 00.09.009
26 SunFounder Car 4 ultrasonic video snapshot 02.26.146
26 SunFounder Car 4 ultrasonic video snapshot 02.26.146
26 SunFounder Car 4 ultrasonic video snapshot 00.00.000
26 SunFounder Car 4 ultrasonic video snapshot 00.00.000
899-Lesson 26/31: Avoiding Obstacle Using Ultrasonic Sensor
語言: C++
/*
Lesson 26/31: Avoiding Obstacle Using Ultrasonic Sensor 
Get this code and watch video Download and resource page https://robojax.com/RJT609
YouTube video https://www.youtube.com/watch?v=uLBmRvaemxA

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

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

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);
}

void loop() {
  float distance = readSensorData();
  if (distance > 25) {
    moveForward(200);
  }
  else if (distance < 10 && distance > 2) {
    moveBackward(200);
  } else {
    stopMove();
  }
}

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 stopMove() {
  analogWrite(A_1B, 0);
  analogWrite(A_1A, 0);
  analogWrite(B_1B, 0);
  analogWrite(B_1A, 0);
}

資源與參考資料

文件📁

Arduino 函式庫 (zip)