基于Vision Board开发板的电动滑板设计方案
1. 前言2018年,本科生在万玉杰老师的带领下和朋友们立项了校级重点科研项目—— 《DIY电动滑板》,我非常怀念那时候的干劲。空闲时间,我和梅锦江一起玩滑板,晚上在绿道上奔跑,白天和刘娇一起画工程图纸,晚上和叶君吉、万金花等人一起制作跳舞机器人。时间就这样慢慢地流过。
不知不觉,双班的同学们都飞得很高,而我却还在努力学习(2025年10月被OE拒,2025年11月被CEP拒)。它碰巧给了我一个新的想法。之前的滑板是用Arduino Uno硬件和扩展板设计的。现在,我的滑板小小的身躯被用来运送做实验的船,每次都要步行数公里才能到达海边。滑板载着小船沿着海边小路,载着我穿过乡间小路,载着打印机沿着校园大道走。还好我的滑板累计了200公里左右没有任何问题,呵呵。
然后我借此机会尝试使用这块《2025RTT硬件设计大赛》中的Vision板来移植原始的Arduino Uno解决方案,以纪念我的青春创作并保留原始Uno扩展板的电气和硬件。本次比赛第一步是画出一块类似于Arduino Uno原口封装和Vision板的扩展板,其次移植蓝牙控制程序,完善主动刹车功能。
2. 设计方案本设计采用长板滑板布局,采用直流无刷电机,购买绘制长板滑板特殊规格的滑轮和电机架,采用航模电池3S5200MAH电池供电。配备专用直流无刷电机电调。主控电路和遥控电路均基于Vision Board,采用蓝牙数据通信协议进行无线数据透明传输,采用PWM脉宽调制方式,采用TOF激光距离传感器进行紧急制动判断。下面对各个模块的设计进行介绍。
2.1 机械结构模块机械模块主要解决传动系统的搭建和电机的安装。车架框架设计为高64MM、长248MM的7.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值
2.2.2 电机控制单片机的控制信号可以轻松输出0或1。如果需要控制电机信号,则需要PWM脉宽调制。也可以参考SG90舵机控制。本设计中采用KV值为270KV的N5065无刷电机。无刷电机与有刷电机类似。它也有转子和定子,但其结构与有刷电机相反。有刷电机的转子是线圈绕组,转子是线圈绕组。连接力输出轴,定子为永磁体;无刷电机的转子是永磁体,与外壳一起连接到输出轴。定子是绕组线圈,去掉了有刷电机交替变换电磁场的换向电刷,因此称为无刷电机。通过改变输入到无刷电机定子线圈的电流波的交变频率和波形,在绕电机几何轴旋转的绕组线圈周围形成磁场。这个磁场带动转子上的永磁钢旋转,电机开始转动。电机的性能取决于磁铁的数量、磁铁的磁通量强度和电流。它与机器的输入电压等因素有关,与无刷电机的控制性能有很大关系。由于输入的是直流电,因此需要电子调速器将其转换为三相交流电。它还需要接收遥控接收器的控制信号来控制电机的速度以满足模型的需要。与传统有刷直流电机相比,无刷电机具有能量密度高、扭矩大、重量轻、性能好等优点。它增强了电机的可靠性,但无刷电机的驱动比有刷电机复杂得多,需要特殊的电子驱动器才能正常工作。为了降低开发难度,该部分采用了车模无刷电机调速器,可以根据输入的PWM信号的占空比来控制无刷电机的转速。
2.3 主控板及其遥控模块本设计采用Vision板作为控制芯片,手机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-b sp/瑞萨-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板和一个HC-05蓝牙模块。蓝牙模块设置为自动配对后,上电后进入“传输”状态。此时,利用功能串口8编写读取解析程序,即可实现遥控器与主控板之间的数据传输。
2.3.3 自动紧急刹车控制防追尾系统是驾驶员必备的驾驶辅助工具。本次设计的防追尾系统主要利用超声波在空气中的传播速度和关系来测量。超声波具有方向性强、能量消耗慢、在介质中传播距离远的特点。事实上,当我们谈论超声波时,我们就会想到蝙蝠。是的,它的工作原理就是模仿蝙蝠。首先发出声音,然后接收返回的声音。可以根据发射和返回之间的时间差来计算距离。就是这么简单。所以我们需要有一个机制来确定光信号要发射多长时间。理论上,为了回收和收集,应在排放的同时进行采样和收集。
最初的解决方案是超声波测距。之前测量发现会频繁误触,而且采样时间很长(连续两次判断1.5m的障碍物大约需要0.5s,如果车速为2m/s,来不及刹车,主要是反应时间有点长,有碰撞风险)。这次用的是I2c距离TOF传感器,效果应该会好一点。
3. 实验步骤3.1 实验材料主控板:视觉板开发板、传感器扩展板、USB 数据线传感器:TOF 传感器、光线传感器执行器:N5056 无刷电机、LED 灯、1 个高电平触发继电器、有源蜂鸣器通讯:蓝牙HC05 辅助硬件:滑板、同步带结构、盒子、泡沫、热熔胶、公母线若干软件:已安装RT-Thread 开发环境的电脑一台
3.2 根据原理图搭建电路实验示意图:
蓝牙RX连接uart8的TX,蓝牙TX连接uart8的RX
有源蜂鸣器引脚2
继电器4脚,再单独连接LED灯并与外部电源串联
电调定义了无刷电机的9脚,电调提供电源
TOF测距SDA连接A4,SCL连接A5
光检测接A0
3.4 PCB及三维图
整体组件很少。只需将2202.54母头连接到下面的Vision板,然后将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%E 5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97?id=%e4%b9%9d%e3%80%81ra8d1-视觉板%e4%b 8%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-视觉板%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 设备驱动程序检查
以下是程序控制源码
/*• 版权所有(c) 2024, YourName• 项目:基于RT-Thread 的电机电调控制(移植自Arduino)• 功能:通过串口接收指令控制电机转速、LED、蜂鸣器,集成VL53L0X 主动刹车和光线检测自动夜灯• 删除:超声波、光敏电阻、自动急停• 新增:所有速度档位切换必须平滑加减速(步进1,每次延时50ms)• 固定:电调上电初始化问题• 新增: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位#defineLIGHT_THRESHOLD 200 //光照阈值,小于200为夜间#defineLIGHT_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_third=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;静态rt_device_t串行_dev;静态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;静态布尔is_started=false; //系统是否已启动static bool esc_initialized=false; //电调是否已完成初始化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 有兴趣的小伙伴可以去华秋开源硬件社区查看!有商业诉求的,请联系项目的作者。