搜尋程式碼

課程 第9課,共10課:使用樹莓派Pico 4WD智能車進行避障

呢一課係……嘅一部分: Raspberry Pi Pico 四驱智能车

課程 第9課,共10課:使用樹莓派Pico 4WD智能車進行避障

簡介

呢個指南係根據Robojax課程第9課(共10課),示範點樣用SunFounder Raspberry Pi Pico 4WD智能車套件整一部避障機械人。呢個項目結合咗舵機驅動嘅超聲波感測器同摩打控制,整出一部可以自主導航嘅機械人。透過好似雷達咁掃描感測器,架車會偵測障礙物,然後聰明咁揀一條暢通嘅路徑繼續行,係認識機械人、感測器整合同自主導航嘅完美入門。

Sunfounder_Pico4DW-09-避障設定,地板上有障礙物

呢個項目唔單止係玩具,佢係好多實際應用嘅基礎。以下有啲靈感俾你參考:

  • 自主探索機械人:整一部可以喺冇人干預嘅情況下繪圖同探索房間或戶外區域嘅機械人。
  • 智能吸塵機:用同樣嘅原理整一部可以喺房間導航、避開傢俬同牆壁同時清潔嘅機械人。
  • 保安巡邏機械人:編程架車巡邏周邊,用超聲波感測器偵測同報告意外障礙物或入侵。
  • AI教育平台:用呢個項目作為踏腳石,學習更複雜嘅演算法,例如路徑規劃同同步定位與地圖構建(SLAM)。

呢課專注於令架車可以做出決策嘅核心邏輯同程式碼。架車用一個舵機摩打轉動超聲波感測器,好似雷達咁量度由0到180度嘅距離。程式碼分析呢啲數據,搵出最闊嘅空曠路徑,然後指示架車向前、向左或向右移動。影片示範咗成個過程,由測試個別組件到喺真實迷宮入面執行最終嘅避障演算法。

硬件/組件

呢個項目係基於SunFounder Raspberry Pi Pico 4WD智能車套件。今課用到嘅主要組件包括:

  • Raspberry Pi Pico微控制器板
  • SunFounder 4WD智能車底盤,配四個摩打
  • 摩打驅動板
  • 超聲波距離感測器(HC-SR04類型)
  • 舵機摩打(用嚟轉動超聲波感測器)
  • 電源(架車用嘅電池)

接線指南

SunFounder套件設計成容易組裝,接線通常透過專用擴展板預先連接好。超聲波感測器安裝喺舵機摩打上面,然後連接到主控制板。呢個設定令感測器可以旋轉掃描環境。想睇你套件嘅詳細接線圖,請參考官方SunFounder文檔。

核心接線涉及超聲波感測器嘅觸發同回聲引腳,以及舵機摩打嘅信號引腳,全部連接到Raspberry Pi Pico上特定嘅GPIO引腳。摩打驅動器亦連接到Pico嚟控制四個驅動摩打。影片提到完整文檔(包括接線圖)可以隨套件下載。

Sunfounder_Pico4DW-09-避障_當超聲波偵測到障礙物時

程式碼解釋

呢課專注於`obstacle_avoid`示例入面嘅邏輯。程式碼係用MicroPython寫嘅。雖然完整程式可以下載,但我哋會集中睇控制架車行為嘅關鍵、用戶可配置參數。呢啲參數通常喺腳本頂部。

以下係你可以調整嚟微調機械人表現嘅主要變數:


# 雷達同移動參數
radar_reference = 20  # 被視為安全嘅最小距離(厘米)
step_angle = 10       # 每次雷達掃描步驟嘅角度增量
forward_speed = 30    # 向前移動嘅摩打速度(0-100)
turn_speed = 50       # 轉彎嘅摩打速度(0-100)
forward_scan_angle = 50  # 冇偵測到障礙物時舵機掃描嘅角度
  • radar_reference:呢個係關鍵嘅安全距離(厘米)。如果偵測到障礙物近過呢個值,架車就會視佢為「危險」並啟動避障動作。喺影片入面,呢個值設為20厘米。
  • step_angle:呢個定義雷達掃描嘅解析度。較細嘅值(例如10度)代表更詳細嘅掃描,但需要更長時間。較大嘅值會快啲,但可能會漏咗窄嘅障礙物。
  • forward_speed同turn_speed:呢啲控制送到摩打嘅功率。你可以調整佢哋嚟改變架車嘅整體速度同靈活性。轉彎速度通常設得較高,以確保架車可以有效咁原地轉向。
  • forward_scan_angle:當前方冇即時危險時,架車會將掃描範圍收窄到呢個角度(以正前方為中心),更頻密咁檢查正前方路徑有冇障礙物,令向前移動更順暢。

條片仲解釋咗主要嘅決策邏輯。有個函數 `get_direction()` 會分析距離讀數嘅列表(轉換成 1 同 0 代表安全/唔安全),去搵最闊嘅連續「1」路徑。根據呢條最闊路徑喺邊度,函數會返回一個方向:「向前」、「向左」或者「向右」。主循環跟住執行相應嘅動作,轉架車同重新掃描,直到前面條路暢通為止。

實時項目/示範

條片提供咗呢個項目嘅詳細示範。佢首先單獨測試超聲波感應器,展示佢點樣量度距離同將數值打印去 shell。導師跟住用流程圖解釋避障算法,詳細講解向左同向右轉嘅決策過程。最後,架車被放入一個用紙箱整成嘅細迷宮入面,示範完整嘅避障行為喺實際運作。架車成功穿越迷宮,向左同向右轉去搵一條清晰嘅前路。

影片章節

  • [00:00] 避障功能簡介
  • [01:31] SunFounder 智能車套件同功能概覽
  • [02:47] 避障功能點樣運作
  • [03:34] 測試超聲波感應器
  • [07:45] 解釋避障算法同流程圖
  • [12:49] 分析主要避障代碼
  • [15:43] 避障邏輯嘅實時示範
  • [22:53] 用障礙迷宮做最終示範
  • [24:35] 總結同下一步

圖片

pico-4wd_main
pico-4wd_main
PICOBOARDWHITEANGLE2_1200x857
PICOBOARDWHITEANGLE2_1200x857
Sunfounder_Pico4DW-09-Obstacle-avoidance setup with obstacle on the floor
Sunfounder_Pico4DW-09-Obstacle-avoidance setup with obstacle on the floor
Sunfounder_Pico4DW-09-Obstacle-avoidance_when ultrasonic detects obstacle
Sunfounder_Pico4DW-09-Obstacle-avoidance_when ultrasonic detects obstacle
909-Lesson 9/10 Pi Pico 4WD card Python code: obstacle avoid
語言: C++
# Lesson 9/10 Pi Car Pico 4WD: Obstacle avoid
# Download and resource page https://robojax.com/RJT631
import pico_4wd as car
import time

car.RADAR_REFERENCE = 20
car.RADAR_STEP_ANGLE = 10
MOTOR_FORWARD_POWER = 30
MOTOR_TURNING_POWER = 50

FORWARD_SCAN_ANGLE = 50

car.set_radar_scan_angle(FORWARD_SCAN_ANGLE)
status = "Danger"

def get_dir(radar_data):
    # get scan status of 0, 1
    # print(radar_data)
    radar_data = [str(i) for i in radar_data]
    radar_data = "".join(radar_data)
    # Split 0, leaves the free path
    paths = radar_data.split("0")
    # print(paths)
    # print("paths: %s" % paths)
    length_list = []
    # Calculate where is the widest
    for path in paths:
        length_list.append(len(path))
    if max(length_list) < 4:
        return "left"
    # Calculate the direction of the widest 
    i = length_list.index(max(length_list))
    pos = radar_data.index(paths[i])
    pos += (len(paths[i]) - 1) / 2
    delta = len(radar_data) / 3
    
    if pos < delta:
        return "left"
    elif pos > 2 * delta:
        return "right"
    else:
        return "forward"

def main():
    global status
    # General
    while True:
        radar_data = car.radar_scan()
        # print("radar_data: %s" % radar_data)
        # If radar data return a int, means scan not finished, and the int is current angle status
        if isinstance(radar_data, int):
            if radar_data == 0 and status != "Danger":
                print("Danger!")
                status = "Danger"
                car.move("stop")
                car.set_radar_scan_angle(180)
            continue
        else:
            status = "Save"
        
        direction = get_dir(radar_data)

        if direction == "left":
            print("turn left")
            distance = car.get_radar_distance_at(-FORWARD_SCAN_ANGLE/2)
            time.sleep(0.5)
            car.move("left", MOTOR_TURNING_POWER)
            while True:
                distance = car.get_radar_distance_at(-FORWARD_SCAN_ANGLE/2)
                status = car.get_radar_status(distance)
                if status == 1:
                    break
            car.move("stop")
            car.set_radar_scan_angle(FORWARD_SCAN_ANGLE)
        elif direction == "right":
            print("turn right")
            distance = car.get_radar_distance_at(FORWARD_SCAN_ANGLE/2)
            time.sleep(0.5)
            car.move("right", MOTOR_TURNING_POWER)
            while True:
                distance = car.get_radar_distance_at(FORWARD_SCAN_ANGLE/2)
                status = car.get_radar_status(distance)
                if status == 1:
                    break
            car.move("stop")
            car.set_radar_scan_angle(FORWARD_SCAN_ANGLE)
        else:
            print("forward")
            car.set_radar_scan_angle(FORWARD_SCAN_ANGLE)
            car.move("forward", MOTOR_FORWARD_POWER)

try:
    main()
finally:
    car.move("stop")
    car.set_light_off()

你可能需要嘅嘢

資源與參考資料

暫時冇資源。

文件📁

樹莓派代碼