AI 樹莓派自走車實作

Troubleshooting 故障排除優化教材

黃老師製作

💡 系統運作架構圖

Camera
OpenCV Lane Detection
YOLO Detection
PID Controller
Motor Control
Robot Car
Web UI (Control Panel)
Flask Backend

📷 影像處理管道:OpenCV 追線原理

原始影像
BGR
HSV 轉換
色彩穩定
顏色遮罩
過濾膠帶色
ROI 限制
只看路面
形態學處理
去噪點
輪廓偵測
找形狀
車道分析
單/雙線
計算 Error
中心偏移

關鍵步驟說明:

  • HSV 轉換:比起 BGR,HSV 受光照影響較小,利於鎖定特定顏色。
  • ROI (Region of Interest):裁切掉天空與背景,避免背景雜訊干擾追線。
  • 形態學 (Morphology):使用 Erode/Dilate 填補遮罩中的破洞或去除細小亮點。
# OpenCV 核心片段
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv, lower_yellow, upper_yellow)
roi = mask[height//2:height, 0:width] # 只看下半部
contours, _ = cv2.findContours(roi, cv2.RETR_TREE, 
                               cv2.CHAIN_APPROX_SIMPLE)
if contours:
    c = max(contours, key=cv2.contourArea)
    M = cv2.moments(c)
    cx = int(M['m10']/M['m00'])
    error = cx - width/2

⚙️ PID 控制邏輯:如何修正路徑?

Lane Error
(偏差值)
PID Controller
(比例/積分/微分)
Correction
(修正量)
Left Motor Speed
Right Motor Speed
Robot Moves
(差速轉向)

// 差速控制公式

correction = pid.compute(error)

left_speed  = base_speed - correction
right_speed = base_speed + correction

pwm.set(left_speed, right_speed)

運作原理說明:

  • 偏差獲取:從 OpenCV 得到的中心點與畫面中心相減。
  • PID 計算:透過 Kp, Ki, Kd 轉化為修正強度。
  • 差速轉向:修正量加減馬達轉速,實現流暢轉向。

01 參數改了卻沒生效?

原因分析:

前端使用了狀態輪詢 (Polling),導致在編輯輸入時,後端傳回的舊狀態覆蓋了正在修改的表單內容。

優化方案:

  • 設置 isEditing 旗標鎖定
  • 編輯期間暫停 UI 更新
  • 按下「套用」後才恢復同步

程式邏輯對照 (JavaScript)

// 鎖定機制範例
let isEditing = false;
function updateStatus() {
    if (isEditing) return; 
    fetch('/status').then(res => res.json()).then(data => {
        document.getElementById('kp').value = data.kp;
    });
}
document.getElementById('kp').onfocus = () => isEditing = true;
document.getElementById('kp').onblur = () => isEditing = false;

02 Kp / 速度不能輸入小數點

原因分析:

後端 API 接收資料時,使用了 int() 進行解析,或是 HTML 的 step 屬性未正確設置。

優化方案:

  • 後端解析改用 float()
  • HTML Input 設置 step="0.01"

程式邏輯對照 (Flask Python)

@app.route('/set_param')
def set_param():
    try:
        # 使用 float() 解析
        kp = float(request.args.get('kp', 0.0))
        speed = float(request.args.get('speed', 0.0))
        return "OK"
    except ValueError:
        return "Invalid format", 400

03 手動按鈕按了沒反應?

原因分析:

瀏覽器或裝置(手機觸控)對事件支援差異,導致回呼未觸發。

優化方案:

  • 使用 HTML Inline 事件備援
  • 註冊為全域 Window 函式

互動事件對照 (HTML)

<button onmousedown="carMove('forward')" 
        onmouseup="carStop()"
        ontouchstart="carMove('forward')" 
        ontouchend="carStop()">
    前進
</button>

04 API 回 200,但車子不動

重點觀念:

HTTP 200 僅代表伺服器有收到請求,不保證硬體執行成功。

硬體檢測清單:

  • 🔍 I2C: i2cdetect -y 1 檢查 0x40 是否在線
  • 🔍 PCA9685: 檢查外部供電是否正常
  • 🔍 PWM: 設定值是否太低推不動馬達

硬體層邏輯 (Python)

MIN_PWM = 8000
def move_motor(val):
    if val < MIN_PWM: 
        print("警告: PWM 太低,馬達推不動")
    # 設定 PCA9685...

05 自動駕駛過彎就停住?

原因分析:

過彎角度大於鏡頭視野時導致丟線,舊程式因「沒線就停」陷入死鎖。

邏輯優化:

  • Lane Memory: 丟線時沿用上一次轉向值
  • Slow Exploration: 找不到線時緩慢前行搜尋

進階邏輯 (Pseudo)

if cx is None:
    # 丟線時優化: 減弱轉向但不停車
    steering = last_error * 0.8 
    return steering, LOW_SPEED

真實場域與理論的差異

💡 光線與反光

環境反光會讓 HSV 閾值失效,建議導入動態亮度補償或邊緣偵測。

📐 透視變形

鏡頭夾角導致近大遠小,需做俯視轉換 (Bird's Eye View) 才能準確測距。

🏎️ 慣性影響

硬體反應有延遲,高速行駛需計算「預判距離」提前發送修正命令。

結語:工程師的修煉

「數據是完美的,但物理世界是有雜訊的。好的系統不是永遠不出錯,而是出錯後能優雅地修正。」