1kW 四輪驅動環保車 (AWD EV) 設計思路與實作 1. 系統硬體架構 (System Architecture) 1.1 動力總成 (Powertrain) 電池電源: 13s 鋰電池組, 最大輸出功率限制 1000W (約 20.8A)。 驅動馬達: 4顆 x 500W 20吋 輪轂馬達 (總額定功率 2000W,採降額使用)。 前軸 (Front Axle): 內建 單向離合器 (Overrunning Clutch) 。 特性: 加速時接合,滑行時空轉無磁阻, 無法回充/倒車 。 後軸 (Rear Axle): 直驅 (Direct Drive)。 特性: 可雙向控制,具備 動能回收 (Regen) 與 扭矩向量 (Vectoring) 能力 1.2 控制單元 (Control Unit) MCU: STM32F446 (Cortex-M4F, 180MHz)。 OS: FreeRTOS (CMSIS-V2 API)。 通訊: CAN Bus (500kbps) 連接 4 組 VESC 驅動器。 感測器: 油門踏板 (ADC)。 方向盤轉角感測器 (ADC 或 Encoder)。 IMU 慣性感測器 (I2C/SPI, MPU6050/ICM20600)。 2. 核心控制邏輯 (Control Strategy) 由於電池僅有 1kW 輸出,而馬達總容量達 2kW,控制核心在於**「功率預算分配」 與 「動態切換」**。 2.1 驅動模式狀態機 (Drive Mode FSM) 狀態 A: 起步與爬坡 (4WD Mode) 條件: 車速 < 35 km/h (可調)。 分配: 前後輪同時輸出。 比例: 建議 前 40% / 後 60% (利用後輪加速時重心後移增加抓地力)。 狀態 B: 高速巡航 (RWD Mode) 條件: 車速 > 35 km/h。 分配: 前 0% / 後 100% 。 優勢: 前輪離合器脫開進入無阻力滑行,1kW 功率全數集中於後輪,並配合弱磁控制 (Field Weakening) 衝擊極速。 2.2 操控輔助系統 (Active Dynamics) 電子差速 (Electronic Differential): 根據方向盤角度,計算阿克曼轉向幾何,調整左右輪速差。 扭矩向量 (Torque Vectoring): * 當 IMU 偵測轉向不足 (Understeer) 時,增加外側後輪扭力,煞車內側後輪。 限制: 前輪因有離合器,計算出的負扭力指令將被強制歸零 (Clamp to 0)。 3. 控制邏輯詳細解析 (Detailed Logic Analysis) 本系統架構基於 RTOS 設計,以下為各邏輯區塊的詳細運作機制: 3.1 狀態觀測層 (Observer Layer) 負責將原始數據轉換成物理意義,並計算當前的「邊界條件」。 CalcPower (功率預算): 最重要的守門員。 公式:$Max_Current = 1000W / V_bat$ 作用: 確保無論後續如何分配扭矩,總電流基數永遠不會讓電池過載。 CalcSpeed (速度計算): 邏輯: 主要參考 後輪 (Rear Wheels) 的 ERPM。 原因: 前輪具有離合器,放開油門滑行時前輪轉速可能低於車速(空轉),無法代表真實車速。 3.2 策略層 (Strategy Layer) - 大腦 ModeLogic (模式切換): 4WD 模式: 設定 Splitter 比例為 前 33% / 後 67% (符合前250W/後500W配置比例)。 RWD 模式: 設定 Splitter 比例為 前 0% / 後 100% 。 EDiff (電子差速): 計算轉向時的幾何差。 邏輯: 左轉時,右輪(外側)電流增加 $\Delta I$,左輪(內側)電流減少 $\Delta I$。 TCS_ESP (動態穩定): 比較「方向盤角度想要的轉向率 (Target Yaw)」與「IMU 測到的實際轉向率 (Actual Yaw)」。 若差距過大 (出現 Understeer/Oversteer),產生修正扭矩 $\Delta I_{ESP}$。 3.3 動力分配混合器 (Mixer Layer) - 關鍵演算法 這是數學運算最複雜的地方,負責將基礎扭矩與修正量混合: 後輪邏輯 (Rear Logic - 直驅): $$I_{Rear_L} = (I_{Total} \times Ratio_{Rear} \times 0.5) + \Delta I_{Diff} + \Delta I_{ESP}$$ $$I_{Rear_R} = (I_{Total} \times Ratio_{Rear} \times 0.5) - \Delta I_{Diff} - \Delta I_{ESP}$$ 特點: 後輪是直驅,可以接受負值(電子煞車/回充)來修正車身動態。 前輪邏輯 (Front Logic - 離合器特殊處理): $$I_{Front_L} = (I_{Total} \times Ratio_{Front} \times 0.5) + \Delta I_{Diff}$$ $$I_{Front_R} = (I_{Total} \times Ratio_{Front} \times 0.5) - \Delta I_{Diff}$$ 重要限制: 由於前輪有單向離合器,當 Mixer 算出負值時必須 強制歸零 (Clamp to 0) 。前輪無法產生制動力,只能靠「少出力」或「多出力」來協助。 3.4 安全限制器 (Limiter Layer) 發送給 VESC 之前的最後一道防線: 單體限制: 檢查單顆電機是否超過其額定電流 (例如前輪 Max 10A)。 總量限制: 再次加總四顆電機的最終指令,確保 $\sum I \le I_{max_battery}$。如果因為 ESP 修正導致總電流超標,則等比例縮小 (Scale Down) 所有指令。 4. 程式碼實作 (Implementation) 軟體架構 (Software Architecture) 採用 FreeRTOS 多任務系統,確保控制迴圈的即時性。所有運算採用 整數 (int32) 以優化 STM32 執行效率。 任務名稱 優先級 頻率 功能描述 Task_Control Realtime 1kHz 核心控制迴圈 (讀取狀態 -> 策略運算 -> CAN 發送) Task_CanRx High Event 接收 VESC 回傳封包 (轉速、電流),更新車輛狀態 Task_Input Normal 100Hz 讀取油門 ADC、方向盤角度、IMU 數據 以下程式碼基於 STM32 HAL 庫與 CMSIS-OS V2。 4.1 標頭檔設定 (main.h) /* main.h - 參數與結構定義 */ #ifndef __MAIN_H #define __MAIN_H #include // --- 物理限制 --- #define POWER_LIMIT_W 1000 // 電池功率限制 #define BATTERY_VOLTAGE_NOM 48 // 標稱電壓 // 最大總電流 (mA) = 1000W / 48V = 20833 mA #define MAX_TOTAL_CURRENT_MA ((POWER_LIMIT_W * 1000) / BATTERY_VOLTAGE_NOM) // --- 控制參數 --- #define ERPM_THRESHOLD_RWD 10000 // 切換後驅的轉速閾值 (ERPM) #define ERPM_HYSTERESIS 500 // 遲滯區間 #define STEERING_GAIN 50 // 轉向靈敏度係數 (整數縮放) #define VECTORING_GAIN 80 // 向量控制強度係數 // --- VESC CAN ID --- #define VESC_ID_FL 1 #define VESC_ID_FR 2 #define VESC_ID_RL 3 #define VESC_ID_RR 4 #define CAN_PACKET_SET_CURRENT 1 // --- 共享車輛狀態結構 --- typedef struct { int32_t avg_erpm; // 平均車速 (ERPM) int32_t throttle_adc; // 油門 (0-4095) int32_t steering_val; // 方向盤 (-2048 左 ~ +2048 右) int32_t yaw_rate_imu; // IMU Z軸角速度 uint8_t drive_mode; // 0: 4WD, 1: RWD } VehicleState_t; #endif 4.2 RTOS 任務邏輯 (freertos.c) /* freertos.c - 核心控制邏輯 */ #include "main.h" #include "cmsis_os.h" #include "can.h" // 全域變數與 Handles extern VehicleState_t g_VehicleState; extern osMutexId_t VehicleMutexHandle; extern CAN_HandleTypeDef hcan1; // 輔助函式:發送 CAN void VESC_Send_Current(uint8_t controller_id, int32_t current_ma) { CAN_TxHeaderTypeDef TxHeader; uint32_t TxMailbox; uint8_t TxData[4]; TxHeader.ExtId = (CAN_PACKET_SET_CURRENT << 8) | controller_id; TxHeader.IDE = CAN_ID_EXT; TxHeader.RTR = CAN_RTR_DATA; TxHeader.DLC = 4; // Big Endian Packing TxData[0] = (uint8_t)(current_ma >> 24); TxData[1] = (uint8_t)(current_ma >> 16); TxData[2] = (uint8_t)(current_ma >> 8); TxData[3] = (uint8_t)(current_ma); if (HAL_CAN_GetTxMailboxesFreeLevel(&hcan1) > 0) { HAL_CAN_AddTxMessage(&hcan1, &TxHeader, TxData, &TxMailbox); } } // --- Task 1: 核心馬達控制 (1kHz) --- void StartControlTask(void *argument) { uint32_t tick_count = osKernelGetTickCount(); const uint32_t period = 1; // 1ms // 本地變數 (減少 Mutex 佔用) int32_t cmd_FL=0, cmd_FR=0, cmd_RL=0, cmd_RR=0; int32_t loc_rpm=0, loc_thr=0, loc_steer=0; uint8_t loc_mode=0; for(;;) { // 1. 快速讀取狀態 if (osMutexAcquire(VehicleMutexHandle, 2) == osOK) { loc_rpm = g_VehicleState.avg_erpm; loc_thr = g_VehicleState.throttle_adc; loc_steer = g_VehicleState.steering_val; loc_mode = g_VehicleState.drive_mode; osMutexRelease(VehicleMutexHandle); } // 2. 計算總功率預算 (Base Torque) // 使用位元移位 (>>12) 代替除以 4096,效率極高 int32_t total_ma = (loc_thr * MAX_TOTAL_CURRENT_MA) >> 12; // 3. 判斷驅動模式 (Hysteresis) if (loc_mode == 0) { // 4WD if (loc_rpm > (ERPM_THRESHOLD_RWD + ERPM_HYSTERESIS)) loc_mode = 1; } else { // RWD if (loc_rpm < (ERPM_THRESHOLD_RWD - ERPM_HYSTERESIS)) loc_mode = 0; } // 4. 計算前後軸基底電流 int32_t base_front = 0; int32_t base_rear = 0; if (loc_mode == 0) { // 4WD Mode // 策略:前 40%, 後 60% base_front = (total_ma * 40) / 100; base_rear = total_ma - base_front; } else { // RWD Mode base_front = 0; // 前輪空轉 base_rear = total_ma; // 後輪全功率 } // 5. 計算電子差速與向量修正 (Differential & Vectoring) // 簡單模型:轉向值 * 係數 = 電流差值 int32_t diff_adj = (loc_steer * STEERING_GAIN) / 100; // 6. 混合與分配 (Mixing) // 前軸 (注意:離合器不接受負值) int32_t fl_temp = (base_front / 2) + diff_adj; int32_t fr_temp = (base_front / 2) - diff_adj; // Clamp logic for front clutch (No regen) cmd_FL = (fl_temp < 0) ? 0 : fl_temp; cmd_FR = (fr_temp < 0) ? 0 : fr_temp; // 後軸 (接受負值,允許向量煞車) // 這裡可以加入額外的 IMU 穩定修正 (Yaw Control) cmd_RL = (base_rear / 2) + diff_adj; cmd_RR = (base_rear / 2) - diff_adj; // 7. 最終安全檢查 (Total Current Limiter) // 防止向量控制疊加後超過電池極限 int32_t total_req = cmd_FL + cmd_FR + cmd_RL + cmd_RR; if (total_req > MAX_TOTAL_CURRENT_MA) { // 簡單等比例縮小 (Scaling Down) // 這裡為了效率,簡化處理: // 實際專案建議使用定點數乘法進行縮放 } // 8. 回寫模式狀態 if (loc_mode != g_VehicleState.drive_mode) { if (osMutexAcquire(VehicleMutexHandle, 0) == osOK) { g_VehicleState.drive_mode = loc_mode; osMutexRelease(VehicleMutexHandle); } } // 9. 發送 CAN 指令 VESC_Send_Current(VESC_ID_FL, cmd_FL); VESC_Send_Current(VESC_ID_FR, cmd_FR); VESC_Send_Current(VESC_ID_RL, cmd_RL); VESC_Send_Current(VESC_ID_RR, cmd_RR); // 10. 精確等待 tick_count += period; osDelayUntil(tick_count); } } 5. 系統接線與配置備忘 (Wiring Notes) CAN Bus 終端電阻: 確保 CAN H/L 兩端各有一顆 120Ω 電阻 (MCU 端與最遠端 VESC)。 共地 (Common Ground): 所有的 VESC 訊號地 (GND) 必須與 STM32 的 GND 連接。 VESC 設定 (VESC Tool): App Settings: 設為 CAN Uart 或 CAN 。 Controller ID: 必須分別設為 1, 2, 3, 4 且不重複。 Baud Rate: 設為 500K 或符合 STM32 設定。 Current Limits: 電機最大電流 (Motor Current Max) 可設為 20A (500W級距),但輸入電流 (Battery Current Max) 需配合電池 BMS 限制。 6. 未來優化方向 弱磁控制 (Field Weakening): 在 RWD 模式下,透過 VESC Tool 開啟後輪的弱磁功能,利用集中的 1kW 功率突破基速限制。 牽引力控制 (TCS): 在 Task_Control 中加入輪速比較,若 (Wheel_RPM - Avg_RPM) > Threshold,則瞬間將該輪電流 cmd 減半。 IMU 融合濾波: 使用互補濾波器融合 加速度計 與 陀螺儀,獲得更穩定的 Yaw Rate,提升高速過彎穩定性。