1. 前言
在2018年我本科在萬宇杰老師的帶領下和小伙伴們一起立了校級重點科研立項——《DIY電動滑板》,非常懷戀那時候的干勁,閑暇時分傍晚和枚金江一起玩滑板飛馳綠道,白天和劉姣一起畫工程圖,晚上和葉俊吉萬金華他們做舞蹈機器人,時光就是這樣一點點緩緩流淌過。
不知不覺中雙元班的同窗們都各自高飛,而我還在艱難的求學中(2025年10月被OE、11月CEP拒稿)。恰巧也讓我有了新的想法,之前的滑板是用Arduino Uno加拓展板設計的硬件,現在運輸小船做實驗就由我的滑板小小的身體承受著,每次都要走公里才能到達海邊。滑板載著小船漫步過海濱小路,載著我跑過鄉村小路,載著打印機溜過校園大道彎兒,值得高興的是我的滑板已經累計有200公里左右,也沒有出現什么故障,嘻嘻。
接著這樣的機會嘗試用本次《2025RTT硬件設計大賽》中的Vision board來移植原來的Arduino Uno方案,以此來紀念我的青春創作,保留原先Uno拓展板的電氣與硬件。這次比賽首先是繪制類似Arduino Uno原先的端口封裝與Vision board之間的拓展板,其次移植藍牙控制程序和改進主動剎車功能。
2. 設計方案
本設計采用長板滑板版面,選用直流無刷電機,購買繪制特殊規格長板滑板的皮帶輪及電機架,以航模電池3S5200MAH電池供電。配以專用直流無刷電機電調。主控電路與遙控電路均以Vision Board為核心,使用藍牙數據通訊協議進行無線數據透傳,采用PWM脈沖寬度調制方式,采用TOF激光距離傳感器進行緊急制動判斷。以下為各模塊設計簡介。
2.1 機械結構模塊
機械模塊主要解決傳動系統搭建及電機的安裝。車架架設計為高64MM,長248MM7.25英寸的支架。傳動系統采用同步輪傳動,使用皮帶連接。齒輪比是大輪36齒,小輪12齒,用5M*270,11帶寬齒的齒輪帶連接,傳動比為3:1,如圖電機支架同步輪及配件。

2.2 電機模塊
電機的KV值,決定著電機的轉速增加量,KV值越大轉速越快。電動滑板在啟動時,由于靜摩擦的原因,啟動的階段阻力非常大,之后阻力會突然變小。所以,電動滑板在啟動之后常常有頓挫感。電機的選擇對滑板的安全性的提升顯得尤為重要。根據滑板的啟動的特性,應選用KV值越小的電機。
2.2.1 電機選擇
本設計電機選用N5065外轉子無刷電機270KV,其各項參數指標如圖左邊為無刷電機N5065,右邊為C5065

首先從電機型號上來說n5065表示電機尺寸為:直徑50mm,長度65mm。前面的n和c表示系列號,其中n系列做工和工作效率高于c系,N電機比C電機功率大,發熱小,扭力大。N電機比C電機的磁鐵長度和定子長度稍微長一些,n系尾部為平面,c系尾部為錐形。詳細參數如下: 可以看到,n5065的功率要比c5065大,一個是1820W,一個是1665W。電壓比c5065高,重量也比c5065重50g。(注:這里只說了KV值400的,你也可以選擇270的) 根據公式:轉速=KV值X電壓; n5065電機轉速=KV (400)x22(v)=8800rpm ; c5065電機轉速=KV (400) x20(v)=8000rpm ;
2.2.2 電機控制
單片機的控制信號,可以輕松輸出0或1,如果需要控制電機信號就需要PWM脈沖寬度調制,也可參考SG90舵機控制。在本設計中使用KV值為270KV的N5065無刷電機,無刷電機和有刷電機有相似之處,也有轉子和定子,只不過和有刷電機的結構相反;有刷電機的轉子是線圈繞組,和動力輸出軸相連,定子是永磁磁鋼;無刷電機的轉子是永磁磁鋼,連同外殼一起和輸出軸相連,定子是繞組線圈,去掉了有刷電機用來交替變換電磁場的換向電刷,故稱之為無刷電機。依靠改變輸入到無刷電機定子線圈上的電流波交變頻率和波形,在繞組線圈周圍形成一個繞電機幾何軸心旋轉的磁場,這個磁場驅動轉子上的永磁磁鋼轉動,電機就轉起來了,電機的性能和磁鋼數量、磁鋼磁通強度、電機輸入電壓大小等因素有關,更與無刷電機的控制性能有很大關系,因為輸入的是直流電,電流需要電子調速器將其變成3相交流電,還需要從遙控器接收機那里接收控制信號,控制電機的轉速,以滿足模型使用需要。相比于傳統直流有刷電機相比,無刷電機能量密度高,力矩大,重量輕,性能好等優點。增強了電機的可靠性,但是無刷電機的驅動比有刷電機要復雜得多,需要通過專門的電子驅動器才能正常工作,為降低開發難度的目的,該部分采用了車模用的無刷電機調速器,該調速器可根據輸入的PWM信號占空比的大小來控制無刷電機的轉速。
2.3 主控板及其遙控模塊
本設計選用Vision board作為控制芯片,手機app收發作為上位機遙控。app使用參考

2.3.1 主控芯片選擇
Vision Board搭載全球首顆 480 MHz Arm Cortex-M85芯片,擁有Helium和TrustZone技術的加持。SDK包里集成了OpenMV機器視覺例程,配合MicroPython 解釋器,使其可以流暢地開發機器視覺應用。Vision Board搭載了全球首款基于 ARM Cortex-M85 架構的瑞薩電子RA8 MCU,6.39 CoreMark/MHz,可以快速而高效地運行機器視覺算法,實現圖像處理、等功能。雖然在這個電動滑板大材小用,但是給代碼框架和使用安全上提高了不少。

參考資料見:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/make-bsp/renesas-ra/%E7%91%9E%E8%90%A8VisionBoard%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97
2.3.2 無線通信模塊的選取
本設計的無線通信模塊選擇經典HC-05主從機一體藍牙模塊,該模塊能耗低,穩定性強,具有很好的抗干擾能力。選用藍牙模塊以后,可以實現雙向通訊,加入顯示模塊及其他傳感器模塊后,遙控器可顯示電池電量,行駛速度,行駛里程和載重等。為之后功能的增加和改進,提供了便利,同時大量搭載藍牙的設備可以用于控制滑板,例如開發手機APP控制端,將手機作為遙控端使用。

本設計的遙控器和主控板上,分別有一塊Vision board和一個HC-05藍牙模塊。藍牙模塊設置了自動配對之后,上電之后它們就進入“傳輸”狀態,這時,使用函數串口8編寫讀取解析程序,便可實現遙控器與主控板之間的數據傳輸。
2.3.3 自動緊急剎車控制
防追尾系統對于駕駛員來說是一大必要輔助駕駛利器。此次設計的防追尾系統主要利用超聲波在空氣中的傳播速度和關系進行測量。超聲波具有指向性強、能量消耗慢且在介質中傳播距離較遠特點。其實說到超聲波,我們就會想到蝙蝠,是的,它的工作原理就是模仿蝙蝠的。先發出一個聲音,然后在接收返回的聲音,通過發出和返回的時間差來可以計算出距離,就這么簡單。所以我們就要有一個機制,發出多長的光信號,回收采集的理論上應該是發出的同時就要采樣收集了。
原先的方案是超聲波測距,之前實測發現會頻繁誤觸,而且采樣時間非常長(兩次連續判斷1.5m障礙物大約需要0.5s,如果車速在2m/s,會明顯剎車來不及,主要是反應時間有點長,發生碰撞危險),這次采用I2c距離TOF傳感器,看看效果應該要好一點點

3. 實驗步驟
3.1 實驗材料
主控板:Vision board開發板,sensor shield拓展板,USB數據線 傳感器:TOF傳感器,光照傳感器 執行器:N5056無刷電機,LED燈,一路高電平觸發繼電器,有源蜂鳴器 通訊:藍牙HC05 輔助硬件:滑板,同步帶結構,盒子,泡沫,熱熔膠,公母線若干 軟件:一臺安裝RT-Thread開發環境的電腦
3.2 根據原理圖搭建電路
實驗原理圖:
藍牙RX接uart8的TX,藍牙TX接uart8的RX
有源蜂鳴器引腳2
繼電器引腳4,然后單獨接led燈與外接電源串聯
ESC定義無刷電機引腳9,電調提供電源
TOF測距SDA接A4,SCL接A5
光照檢測接A0
3.4 PCB及三維圖

整體元器件非常少,就2202.54排母下面連接Vision board,然后6/2*8/10排母在上方連接Arduino Uno拓展板
下面是硬件細節圖 拓展板焊接效果

控制器電源電調都安裝在防水盒中
控制盒整體外觀

3.5 源碼分享
配置串口2

參考:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/make-bsp/renesas-ra/%E7%91%9E%E8%90%A8VisionBoard%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97?id=%e4%b8%80%e3%80%81ra8d1-vision-board%e4%b8%8a%e7%9a%84uart%e5%ae%9e%e8%b7%b5%ef%bc%88%e5%88%98%e5%bb%ba%e5%8d%8eou%ef%bc%89 配置PWM12

參考:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/make-bsp/renesas-ra/%E7%91%9E%E8%90%A8VisionBoard%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97?id=%e4%b9%9d%e3%80%81ra8d1-vision-board%e4%b8%8a%e7%9a%84pwm%e5%ae%9e%e8%b7%b5%ef%bc%88%e4%b8%81%e6%8c%af%e5%af%8c%ef%bc%89 配置軟件I2C



參考:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/make-bsp/renesas-ra/%E7%91%9E%E8%90%A8VisionBoard%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97?id=%e5%8d%81%e4%b8%89%e3%80%81ra8d1-vision-board%e4%b8%8a%e7%9a%84iic%e5%ae%9e%e8%b7%b5%ef%bc%88%e6%ac%a7%e5%b0%8f%e9%be%99%ef%bc%89 配置ADC
參考:https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/tutorial/make-bsp/renesas-ra/%E7%91%9E%E8%90%A8VisionBoard%E5%BC%80%E5%8F%91%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97?id=%e5%85%ad%e3%80%81ra8d1-vision-board%e4%b8%8a%e7%9a%84adc%e5%ae%9e%e8%b7%b5%ef%bc%88%e4%be%af%e6%b3%bd%e5%8d%8e%ef%bc%89 rt-thread設備驅動勾選

下面是程序控制源碼
/* ? Copyright (c) 2024, YourName ? 項目:基于 RT-Thread 的電機 ESC 控制(移植自 Arduino) ? 功能:通過串口接收指令控制電機轉速、LED、蜂鳴器,集成VL53L0X主動剎車和光線檢測自動夜燈 ? 已移除:超聲波、光敏電阻、自動急停 ? 新增:所有速度檔位切換必須平滑加減速(逐步 ±1,每次延時 50ms) ? 修復:ESC電調上電初始化問題 ? 新增:VL53L0X激光測距主動剎車功能 ? 新增:光線檢測自動夜燈功能 */ #include#include #include #include"hal_data.h" // ====================== 引腳 / 設備 宏定義 ====================== #definePWM_DEV_NAME "pwm12" // PWM設備名,請根據實際連接修改 #definePWM_CHANNEL 0 // PWM通道 #defineLED_PIN BSP_IO_PORT_00_PIN_01 // LED引腳(根據實際修改) #defineBUZZER_PIN BSP_IO_PORT_05_PIN_05 // 蜂鳴器引腳(根據實際修改) #defineSERIAL_DEVICE_NAME "uart2" // 串口設備名,如USB轉串口 / 藍牙模塊 // ====================== VL53L0X 配置 ====================== #defineTOF_DEVICE_NAME "tof_vl53l0x" // VL53L0X設備名 #defineBRAKE_DISTANCE 1000 // 剎車距離閾值:1000mm = 1m #defineBRAKE_SAMPLE_COUNT 2 // 連續檢測次數 // ====================== ADC 光線檢測配置 ====================== #defineADC_DEV_NAME "adc1" // ADC 設備名稱 #defineADC_DEV_CHANNEL 4 // ADC 通道 #defineREFER_VOLTAGE 330 // 參考電壓 3.3V,數據精度乘以100保留2位小數 #defineCONVERT_BITS (1 << 12) ? // 轉換位數為12位 #define?LIGHT_THRESHOLD ? ? 200 ? ? ? ? // 光線閾值,小于200為夜間 #define?LIGHT_SAMPLE_DELAY ?2000 ? ? ? ?// 光線檢測間隔:2秒 // ====================== 速度檔位定義 ====================== volatile int item = 1000; ? ? ? ? ? ? ? // 當前速度值(擴大10倍以支持小數計算) const int speed_level = 1000; ? ? ? ? ? // 啟動速度(對應1.0ms) const int speed_min = 950; ? ? ? ? ? ? ?// 最低速度(對應0.95ms) const int speed_one = 1150; ? ? ? ? ? ? // 檔位1(對應1.15ms) const int speed_two = 1250; ? ? ? ? ? ? // 檔位2(對應1.25ms) const int speed_three = 1300; ? ? ? ? ? // 檔位3(對應1.3ms) const int speed_max = 1400; ? ? ? ? ? ? // 檔位4(最高速,對應1.4ms) const int speed_add = 50; ? ? ? ? ? ? ? // 每次調整步進(對應0.05ms) // ====================== 全局變量 ====================== static struct rt_device_pwm *pwm_dev; static rt_device_t serial_dev; static rt_device_t tof_dev = RT_NULL; ? // VL53L0X設備句柄 static rt_adc_device_t adc_dev = RT_NULL; // ADC設備句柄 char rx_buffer[64]; int rx_len = 0; static bool is_started = false; ? ? ? ? // 系統是否已啟動 static bool esc_initialized = false; ? ?// ESC是否已完成初始化 static bool auto_brake_enabled = true; ?// 自動剎車功能是否啟用 static bool auto_light_enabled = true; ?// 自動夜燈功能是否啟用 static bool manual_light_control = false; // 手動燈光控制標志 static int brake_counter = 0; ? ? ? ? ? // 連續剎車檢測計數器 static int current_light_level = 0; ? ? // 當前光線強度 // ====================== PWM脈沖寬度計算 ====================== // 將速度值轉換為PWM脈沖寬度(納秒) static int speed_to_pulse(int speed_val) { ? ? // 將速度值映射到安全范圍內 ? ? int pulse_ns = 950000 + (speed_val - 950) * (450000 / (1400 - 950)); ? ? // 確保在安全范圍內 ? ? if (pulse_ns < 950000) pulse_ns = 950000; ? ? if (pulse_ns > 1400000) pulse_ns = 1400000; return pulse_ns; } // ====================== 蜂鳴器控制 ====================== void buzzer_beep(int count, int duration_ms) { for (int i = 0; i < count; i++) ? ? { ? ? ? ? rt_pin_write(BUZZER_PIN, PIN_HIGH); ? ? ? ? rt_thread_mdelay(duration_ms); ? ? ? ? rt_pin_write(BUZZER_PIN, PIN_LOW); ? ? ? ? rt_thread_mdelay(duration_ms); ? ? } } // ====================== ESC初始化序列 ====================== static void esc_init_sequence(void) { ? ? rt_kprintf("[ESC] Starting initialization sequence... "); ? ? // 發送安全啟動信號 ? ? rt_kprintf("[ESC] Setting to safe start position (1.0ms)... "); ? ? rt_pwm_set(pwm_dev, PWM_CHANNEL, 20000000, 1000000); // 1.0ms ? ? rt_thread_mdelay(1000); ? ? esc_initialized = true; ? ? rt_kprintf("[ESC] Initialization completed successfully! "); ? ? buzzer_beep(3, 100); // 3聲短鳴表示初始化完成 } // ====================== LED 控制 ====================== void led_on(void) { ? ? rt_pin_write(LED_PIN, PIN_HIGH); } void led_off(void) { ? ? rt_pin_write(LED_PIN, PIN_LOW); } // ====================== ADC 光線檢測函數 ====================== static int read_light_level(void) { ? ? rt_uint32_t value, vol; ? ? rt_err_t ret = RT_EOK; ? ? if (adc_dev == RT_NULL) ? ? { ? ? ? ? rt_kprintf("[LIGHT] ADC device not initialized! "); ? ? ? ? return -1; ? ? } ? ? // 使能設備 ? ? ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL); ? ? if (ret != RT_EOK) ? ? { ? ? ? ? rt_kprintf("[LIGHT] Failed to enable ADC channel! "); ? ? ? ? return -1; ? ? } ? ? // 讀取采樣值 ? ? value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL); ? ? // 轉換為對應電壓值(乘以100保留2位小數) ? ? vol = value * REFER_VOLTAGE / CONVERT_BITS; ? ? // 關閉通道 ? ? ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL); ? ? // 返回原始ADC值(0-4095),值越小表示光線越暗 ? ? return (int)value; } // ====================== 自動燈光控制 ====================== static void auto_light_control(void) { ? ? if (!auto_light_enabled || manual_light_control) ? ? { ? ? ? ? return; ? ? } ? ? int light_level = read_light_level(); ? ? if (light_level < 0) ? ? { ? ? ? ? return; // 讀取失敗 ? ? } ? ? current_light_level = light_level; ? ? // 光線閾值判斷:小于200為夜間 ? ? if (light_level < LIGHT_THRESHOLD) ? ? { ? ? ? ? // 夜間模式,開啟LED ? ? ? ? led_on(); ? ? ? ? static bool night_mode_reported = false; ? ? ? ? if (!night_mode_reported) ? ? ? ? { ? ? ? ? ? ? rt_kprintf("[LIGHT] Night mode detected. Light level: %d, LED ON ", light_level); ? ? ? ? ? ? night_mode_reported = true; ? ? ? ? } ? ? } ? ? else ? ? { ? ? ? ? // 白天模式,關閉LED ? ? ? ? led_off(); ? ? ? ? static bool day_mode_reported = false; ? ? ? ? if (!day_mode_reported) ? ? ? ? { ? ? ? ? ? ? rt_kprintf("[LIGHT] Day mode detected. Light level: %d, LED OFF ", light_level); ? ? ? ? ? ? day_mode_reported = true; ? ? ? ? } ? ? } } // ====================== 緊急剎車函數 ====================== static void emergency_brake(void) { ? ? rt_kprintf("[BRAKE] EMERGENCY BRAKE ACTIVATED! Distance too close. "); ? ? // 快速減速到最小值(比平滑減速更快) ? ? int current_speed = item; ? ? rt_kprintf("[BRAKE] Rapid deceleration from %d to %d ", current_speed, speed_min); ? ? while (item > speed_min) { item -= 2; // 每次減2,更快減速 // 防止低于最小值 if (item < speed_min) ? ? ? ? { ? ? ? ? ? ? item = speed_min; ? ? ? ? } ? ? ? ? int pulse = speed_to_pulse(item); ? ? ? ? rt_pwm_set(pwm_dev, PWM_CHANNEL, 20000000, pulse); ? ? ? ? rt_thread_mdelay(20); // 更短的延時,快速剎車 ? ? } ? ? // 剎車提示 ? ? buzzer_beep(3, 100); ? ? led_on(); // LED亮起表示剎車狀態 ? ? rt_kprintf("[BRAKE] Emergency brake completed. Speed: %d ", item); } // ====================== 平滑加減速函數 ======================= static void smooth_set_speed(int target) { ? ? if (!esc_initialized) ? ? { ? ? ? ? rt_kprintf("[ERROR] ESC not initialized! Cannot set speed. "); ? ? ? ? return; ? ? } ? ? int step = (target > item) ? 1 : -1; rt_kprintf("[Smooth] Changing speed from %d to %d... ", item, target); while (item != target) { item += step; // 防止超過目標 if ((step > 0 && item > target) || (step < 0 && item < target)) ? ? ? ? { ? ? ? ? ? ? item = target; ? ? ? ? } ? ? ? ? // 設置 PWM ? ? ? ? int pulse = speed_to_pulse(item); ? ? ? ? rt_pwm_set(pwm_dev, PWM_CHANNEL, 20000000, pulse); ? ? ? ? rt_thread_mdelay(30); ? ? ? ? rt_kprintf("[Smooth] Now at: %d (Pulse: %dns) ", item, pulse); ? ? } ? ? rt_kprintf("[Smooth] Reached target: %d ", item); } // ====================== VL53L0X 距離監測線程 ====================== static void distance_monitor_thread_entry(void *parameter) { ? ? struct rt_sensor_data sensor_data; ? ? rt_size_t res; ? ? rt_kprintf("[VL53L0X] Distance monitoring thread started. "); ? ? // 查找VL53L0X設備 ? ? tof_dev = rt_device_find(TOF_DEVICE_NAME); ? ? if (tof_dev == RT_NULL) ? ? { ? ? ? ? rt_kprintf("[VL53L0X] ERROR: Cannot find VL53L0X device: %s ", TOF_DEVICE_NAME); ? ? ? ? return; ? ? } ? ? // 打開設備 ? ? if (rt_device_open(tof_dev, RT_DEVICE_FLAG_RDONLY) != RT_EOK) ? ? { ? ? ? ? rt_kprintf("[VL53L0X] ERROR: Failed to open VL53L0X device. "); ? ? ? ? return; ? ? } ? ? rt_kprintf("[VL53L0X] Device opened successfully. Starting distance monitoring... "); ? ? while (1) ? ? { ? ? ? ? // 只有系統已啟動且自動剎車啟用時才進行距離檢測 ? ? ? ? if (is_started && auto_brake_enabled && esc_initialized) ? ? ? ? { ? ? ? ? ? ? res = rt_device_read(tof_dev, 0, &sensor_data, 1); ? ? ? ? ? ? if (res == 1) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? int distance = sensor_data.data.proximity; ? ? ? ? ? ? ? ? // 調試輸出(可選,避免輸出過于頻繁) ? ? ? ? ? ? ? ? static int debug_counter = 0; ? ? ? ? ? ? ? ? if (debug_counter++ % 10 == 0) // 每10次輸出一次 ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? rt_kprintf("[VL53L0X] Distance: %d mm ", distance); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? // 檢測到障礙物距離小于閾值 ? ? ? ? ? ? ? ? if (distance > 0 && distance < BRAKE_DISTANCE) ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? brake_counter++; ? ? ? ? ? ? ? ? ? ? rt_kprintf("[VL53L0X] Obstacle detected: %d mm (counter: %d/%d) ", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? distance, brake_counter, BRAKE_SAMPLE_COUNT); ? ? ? ? ? ? ? ? ? ? // 連續2次檢測到障礙物,觸發緊急剎車 ? ? ? ? ? ? ? ? ? ? if (brake_counter >= BRAKE_SAMPLE_COUNT) { emergency_brake(); brake_counter = 0; // 重置計數器 } } else { // 距離安全,重置計數器 if (brake_counter > 0) { rt_kprintf("[VL53L0X] Distance safe: %d mm. Reset brake counter. ", distance); brake_counter = 0; // 注意:這里不關閉LED,因為LED可能由光線控制 } } } else { rt_kprintf("[VL53L0X] ERROR: Failed to read distance data. "); } } else { // 系統未啟動或剎車禁用,重置計數器 brake_counter = 0; } rt_thread_mdelay(50); // 50ms檢測周期 } } // ====================== 光線檢測線程 ====================== static void light_monitor_thread_entry(void *parameter) { rt_kprintf("[LIGHT] Light monitoring thread started. "); // 初始化ADC設備 adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME); if (adc_dev == RT_NULL) { rt_kprintf("[LIGHT] ERROR: Cannot find ADC device: %s ", ADC_DEV_NAME); return; } rt_kprintf("[LIGHT] ADC device initialized successfully. "); while (1) { // 只有系統已啟動時才進行光線檢測 if (is_started) { auto_light_control(); } rt_thread_mdelay(LIGHT_SAMPLE_DELAY); // 2秒檢測一次 } } // ====================== 指令動作處理函數 ====================== void action(const char *throttle) { rt_kprintf("[Action] Received: %s ", throttle); if (strcmp(throttle, "stop") == 0) { smooth_set_speed(speed_level); // 注意:這里不控制LED關閉,因為可能由光線控制 buzzer_beep(1, 500); rt_kprintf("[Action] STOPPED. Speed set to level. "); is_started = false; brake_counter = 0; // 重置剎車計數器 } else if (strcmp(throttle, "decrease") == 0) { int target = item - speed_add; if (target < speed_min) ? ? ? ? ? ? target = speed_min; ? ? ? ? smooth_set_speed(target); ? ? ? ? buzzer_beep(1, 100); ? ? ? ? rt_kprintf("[Action] DECREASED (smooth). Speed: %d ", item); ? ? } ? ? else if (strcmp(throttle, "increase") == 0) ? ? { ? ? ? ? int target = item + speed_add; ? ? ? ? if (target > speed_max) target = speed_max; smooth_set_speed(target); buzzer_beep(1, 200); rt_kprintf("[Action] INCREASED (smooth). Speed: %d ", item); } else if (strcmp(throttle, "one") == 0) { smooth_set_speed(speed_one); buzzer_beep(1, 150); rt_kprintf("[Action] SPEED 1 (smooth). Speed: %d ", item); } else if (strcmp(throttle, "two") == 0) { smooth_set_speed(speed_two); buzzer_beep(2, 150); rt_kprintf("[Action] SPEED 2 (smooth). Speed: %d ", item); } else if (strcmp(throttle, "three") == 0) { smooth_set_speed(speed_three); buzzer_beep(3, 150); rt_kprintf("[Action] SPEED 3 (smooth). Speed: %d ", item); } else if (strcmp(throttle, "four") == 0) { smooth_set_speed(speed_max); buzzer_beep(4, 150); rt_kprintf("[Action] SPEED 4 (MAX, smooth). Speed: %d ", item); } else if (strcmp(throttle, "turn on") == 0) { manual_light_control = true; // 進入手動控制模式 led_on(); buzzer_beep(1, 200); rt_kprintf("[Action] LED ON (Manual control) "); } else if (strcmp(throttle, "turn off") == 0) { manual_light_control = true; // 進入手動控制模式 led_off(); buzzer_beep(1, 200); rt_kprintf("[Action] LED OFF (Manual control) "); } else if (strcmp(throttle, "auto light") == 0) { manual_light_control = false; // 退出手動控制,返回自動模式 rt_kprintf("[Action] Auto light control ENABLED "); buzzer_beep(1, 200); } else if (strcmp(throttle, "buzzer on") == 0) { buzzer_beep(2, 300); rt_kprintf("[Action] BUZZER ON "); } else if (strcmp(throttle, "buzzer off") == 0) { buzzer_beep(2, 100); rt_kprintf("[Action] BUZZER OFF "); } else if (strcmp(throttle, "init esc") == 0) { esc_init_sequence(); } else if (strcmp(throttle, "brake on") == 0) { auto_brake_enabled = true; rt_kprintf("[Action] Auto brake ENABLED "); buzzer_beep(1, 200); } else if (strcmp(throttle, "brake off") == 0) { auto_brake_enabled = false; rt_kprintf("[Action] Auto brake DISABLED "); buzzer_beep(2, 200); } else if (strcmp(throttle, "light on") == 0) { auto_light_enabled = true; rt_kprintf("[Action] Auto light ENABLED "); buzzer_beep(1, 200); } else if (strcmp(throttle, "light off") == 0) { auto_light_enabled = false; rt_kprintf("[Action] Auto light DISABLED "); buzzer_beep(2, 200); } else if (strcmp(throttle, "test brake") == 0) { rt_kprintf("[Action] Testing emergency brake... "); emergency_brake(); } else if (strcmp(throttle, "light status") == 0) { rt_kprintf("[LIGHT] Current light level: %d, Threshold: %d, Auto: %s, Manual: %s ", current_light_level, LIGHT_THRESHOLD, auto_light_enabled ? "ON" : "OFF", manual_light_control ? "ON" : "OFF"); } else { rt_kprintf("[Action] Unknown command: %s ", throttle); } } // ====================== 串口指令線程 ====================== static void serial_cmd_thread_entry(void *parameter) { rt_size_t len; while (1) { memset(rx_buffer, 0, sizeof(rx_buffer)); len = rt_device_read(serial_dev, 0, rx_buffer, sizeof(rx_buffer) - 1); if (len > 0) { // 去除換行符和回車符 for (int i = 0; i < len; i++) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? if (rx_buffer[i] == ' ' || rx_buffer[i] == ' ') ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? rx_buffer[i] = '?'; ? ? ? ? ? ? ? ? ? ? break; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? rt_kprintf("[Serial] Rx: %s ", rx_buffer); ? ? ? ? ? ? if (!is_started) ? ? ? ? ? ? { ? ? ? ? ? ? ? ? if (strcmp(rx_buffer, "start") == 0) ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? if (!esc_initialized) ? ? ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? ? ? rt_kprintf("[System] Initializing ESC for first start... "); ? ? ? ? ? ? ? ? ? ? ? ? esc_init_sequence(); ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? ? ? is_started = true; ? ? ? ? ? ? ? ? ? ? rt_kprintf("[System] System STARTED. "); ? ? ? ? ? ? ? ? ? ? buzzer_beep(2, 300); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? else ? ? ? ? ? ? ? ? { ? ? ? ? ? ? ? ? ? ? rt_kprintf("[System] ERROR: System NOT STARTED. Send 'start' first. "); ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? else ? ? ? ? ? ? { ? ? ? ? ? ? ? ? action(rx_buffer); ? ? ? ? ? ? } ? ? ? ? ? ? rx_buffer[0] = '?'; ? ? ? ? } ? ? ? ? rt_thread_mdelay(10); ? ? } } // ====================== VL53L0X 硬件初始化 ====================== static int rt_hw_vl53l0x_port(void) { ? ? struct rt_sensor_config cfg; ? ? cfg.intf.dev_name = "i2c1"; ? ? ? ? /* i2c bus */ ? ? cfg.intf.user_data = (void *)0x29; ?/* i2c slave addr */ ? ? // 注意:這個函數名稱需要根據你實際的VL53L0X驅動來調整 ? ? rt_hw_vl53l0x_init("vl53l0x", &cfg, 57); /* xshutdown ctrl pin */ ? ? rt_kprintf("[VL53L0X] Hardware port initialized. "); ? ? return RT_EOK; } INIT_COMPONENT_EXPORT(rt_hw_vl53l0x_port); // ====================== 初始化函數 ====================== int motor_control_app_init(void) { ? ? rt_kprintf("=== Motor Control System Starting === "); ? ? // 1. 初始化 PWM ? ? pwm_dev = (struct rt_device_pwm *) rt_device_find(PWM_DEV_NAME); ? ? if (pwm_dev == RT_NULL) ? ? { ? ? ? ? rt_kprintf("Cannot find PWM device: %s ", PWM_DEV_NAME); ? ? ? ? return -1; ? ? } ? ? // 啟用PWM設備,設置安全啟動位置 ? ? rt_pwm_enable(pwm_dev, PWM_CHANNEL); ? ? rt_pwm_set(pwm_dev, PWM_CHANNEL, 20000000, 1000000); // 1.0ms ? ? rt_thread_mdelay(1000); ? ? rt_kprintf("PWM ESC device enabled at safe position. "); ? ? // 2. 初始化 LED & 蜂鳴器 ? ? rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT); ? ? rt_pin_mode(BUZZER_PIN, PIN_MODE_OUTPUT); ? ? led_off(); ? ? rt_pin_write(BUZZER_PIN, PIN_LOW); ? ? // 3. 打開串口 ? ? serial_dev = rt_device_find(SERIAL_DEVICE_NAME); ? ? if (serial_dev == RT_NULL) ? ? { ? ? ? ? rt_kprintf("Cannot find serial device: %s ", SERIAL_DEVICE_NAME); ? ? ? ? return -1; ? ? } ? ? rt_device_open(serial_dev, RT_DEVICE_FLAG_INT_RX); ? ? // 4. 創建串口指令線程 ? ? rt_thread_t tid = rt_thread_create("serial_cmd", serial_cmd_thread_entry, RT_NULL, 1024, 20, 10); ? ? if (tid != RT_NULL) ? ? { ? ? ? ? buzzer_beep(1, 500); ? ? ? ? rt_thread_startup(tid); ? ? ? ? rt_kprintf("Serial command thread started. "); ? ? } ? ? else ? ? { ? ? ? ? rt_kprintf("Failed to create serial command thread. "); ? ? } ? ? // 5. 創建距離監測線程(優先級較高,確保及時剎車) ? ? rt_thread_t distance_tid = rt_thread_create("distance_monitor", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?distance_monitor_thread_entry, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?RT_NULL, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?1024, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?15, ?// 較高優先級 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?10); ? ? if (distance_tid != RT_NULL) ? ? { ? ? ? ? rt_thread_startup(distance_tid); ? ? ? ? rt_kprintf("Distance monitoring thread started. "); ? ? } ? ? else ? ? { ? ? ? ? rt_kprintf("Failed to create distance monitoring thread. "); ? ? } ? ? // 6. 創建光線檢測線程 ? ? rt_thread_t light_tid = rt_thread_create("light_monitor", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?light_monitor_thread_entry, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?RT_NULL, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?1024, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?18, ?// 中等優先級 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?10); ? ? if (light_tid != RT_NULL) ? ? { ? ? ? ? rt_thread_startup(light_tid); ? ? ? ? rt_kprintf("Light monitoring thread started. "); ? ? } ? ? else ? ? { ? ? ? ? rt_kprintf("Failed to create light monitoring thread. "); ? ? } ? ? rt_kprintf("=== System Initialization Complete === "); ? ? rt_kprintf("Commands: start, stop, increase, decrease, one-two-three-four "); ? ? rt_kprintf(" ? ? ? ? ?turn on/off, auto light, light on/off, light status "); ? ? rt_kprintf(" ? ? ? ? ?brake on/off, test brake, init esc "); ? ? return 0; } // ====================== 導出組件初始化 ====================== INIT_APP_EXPORT(motor_control_app_init);
需要修改rt_config.h中adc0為1:#defineBSP_USING_ADC1

這是一個基于RT-Thread的智能電機控制系統,通過串口指令控制無刷電機轉速,集成了VL53L0X激光測距主動剎車和光線檢測自動夜燈功能,具備多線程安全保護和智能決策能力。

流程說明:
多線程并行:三個獨立線程分別處理用戶指令、障礙物監測和光線檢測
安全保護:距離監測線程具有較高優先級,確保及時剎車
智能決策:基于連續檢測和閾值判斷,避免誤觸發
模式切換:支持手動/自動模式靈活切換
平滑控制:電機速度變化采用漸進式調節,提升系統穩定性
4.動手操作
a.首先進行光照檢測,如光線較弱則自動打開前燈; b.連接好藍牙,發送“start”字符串開始遙控,發送“one”,“two”,“three”,“four”即可實現穩步增速,發送“increase”、“dicrease”即可實現精準調速,發送“turn on”、“turn off”即可打開前燈led繼電器,發送“buzeer on”、“buzeer off”即可觸發有源蜂鳴器聲響,app不完全配置

c.發送stop即可實現關閉所有增益,發送“reset”即可實現復位跳出循環,再次發送發送“start”字符串又開始遙控。超聲波測距檢測前方物體距離小于100cm及時關閉所有增益,起到自動緊急剎車保護,程序中執行動作時有蜂鳴器響應反饋;還有心跳包程序,可判斷是否藍牙斷開(若斷開及時關閉所有增益,起到失控保護)
● 第一次是RT-Thread的【基于RT-Thread+RA6M4的智能魚缸系統設計之魚我所欲也】活動,作品是2022年暑假做的獲得第六名,還是比較開心!
● 第二次2023年寒假做的是【基于MAX7800羽毛板語音控制ESP8266小車】,成績還不錯第七名,讓對小車車的可玩性又近了一步!
● 第三次2023年春做的【基于騰訊云的CH32V307開發板遠程機械臂小車】,由于圖床引用CSDN導致最后評審沒有顯示出來,最后獲得安慰獎!
● 第四次2023年冬做的【FastBond2階段2——基于ESP32C3開發的簡易IO調試設備 - 電子森林 (eetree.cn) 】 ,最終獲得三等獎,再接再厲哦!
● 第五次實現了【基于LicheePi-4A的 人臉識別系統軟件設計】,人臉識別系統軟件設計和調試全流程,加深了對tkinter GUI設計思路,對LicheePi-4A 國產單板計算機更有信心,最終獲得參與獎!
● 第六次實現了2024年寒假練 - 基于xiao ESP32S3 Sense的自動化HA魚缸設計,探討如何運用Seeed Xiao ESP32-S3 Cam開發板設計一款自動化、可接入Home Assistant(簡稱HA)的智能魚缸系統。最終獲得第一名,結實了許多朋友,視野開闊了許多。
● 第七次實現了FastBond3挑戰部分-XIAO智能助手,讓我關于Platformio C++編程充滿期待。搭配國產通義靈碼編程插件,編程效率嘎嘎上升,與此同時智能終端有更深刻認識啦!
● 第8次設計基于ESP32-S3雙核處理器,構建支持8通道K型熱電偶(MAX31856)的智能采集系統,通過多線程架構實現數據采集、通信處理、看門狗監控的并行執行,最終達成±0.5℃精度、5Hz采樣率
這是一個功能完善、安全機制到位的嵌入式智能控制系統,移植了原先Arduino Uno項目,替換更好的TOF距離傳感器,體現了Vision Board多傳感器融合與實時控制的良好實踐。
開源地址
最后是該項目的開源地址: https://p.eda.cn/d-1302180533932916736 有興趣的小伙伴可以去華秋開源硬件社區查看!有商業訴求的,請聯系項目的作者。
-
傳感器
+關注
關注
2576文章
55028瀏覽量
791233 -
Arduino
+關注
關注
190文章
6526瀏覽量
196905 -
電動滑板
+關注
關注
0文章
24瀏覽量
7151
原文標題:DIY 滑板玩出黑科技!Vision Board 電動滑板,TOF 激光剎車 + 平滑調速性能體驗感雙在線!
文章出處:【微信號:HarmonyOS_Community,微信公眾號:電子發燒友開源社區】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
基于 RT-Thread 的 Vision Board 智能電動滑板設計 | 技術集結
【Vision Board創客營連載體驗】RA8D1 Vision Board初體驗
【Vision Board創客營連載體驗】基于Vision Board的垃圾分類
vision board開發板用MDK燒錄顯示成功卻找不到例程,為什么?
常規的滑板車控制系統硬件設計方案
常規的滑板車控制系統硬件設計方案
Vision Board/首款ARM Cortex-M85開發板價格大公開
【Vision Board 創客營】Vision Board上的DAC實踐
Vision-Board 使用TinyUSB驅動Xbox游戲手柄
采用XIAO MG24開發板的手套動作控制電動滑板設計
基于Vision Board開發板的電動滑板設計方案
評論