0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于Vision Board开发板的电动滑板设计方案

电子发烧友开源社区 来源:电子发烧友开源社区 2026-01-13 14:12 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

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,如图电机支架同步轮及配件。

da607da8-eb5c-11f0-92de-92fbcf53809c.jpg

2.2 电机模块

电机的KV值,决定着电机的转速增加量,KV值越大转速越快。电动滑板在启动时,由于静摩擦的原因,启动的阶段阻力非常大,之后阻力会突然变小。所以,电动滑板在启动之后常常有顿挫感。电机的选择对滑板的安全性的提升显得尤为重要。根据滑板的启动的特性,应选用KV值越小的电机。

2.2.1 电机选择

本设计电机选用N5065外转子无刷电机270KV,其各项参数指标如图左边为无刷电机N5065,右边为C5065

dac59f76-eb5c-11f0-92de-92fbcf53809c.jpg

首先从电机型号上来说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使用参考

db2e561a-eb5c-11f0-92de-92fbcf53809c.jpg

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,可以快速而高效地运行机器视觉算法,实现图像处理、等功能。虽然在这个电动滑板大材小用,但是给代码框架和使用安全上提高了不少。

db987090-eb5c-11f0-92de-92fbcf53809c.jpg

参考资料见: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控制端,将手机作为遥控端使用。

dc0235a2-eb5c-11f0-92de-92fbcf53809c.jpg

本设计的遥控器和主控板上,分别有一块Vision board和一个HC-05蓝牙模块。蓝牙模块设置了自动配对之后,上电之后它们就进入“传输”状态,这时,使用函数串口8编写读取解析程序,便可实现遥控器与主控板之间的数据传输。

2.3.3 自动紧急刹车控制

防追尾系统对于驾驶员来说是一大必要辅助驾驶利器。此次设计的防追尾系统主要利用超声波在空气中的传播速度和关系进行测量。超声波具有指向性强、能量消耗慢且在介质中传播距离较远特点。其实说到超声波,我们就会想到蝙蝠,是的,它的工作原理就是模仿蝙蝠的。先发出一个声音,然后在接收返回的声音,通过发出和返回的时间差来可以计算出距离,就这么简单。所以我们就要有一个机制,发出多长的光信号,回收采集的理论上应该是发出的同时就要采样收集了。

原先的方案是超声波测距,之前实测发现会频繁误触,而且采样时间非常长(两次连续判断1.5m障碍物大约需要0.5s,如果车速在2m/s,会明显刹车来不及,主要是反应时间有点长,发生碰撞危险),这次采用I2c距离TOF传感器,看看效果应该要好一点点

dc6d6520-eb5c-11f0-92de-92fbcf53809c.jpg

3. 实验步骤

3.1 实验材料

主控板:Vision board开发板,sensor shield拓展板,USB数据线 传感器:TOF传感器,光照传感器 执行器:N5056无刷电机,LED灯,一路高电平触发继电器,有源蜂鸣器 通讯:蓝牙HC05 辅助硬件:滑板,同步带结构,盒子,泡沫,热熔胶,公母线若干 软件:一台安装RT-Thread开发环境的电脑

3.2 根据原理图搭建电路

实验原理图:dcd740ee-eb5c-11f0-92de-92fbcf53809c.jpg

蓝牙RX接uart8的TX,蓝牙TX接uart8的RX

有源蜂鸣器引脚2

继电器引脚4,然后单独接led灯与外接电源串联

ESC定义无刷电机引脚9,电调提供电源

TOF测距SDA接A4,SCL接A5

光照检测接A0

3.4 PCB及三维图

dd4243a8-eb5c-11f0-92de-92fbcf53809c.jpg

整体元器件非常少,就2202.54排母下面连接Vision board,然后6/2*8/10排母在上方连接Arduino Uno拓展板

下面是硬件细节图 拓展板焊接效果ddacba1c-eb5c-11f0-92de-92fbcf53809c.jpg

de19a91a-eb5c-11f0-92de-92fbcf53809c.jpg

控制器电源电调都安装在防水盒中de83ab08-eb5c-11f0-92de-92fbcf53809c.jpg控制盒整体外观

deee4ee0-eb5c-11f0-92de-92fbcf53809c.jpg

3.5 源码分享

配置串口2

df5fc0ac-eb5c-11f0-92de-92fbcf53809c.jpg

参考: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

dfd38780-eb5c-11f0-92de-92fbcf53809c.jpg

参考: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

e03f5640-eb5c-11f0-92de-92fbcf53809c.jpge0aa3cb2-eb5c-11f0-92de-92fbcf53809c.jpge1150be6-eb5c-11f0-92de-92fbcf53809c.jpg

参考: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

e1815530-eb5c-11f0-92de-92fbcf53809c.jpg参考: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设备驱动勾选

e1eb9850-eb5c-11f0-92de-92fbcf53809c.jpg

下面是程序控制源码

/*
• 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

e2544224-eb5c-11f0-92de-92fbcf53809c.jpg

这是一个基于RT-Thread的智能电机控制系统,通过串口指令控制无刷电机转速,集成了VL53L0X激光测距主动刹车和光线检测自动夜灯功能,具备多线程安全保护和智能决策能力。

e2c833aa-eb5c-11f0-92de-92fbcf53809c.jpg

流程说明:

多线程并行:三个独立线程分别处理用户指令、障碍物监测和光线检测

安全保护:距离监测线程具有较高优先级,确保及时刹车

智能决策:基于连续检测和阈值判断,避免误触发

模式切换:支持手动/自动模式灵活切换

平滑控制:电机速度变化采用渐进式调节,提升系统稳定性

4.动手操作

a.首先进行光照检测,如光线较弱则自动打开前灯; b.连接好蓝牙,发送“start”字符串开始遥控,发送“one”,“two”,“three”,“four”即可实现稳步增速,发送“increase”、“dicrease”即可实现精准调速,发送“turn on”、“turn off”即可打开前灯led继电器,发送“buzeer on”、“buzeer off”即可触发有源蜂鸣器声响,app不完全配置

e32fc6aa-eb5c-11f0-92de-92fbcf53809c.jpg

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 有兴趣的小伙伴可以去华秋开源硬件社区查看!有商业诉求的,请联系项目的作者。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 传感器
    +关注

    关注

    2577

    文章

    55516

    浏览量

    793973
  • Arduino
    +关注

    关注

    190

    文章

    6527

    浏览量

    197469
  • 电动滑板
    +关注

    关注

    0

    文章

    24

    浏览量

    7173

原文标题:DIY 滑板玩出黑科技!Vision Board 电动滑板,TOF 激光刹车 + 平滑调速性能体验感双在线!

文章出处:【微信号:HarmonyOS_Community,微信公众号:电子发烧友开源社区】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    基于 RT-Thread 的 Vision Board 智能电动滑板设计 | 技术集结

    目录前言设计方案实验步骤动手操作好物直达1前言在2018年我本科在万宇杰老师的带领下和小伙伴们一起立了校级重点科研立项——《DIY电动滑板》,非常怀恋那时候的干劲,闲暇时分傍晚和枚金江一起玩
    的头像 发表于 02-26 20:15 7832次阅读
    基于 RT-Thread 的 <b class='flag-5'>Vision</b> <b class='flag-5'>Board</b> 智能<b class='flag-5'>电动</b><b class='flag-5'>滑板</b>设计 | 技术集结

    Vision Board创客营连载体验】RA8D1 Vision Board初体验

    1 RA8D1 Vision Board简介 Vision-Board 开发板是 RT-Thread 推出基于瑞萨 Cortex-M85 架构 RA8D1 芯片,拥有Helium和Tr
    发表于 04-23 21:53

    Vision Board创客营连载体验】基于Vision Board的垃圾分类

    好相关选项。 顺便把SDRAM等打开。保存工程,打开工程执行编译后下载到Vision Board开发板,检查下openMV是否正常运行。 看看micropython信息: MicroPython
    发表于 06-16 17:41

    vision board开发板用MDK烧录显示成功却找不到例程,为什么?

    开发板vision board 连接好开发板后要烧录sdk仓库中的openmv例程 代码运行正常 烧录下载正常 再连接好openmv后仍然找不到相关例程代码 然后我使用瑞萨 flas
    发表于 09-22 06:34

    常规的滑板车控制系统硬件设计方案

    安全运行,对电机控制系统的性能要求很高,对电机的效率也有较大的要求。同时作为一种实用型的交通工具,要求电机控制系统能承受震动、耐受恶劣环境、可靠性高。常规的滑板车控制系统硬件设计方案如下图所示,主要包括
    发表于 11-10 07:24

    常规的滑板车控制系统硬件设计方案

    快速安全运行,对电机控制系统的性能要求很高,对电机的效率也有较大的要求。同时作为一种实用型的交通工具,要求电机控制系统能承受震动、耐受恶劣环境、可靠性高。 常规的滑板车控制系统硬件设计方案如下图所示,主要包括驱
    的头像 发表于 01-06 15:30 5419次阅读
    常规的<b class='flag-5'>滑板</b>车控制系统硬件<b class='flag-5'>设计方案</b>

    单片机开发板电路原理图设计方案免费下载

    单片机开发板电路原理图设计方案免费下载
    发表于 12-14 15:18 42次下载
    单片机<b class='flag-5'>开发板</b>电路原理图<b class='flag-5'>设计方案</b>免费下载

    OpenHarmony Dev-Board-SIG专场:OpenHarmony开发板适配经验分享

    OpenHarmony Dev-Board-SIG专场:OpenHarmony开发板适配经验分享
    的头像 发表于 12-28 14:28 1899次阅读
    OpenHarmony Dev-<b class='flag-5'>Board</b>-SIG专场:OpenHarmony<b class='flag-5'>开发板</b>适配经验分享

    OpenHarmony Dev-Board-SIG专场:开发板选型—为什么选择树莓派3B

    OpenHarmony Dev-Board-SIG专场:开发板选型—为什么选择树莓派3B
    的头像 发表于 12-28 14:51 2922次阅读
    OpenHarmony Dev-<b class='flag-5'>Board</b>-SIG专场:<b class='flag-5'>开发板</b>选型—为什么选择树莓派3B

    OpenHarmony Dev-Board-SIG专场:龙芯开发板成功移植OpenHarmony

    OpenHarmony Dev-Board-SIG专场:龙芯开发板成功移植OpenHarmony
    的头像 发表于 12-28 15:24 2639次阅读
    OpenHarmony Dev-<b class='flag-5'>Board</b>-SIG专场:龙芯<b class='flag-5'>开发板</b>成功移植OpenHarmony

    Vision Board/首款ARM Cortex-M85开发板价格大公开

    第一轮24小时限时盲购,机器视觉Vision Board获得了超预期的支持,我们由衷感谢所有开发者的热情参与。机器视觉Vision Board
    的头像 发表于 02-22 14:13 2890次阅读
    <b class='flag-5'>Vision</b> <b class='flag-5'>Board</b>/首款ARM Cortex-M85<b class='flag-5'>开发板</b>价格大公开

    Vision_Board_schematic

    Vision_Board_schematic
    发表于 03-20 09:59 11次下载

    Vision Board 创客营】Vision Board上的DAC实践

    1、概述 感谢官方举办【Vision Board 创客营】活动,使得我有机会试用Vision Board开发板,体验嵌入式AI的快乐。在此,
    的头像 发表于 04-24 21:55 1791次阅读
    【<b class='flag-5'>Vision</b> <b class='flag-5'>Board</b> 创客营】<b class='flag-5'>Vision</b> <b class='flag-5'>Board</b>上的DAC实践

    Vision-Board 使用TinyUSB驱动Xbox游戏手柄

    :  Vision-Board开发板 + 2.0寸Mipi显示屏拓展板  Xbox One游戏手柄  搭建好开发环境:Vision Board
    的头像 发表于 05-10 15:42 1977次阅读
    <b class='flag-5'>Vision-Board</b> 使用TinyUSB驱动Xbox游戏手柄

    采用XIAO MG24开发板的手套动作控制电动滑板设计

    本篇应用文章来自于Silicon Labs(芯科科技)在线技术社区,作者分享了运用XIAO MG24开发板来打造通过手套动作控制电动滑板(Electric Skateboard)的简要开发
    的头像 发表于 12-25 11:37 3806次阅读
    采用XIAO MG24<b class='flag-5'>开发板</b>的手套动作控制<b class='flag-5'>电动</b><b class='flag-5'>滑板</b>设计