尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

STM32开源智能导盲杖系统:多传感器融合、避障与低功耗实践

STM32开源智能导盲杖系统:多传感器融合、避障与低功耗实践 这套基于STM32的智能导盲杖系统的设计与实现最初是我给一个学弟做毕业设计时搭起来的原型后来发现里面的避障逻辑、震动编码、低功耗调度和开源文档组织都挺有复用价值就干脆整理成了一个完整的开源项目。它不是那种只点个灯、读个温湿度的练手 Demo而是一根真正要拿在手里、走在路上、面对复杂地面和突发姿态变化的助行设备。核心关键词就三个开源、STM32、智能导盲杖系统。你如果是嵌入式初学者、准备做 stm32 项目的学生或者想找一个能写进简历的毕业设计这套东西的完整度刚好够用如果你已经做过 stm32 教程里的各种外设实验也能从中学到多传感器融合、状态机、低功耗和开源项目管理这些更接近产品化的经验。整根杖子主要做四件事前方障碍探测、跌倒或剧烈倾斜识别、语音与震动反馈、可选的位置上报与 SOS 求助。下面我不讲空泛的概念直接按硬件选型、代码实现、调试避坑和开源发布顺序把能复现的细节全部摊开。1. 项目整体设计与关键需求拆解1.1 导盲杖到底要解决哪些真实问题很多人第一次做这个项目会本能地堆传感器超声波、红外、激光、摄像头、温湿度、心率恨不得全焊上去。但导盲杖不是传感器展示板它真正的使用场景非常具体使用者一只手握着杖体前方 0.3 米到 2 米之间需要有障碍提示地面突然出现台阶或坑洼时要有震动或语音提醒身体发生跌倒或长时间静止时能主动求助设备本身还要足够省电不能让使用者半天一充电。我把需求拆成四层。第一层是安全避障重点是前方、左前、右前三个方向探测距离不需要特别远2 米左右已经足够太远反而容易误报。第二层是姿态识别MPU6050 这类六轴传感器读取加速度和角速度判断是否发生跌倒或剧烈倾斜。第三层是人机反馈语音负责复杂信息震动负责即时方向提示按键负责 SOS 和模式切换。第四层是可选联网GNSS 获取位置物联网模组把跌倒事件和坐标上报给监护人。注意这套系统不能宣称替代专业导盲犬或专业培训它只是辅助工具定位是“提高环境感知能力”这个边界在开源文档里也要写清楚。我在实际测试时发现使用者对“延迟”比“精度”更敏感。超声波测距误差 3 厘米到 5 厘米都能接受但如果语音播报延迟超过 500 毫秒或者震动反馈忽强忽弱体验会立刻变差。所以软件架构里不能把所有事情都塞进主循环必须做时间片或 RTOS 任务划分。避障任务 50 毫秒跑一次姿态检测 20 毫秒跑一次语音播报用队列震动马达用 PWM 控制强度按键用外部中断加软件消抖。这些周期不是拍脑袋来的后面我会给出计算依据。另一个容易忽略的问题是“误报”比“漏报”更烦人。超声波在雨天、软地面、斜坡上容易乱跳如果每次乱跳都触发紧急震动使用者很快就会不信任设备。因此滤波和状态确认必须做足阈值也要留迟滞区间。比如 0.5 米内才进入紧急状态退出紧急状态要等到 0.8 米以上这样不会在临界点反复横跳。1.2 为什么我选STM32而不是Arduino、ESP32或树莓派选型时我对比过四类平台Arduino Uno、ESP32、树莓派和 STM32。Arduino 上手最快库也多但 Uno 的定时器资源紧张多路超声波和姿态解算容易互相抢资源中断响应也不够稳。ESP32 无线能力强双核跑 FreeRTOS 很舒服但模拟外设和低功耗睡眠唤醒的细节比 STM32 碎而且某些型号在电池供电场景下待机电流不够理想。树莓派适合跑视觉和复杂算法可功耗高、启动慢放在导盲杖里续航会很难看。STM32 的优势在于“实时性、外设丰富、资料多、价格低”。以 STM32F103C8T6 为例72MHz 主频64KB Flash20KB RAM多个定时器、USART、I2C、SPI、ADC、PWM足够跑三路超声波、MPU6050、语音模块和电池检测。如果后续要加 GNSS 和物联网模组可以升级到 STM32F401 或 STM32F411RAM 和主频更宽裕。对于 stm32 项目来说F103 最小系统板便宜、教程多Keil5 安装 stm32 芯片包后就能开发STM32CubeMX 生成初始化代码也很省事。这里有个选型心得不要一上来就选最贵的芯片。导盲杖的核心算法不复杂F103 完全能跑。真正影响体验的是电源设计、传感器安装角度和滤波策略而不是主频多 100MHz。如果你要跑摄像头或复杂神经网络那另说但纯超声波加姿态识别F103 是性价比最高的起点。平台优势短板适合场景Arduino Uno上手快、库多资源少、定时器紧张单传感器验证ESP32无线强、双核低功耗细节碎、模拟外设一般需要 Wi-Fi 的联网 demo树莓派算力强、系统完整功耗高、启动慢视觉和复杂算法STM32F103实时性好、外设全、便宜需要配置寄存器或 HAL导盲杖主控、低功耗设备1.3 开源策略硬件、固件、文档三层拆包既然标题里写了“开源”就不能只丢一个 Keil 工程压缩包。我把它拆成三层硬件开源、固件开源、文档开源。硬件层用立创 EDA 或 KiCad 画原理图和 PCB导出 Gerber、BOM 和坐标文件固件层用 STM32CubeMX 生成 .ioc 文件Keil 工程和 Makefile 都保留方便不同工具链的人使用文档层写清楚接线表、传感器安装角度、测试数据、常见问题和开源许可证。开源项目管理里最容易烂尾的就是“只有代码没有上下文”。别人拿到你的 GitHub 或 Gitee 仓库第一眼想知道这根杖子能做什么、需要买哪些模块、怎么烧录、怎么校准、哪些参数能改。README 里要有一张实物图、一张接线图、一段演示视频链接、一份 BOM 表和一套快速开始步骤。Issue 模板可以分“bug 反馈”“硬件问题”“功能建议”三类Pull Request 模板要求说明修改内容和测试方式。开源文档贡献不一定非得写代码整理接线图、翻译注释、补充测试数据都很有价值。许可证方面如果希望别人随意使用甚至商用选 MIT如果在意专利授权和贡献者条款选 Apache-2.0如果希望衍生项目也必须开源选 GPL 系列。硬件文件可以单独选 CERN-OHL 或 CC BY-SA。gitee 开源许可证选什么这个问题没有标准答案关键是 README 里写清楚不要让使用者猜。2. 硬件选型、电路连接与参数计算2.1 主控、传感器与执行器清单我的基础版清单如下主控用 STM32F103C8T6 最小系统板避障用三路 HC-SR04 超声波分别朝前、左前、右前姿态检测用 MPU6050I2C 接口语音播报用 SYN6288 或类似串口语音模块震动反馈用扁平振动马达通过 MOS 管或驱动芯片控制SOS 按键用带金属帽的轻触开关电源用 3.7V 锂电池加 TP4056 充电板再经 ME6211 或 MP1584 降压到 3.3V电池检测用电阻分压到 ADC。如果要联网再加 GNSS 模块和 Cat.1 或 NB-IoT 模组。这里重点说三个选型细节。第一超声波模块别买太便宜的有些 HC-SR04 在 3.3V 下工作不稳定建议用支持 3.3V 的版本或者给超声波单独供 5VEcho 脚用电阻分压到 3.3V。第二MPU6050 要买正品或质量好的模块山寨模块零偏大校准后还会漂。第三振动马达不要直接接 GPIOSTM32 单个 IO 通常只能输出 20mA 左右马达启动电流可能超过 80mA必须加三极管或 MOS 管驱动并反向并联续流二极管。执行器方面语音模块负责播报“前方障碍”“左前方障碍”“跌倒报警”“电量低”等语句震动马达负责即时方向提示。为什么不用语音做所有提示因为语音播报有延迟而且连续播报会吵。震动编码可以做到 50 毫秒内响应短震一下表示前方两下表示左侧三下表示右侧长震表示紧急。这样使用者在嘈杂环境中也能感知。模块型号建议接口关键注意点主控STM32F103C8T6—保留 SWD 下载口超声波HC-SR04GPIO 定时器Echo 分压分时触发姿态MPU6050I2C上拉 4.7k远离电机语音SYN6288USART独立 5V 供电串口电平匹配震动扁平马达PWM MOS加续流二极管电源TP4056 ME6211—电池检测分压到 ADC2.2 电源与续航计算别让电池拖后腿续航是导盲杖能不能用的硬指标。假设用 3.7V 2000mAh 锂电池系统平均电流 120mA其中 STM32 约 30mA三路超声波合计约 45mAMPU6050 约 4mA语音模块待机约 15mA振动马达按 10% 占空比折算约 8mA其他损耗约 18mA。理论续航是 2000mAh ÷ 120mA ≈ 16.6 小时。但电源转换效率不是 100%ME6211 线性稳压在 3.7V 转 3.3V 时效率约 89%如果换成 MP1584 降压效率可到 85% 到 92%。按 85% 算实际可用续航约 16.6 × 0.85 ≈ 14.1 小时。如果加上 Cat.1 模组发射峰值可能到 2A平均电流增加 30mA 到 50mA续航会掉到 9 到 11 小时。所以电源设计有三个关键点。第一锂电池电压从 4.2V 降到 3.3V 左右LDO 在低压差时效率会变差建议用低压差 LDO 或升降压方案。第二大电流模组旁边要放 470uF 到 1000uF 电解电容再并 100nF 陶瓷电容防止发射瞬间把主控拉复位。第三电池检测分压电阻不能太小否则一直耗电。比如 100k 和 100k 分压3.7V 时电流约 18.5uA可以接受ADC 12 位3.3V 参考分辨率约 0.8mV对应电池电压约 1.6mV足够判断低电量。低电量阈值我设了两级3.6V 时语音提示“电量低”3.45V 时关闭联网和语音只保留避障和震动尽量延长关键功能。不要等到 3.3V 才处理因为电机启动瞬间电压跌落可能直接复位。2.3 接线表与关键外设分配外设分配要提前规划不然后面改代码很痛苦。我的分配如下USART1 接 GNSSUSART2 接语音模块I2C1 接 MPU6050TIM2 用于超声波回波捕获TIM3 CH1 输出 PWM 控制震动马达ADC1 IN0 检测电池PB0 接 SOS 按键并开启外部中断。三路超声波的 Trig 分别接 PA1、PA2、PA3Echo 通过分压后接 PA6、PA7、PB1也可以统一接到定时器输入捕获通道。HC-SR04 的 Echo 输出是 5VSTM32 很多引脚虽然不是 5V 容忍但部分型号有 FT 标记。保险做法是分压Echo 接 1k 电阻到节点节点再接 2k 电阻到地节点电压约 5V × 2/3 3.33V。如果 Echo 高电平持续时间长分压电阻会发热但超声波回波一般几毫秒问题不大。更稳妥的是用 74HC4050 或电平转换芯片。语音模块的串口电平也要注意。有些模块是 5V TTLSTM32 是 3.3V直接连可能通信不稳定。可以在 STM32 TX 到语音 RX 之间加电平转换或者选支持 3.3V 的语音模块。调试时先单独测试语音模块用 USB 转串口发命令确认能播报后再接主控。STM32 引脚外设说明PA9/PA10USART1GNSS 定位PA2/PA3USART2语音模块PB6/PB7I2C1MPU6050PA1/PA2/PA3GPIO超声波 TrigPA6/PA7/PB1TIM 输入捕获超声波 EchoTIM3 CH1PWM震动马达PA0ADC1 IN0电池检测PB0EXTISOS 按键2.4 结构安装与可靠性细节传感器安装角度直接决定误报率。超声波不要完全水平建议朝前略微向下 5 到 10 度这样可以探测到低矮障碍和台阶边缘但又不会把地面回波当障碍。三路超声波之间要有物理隔板或吸音棉减少交叉干扰。MPU6050 要尽量安装在杖体靠近手部的位置远离振动马达否则马达震动会污染姿态数据。杖体材料可以用碳纤维管或铝合金管重量轻、刚度好。线缆走管内出口用热缩管和硅胶密封防止雨水进入。开关和充电口放在手部附近方便操作。振动马达固定在握把内部让震动集中传递到手掌。电池放在杖体中下部降低重心。整个结构要能拆装方便调试和更换模块。我踩过的一个坑是震动马达和 MPU6050 共用一块洞洞板结果每次震动都触发姿态中断。后来把 MPU6050 用软排线移到上方 15 厘米处并在代码里加 100 毫秒屏蔽窗口问题才解决。结构设计和软件滤波要一起考虑不能只靠代码补救。3. 软件架构与核心代码实现3.1 裸机时间片还是FreeRTOSSTM32F103C8T6 只有 20KB RAM跑 FreeRTOS 不是不行但任务多了内存紧张。我的基础版用裸机时间片SysTick 1 毫秒中断维护多个计数器主循环按标志位执行任务。避障任务 50 毫秒一次姿态任务 20 毫秒一次电池检测 1 秒一次语音队列随时处理。每个任务都尽量短不阻塞。这样代码简单调试直观适合初学者。如果你用的是 STM32F401/F411或者要同时跑 GNSS 解析、联网协议和语音队列建议上 FreeRTOS。任务划分可以是SensorTask 负责超声波和 MPU6050DecisionTask 负责状态机FeedbackTask 负责语音和震动CommTask 负责定位上报PowerTask 负责低功耗。任务之间用队列和事件组通信中断只置标志不做复杂处理。无论裸机还是 RTOS原则都是“中断快进快出主循环做决策”。任务周期职责注意事项避障采集50ms读三路超声波分时触发避免串扰姿态检测20ms读 MPU6050先滤波再判断电池检测1s读 ADC多次平均语音反馈事件触发播放优先级语句队列不覆盖紧急语句震动反馈事件触发PWM 编码与姿态检测错开3.2 超声波测距与滤波实战超声波测距公式很简单距离 声速 × 时间 ÷ 2。声速在 15°C 时约 340m/s温度变化时可用 331.4 0.6 × T 修正。HC-SR04 的 Echo 高电平时间对应往返时间单位微秒距离厘米 时间 × 0.034 ÷ 2。比如 Echo 高电平 1000us距离 1000 × 0.034 / 2 17cm。实际代码里我会用定时器捕获避免阻塞。三路超声波不能同时触发否则回波互相干扰。我的做法是每 50 毫秒依次触发前、左前、右前每路间隔 15 毫秒确保上一路回波已经结束。每路连续采 5 次去掉最大值和最小值再取平均最后做滑动平均。代码框架如下#define US_NUM 3 #define SAMPLE_COUNT 5 #define FILTER_WINDOW 4 typedef struct { uint16_t raw[SAMPLE_COUNT]; uint16_t history[FILTER_WINDOW]; uint8_t index; uint16_t distance_cm; } Ultrasonic_t; static Ultrasonic_t us[US_NUM]; static uint16_t Ultrasonic_ReadOnce(uint8_t id) { uint32_t start, end; GPIO_SetBits(TRIG_PORT[id], TRIG_PIN[id]); delay_us(12); GPIO_ResetBits(TRIG_PORT[id], TRIG_PIN[id]); while (GPIO_ReadInputDataBit(ECHO_PORT[id], ECHO_PIN[id]) 0) { if (start 30000) return 999; // 超时 } start 0; while (GPIO_ReadInputDataBit(ECHO_PORT[id], ECHO_PIN[id]) 1) { start; if (start 30000) return 999; } end start; return (uint16_t)(end * 0.034f / 2.0f); } static uint16_t Ultrasonic_GetDistance(uint8_t id) { uint16_t temp[SAMPLE_COUNT]; uint16_t sum 0, min 999, max 0; for (uint8_t i 0; i SAMPLE_COUNT; i) { temp[i] Ultrasonic_ReadOnce(id); delay_ms(5); } for (uint8_t i 0; i SAMPLE_COUNT; i) { if (temp[i] min) min temp[i]; if (temp[i] max) max temp[i]; } for (uint8_t i 0; i SAMPLE_COUNT; i) { if (temp[i] ! min temp[i] ! max) sum temp[i]; } return sum / (SAMPLE_COUNT - 2); }滤波之后避障阈值我设三档0 到 50 厘米是紧急50 到 120 厘米是提醒120 到 250 厘米是关注。进入紧急状态后要持续震动退出阈值放宽到 80 厘米避免临界抖动。语音播报只在状态变化时触发不要每 50 毫秒都播报。震动编码里前方障碍用短震一下左侧用两下右侧用三下紧急状态用连续长震。这样使用者不用听语音也能判断方向。3.3 MPU6050跌倒检测与姿态阈值MPU6050 读取三轴加速度和三轴角速度。跌倒检测不必上复杂卡尔曼滤波先用一阶低通滤波和阈值判断就能做到可用。合加速度 A sqrt(ax² ay² az²)。静止时约 1g跌倒撞击瞬间可能小于 0.6g 或大于 2.0g。倾角可以用加速度反算俯仰角 p atan2(ay, az) × 57.3横滚角 r atan2(-ax, sqrt(ay² az²)) × 57.3。如果倾角超过 60 度并持续 500 毫秒同时合加速度异常就进入跌倒预警再确认 1 秒内没有恢复就触发 SOS。typedef struct { float ax, ay, az; float gx, gy, gz; float pitch, roll; float a_total; } ImuData_t; static float lpf(float new_val, float old_val) { return old_val * 0.8f new_val * 0.2f; } void Imu_Update(ImuData_t *imu) { imu-ax lpf(MPU_ReadAccelX(), imu-ax); imu-ay lpf(MPU_ReadAccelY(), imu-ay); imu-az lpf(MPU_ReadAccelZ(), imu-az); imu-a_total sqrtf(imu-ax * imu-ax imu-ay * imu-ay imu-az * imu-az); imu-pitch atan2f(imu-ay, imu-az) * 57.3f; imu-roll atan2f(-imu-ax, sqrtf(imu-ay * imu-ay imu-az * imu-az)) * 57.3f; } uint8_t Fall_Check(ImuData_t *imu) { static uint16_t tilt_count 0; if ((fabsf(imu-pitch) 60.0f || fabsf(imu-roll) 60.0f) (imu-a_total 0.6f || imu-a_total 2.0f)) { tilt_count; } else { tilt_count 0; } if (tilt_count 25) { // 20ms * 25 500ms tilt_count 0; return 1; } return 0; }校准很关键。上电后前 2 秒保持静止采集 200 组数据算零偏之后每 10 分钟自动校准一次或者用按键手动校准。如果零偏漂移大可以加温度补偿但 F103 资源有限先保证静止校准和安装方向正确。MPU6050 的 X 轴方向要和杖体前进方向一致否则倾角判断会反。3.4 语音播报、震动反馈与SOS按键状态机反馈系统最怕“抢话”。如果避障正在播报“前方障碍”跌倒检测触发“跌倒报警”语音模块不能同时处理两条。我的做法是做一个优先级队列紧急 SOS 优先级最高其次是跌倒预警再到避障紧急再到普通方向提示最后是电量提示。同优先级只保留最新一条低优先级不能覆盖高优先级。队列长度 4 就够每条语音播报前先查询模块忙状态。震动反馈用 PWM 占空比控制强度。低强度提醒占空比 30%紧急提醒 70%。编码如下typedef enum { VIB_NONE 0, VIB_FRONT_SHORT, VIB_LEFT_DOUBLE, VIB_RIGHT_TRIPLE, VIB_EMERGENCY_LONG } VibCode_t; void Vib_Play(VibCode_t code) { switch (code) { case VIB_FRONT_SHORT: Vib_On(30); delay_ms(80); Vib_Off(); break; case VIB_LEFT_DOUBLE: Vib_On(50); delay_ms(80); Vib_Off(); delay_ms(80); Vib_On(50); delay_ms(80); Vib_Off(); break; case VIB_RIGHT_TRIPLE: for (int i 0; i 3; i) { Vib_On(50); delay_ms(80); Vib_Off(); delay_ms(80); } break; case VIB_EMERGENCY_LONG: Vib_On(80); delay_ms(500); Vib_Off(); break; default: break; } }SOS 按键用 PB0 外部中断下降沿触发中断里只置标志主循环消抖 50 毫秒。短按切换模式长按 3 秒进入 SOS。进入 SOS 后先语音播报“正在发送求助”然后通过联网模组上报坐标如果没有联网模组就本地持续蜂鸣和震动直到再次长按取消。状态机可以用枚举实现IDLE、AVOID、FALL_WARN、SOS、LOW_BAT。每个状态有进入动作、退出条件和超时时间代码结构清晰也方便写论文。3.5 定位与远程通知的低功耗策略如果项目要展示联网功能可以加 GNSS 和 Cat.1 或 NB-IoT 模组。GNSS 冷启动可能 30 秒到 60 秒热启动几秒。为了省电不要一直开着 GNSS。我的策略是平时每 5 分钟定位一次跌倒或 SOS 时立即开启 GNSS拿到有效定位后上报然后关闭。上报坐标时加入时间戳和事件类型监护人端可以是一个简单的手机页面或小程序但这部分建议只做到“上报到测试服务器”即可避免涉及复杂隐私问题。低功耗管理分三档正常模式所有功能开启省电模式关闭 GNSS 和语音只保留避障和震动休眠模式只保留按键唤醒和姿态中断。STM32F103 的 STOP 模式电流约 20uA 到 50uA但外设模块可能更耗电所以关模块比关 MCU 更重要。语音模块待机 15mAGNSS 待机 10mA联网模组待机 3mA 到 20mA长时间不用就直接断电。可以用 MOS 管控制各模块电源主控 GPIO 输出高电平开低电平关。3.6 开源固件工程目录与构建方式开源仓库建议按下面结构组织别人一眼就能找到东西smart-cane-stm32/ ├── firmware/ │ ├── Core/ │ ├── Drivers/ │ ├── App/ │ │ ├── ultrasonic.c/h │ │ ├── imu.c/h │ │ ├── voice.c/h │ │ ├── vib.c/h │ │ └── state_machine.c/h │ ├── smart-cane.ioc │ └── Makefile ├── hardware/ │ ├── schematic.pdf │ ├── pcb/ │ └── BOM.csv ├── docs/ │ ├── wiring.md │ ├── calibration.md │ ── faq.md ├── tools/ │ └── serial_debug.py └── README.md构建方式有两种Keil5 工程和 Makefile。Keil5 需要安装 stm32 芯片包打开 .uvprojx 就能编译Makefile 用 arm-none-eabi-gcc适合 Linux 和 macOS。STM32CubeMX 的 .ioc 文件一定要提交这样别人能重新生成初始化代码。串口调试脚本可以用 Python 写读传感器数据并画曲线方便调滤波参数。4. 调试、常见问题与避坑实录4.1 超声波乱跳、误报的排查顺序超声波数据乱跳是最常见的问题。我的排查顺序是先看电源再看触发间隔再看回波超时再看交叉干扰最后才怀疑滤波。电源方面如果超声波和马达共用 5V马达启动瞬间电压跌落超声波会读出 999。触发间隔太短上一路回波还没结束就触发下一路会收到错误回波。回波超时没有处理程序会一直等主循环卡死。交叉干扰需要分时触发或加隔音棉。滤波只能解决随机噪声不能解决系统性错误。实测中软地面和斜坡最容易误报。超声波打到地面再返回会算出很近的距离。解决办法是把超声波朝前略微向下但不要太低同时在代码里加“连续 3 次小于阈值才触发”的确认机制。如果某一路连续 5 次都是 999标记为故障语音提示“左前传感器异常”而不是继续用错误数据。4.2 I2C死锁、串口冲突、复位异常I2C 死锁表现为 MPU6050 读不到数据程序卡在等待 ACK。原因可能是总线被拉低、上拉电阻太大、电源抖动。解决办法是加 4.7k 上拉软件里加超时超时后手动发送 9 个时钟脉冲恢复总线。STM32 的 I2C 外设有时会卡死可以用 GPIO 模拟 I2C虽然慢但稳定。串口冲突常见于语音模块和调试串口共用 USART。语音模块如果一直发数据会占用接收中断。建议语音模块只用 TXSTM32 只发不收或者单独分配 USART。printf 重定向到串口时注意不要和 GNSS 数据混在一起可以加前缀区分。复位异常多半是电源问题。马达启动、联网模组发射都会拉低电压。解决方法是加大电容、分开供电、缩短地线回路。看门狗复位也要排查如果某个任务阻塞超过看门狗时间就会不断复位。可以在复位后读取 RCC_CSR 寄存器判断复位来源打印到串口。现象可能原因排查方法解决超声波读 999超时、电压跌落示波器看 5V加电容、分时触发MPU6050 无数据I2C 死锁示波器看 SCL/SDA上拉 4.7k、总线恢复语音不播报串口电平不匹配USB 转串口单独测电平转换、独立供电系统反复复位电源跌落、看门狗读复位标志大电容、任务喂狗震动误触发跌倒马达干扰 IMU屏蔽窗口测试分离安装、软件屏蔽4.3 雨天、强光、地面材质等场景测试导盲杖要在真实环境里测试不能只在实验室桌面。我做了几类场景平整水泥地、盲道砖、草地、斜坡、雨天、夜间。超声波在雨天会有水膜影响回波变弱误报率上升红外避障在强光下容易饱和草地会吸收超声波测距变短。解决办法是超声波加 ToF 传感器互补红外只做近距离辅助不单独作为决策依据。测试时记录数据很重要。我会用串口把三路超声波距离、IMU 角度、电池电压、状态机状态一起输出再用 Python 脚本存成 CSV。每次测试后对比不同场景的误报次数和漏报次数。比如平整地面误报少于 1 次/分钟草地可能到 3 次/分钟那就需要调整阈值或增加确认次数。这些测试数据写进开源文档比空口说“效果良好”有说服力。4.4 常见问题速查表问题快速定位处理建议编译报错找不到芯片包Keil5 未安装对应 Pack安装 STM32F1xx DFP下载失败SWD 引脚被占用检查 PA13/PA14复位后连接电池电压检测不准分压电阻误差、ADC 参考不稳校准分压比多次平均语音播报断断续续串口波特率不对、供电不足确认波特率独立 5V 供电省电模式唤醒失败中断配置错误检查 EXTI 和 STOP 模式引脚开源仓库别人跑不起来文档缺失、依赖不全补 README、BOM、接线图5. 开源发布、许可证与协作经验5.1 许可证怎么选MIT、Apache-2.0、GPL的三条路开源许可证不是越宽松越好而是看你的目的。MIT 最宽松别人可以闭源商用只需保留版权声明。Apache-2.0 也宽松但多了专利授权和贡献者条款适合有公司参与的项目。GPL 要求衍生项目同样开源适合你希望社区持续回馈的场景。硬件设计文件可以选 CERN-OHL-P 或 CC BY-SA 4.0。gitee 和 GitHub 都支持这些许可证创建仓库时可以直接选。我个人的建议是固件选 MIT 或 Apache-2.0硬件选 CERN-OHL-P文档选 CC BY-SA。README 里明确写“本项目仅供学习和研究不构成医疗建议使用时请遵守当地规定”。这句话不是形式而是边界。开源项目最怕别人拿去做未经验证的医疗设备写清楚能避免很多麻烦。5.2 README、BOM、接线图、Issue模板怎么写得让人愿意用README 是开源项目的门面。我的 README 结构是项目简介、功能列表、实物图、演示视频、硬件清单、接线图、编译步骤、烧录步骤、校准步骤、常见问题、许可证。BOM 表要包含型号、数量、封装、购买链接或替代型号。接线图用 Fritzing 或立创 EDA 导出 PNG标注每个引脚。Issue 模板分三类bug 反馈要求提供固件版本、硬件版本、复现步骤硬件问题要求提供原理图片段功能建议要求说明使用场景。开源文档贡献也是社区参与的重要方式。有人不会写代码但可以帮忙整理接线表、翻译注释、录制演示视频、补充测试数据。你可以在仓库里建一个docs/目录把待办事项列成 issue标记good first issue降低贡献门槛。开源项目管理里及时回复 issue 和 PR 比代码写得多漂亮更能积累口碑。5.3 版本管理与贡献流程Git 分支建议用main稳定版develop开发版功能分支feature/xxx修复分支fix/xxx。提交信息写清楚模块和动作比如ultrasonic: add median filter、docs: update wiring diagram。发布版本打 tag比如v1.0.0并在 release 里附上固件 bin 文件、BOM 和接线图。如果条件允许加一个 GitHub Actions 或 Gitee Go 流水线自动编译固件并检查格式。贡献流程写进CONTRIBUTING.md先开 issue 讨论再提 PRPR 必须说明修改内容、测试平台、测试结果代码风格尽量统一变量命名用英文注释可以中英双语。代码合并前至少自测一遍最好附上串口日志或视频。5.4 毕业设计/比赛展示中的加分项如果是拿这套系统做毕业设计论文里不要只写“实现了什么”要写“为什么这样选”和“测试数据”。比如对比单超声波和三轮超声波的误报率对比不同滤波算法的响应延迟给出电池续航计算过程。展示时准备一段实走视频从平整地面走到斜坡再模拟跌倒让评委看到状态机切换和语音震动反馈。比赛答辩时开源仓库本身也是加分项说明你有文档意识和协作意识。不过要注意演示环境要安全不要在马路上实测也不要在人多的地方突然触发 SOS。测试时最好有同伴陪同杖体尖端加防滑套。所有对外展示都要说明这是辅助原型不是成熟医疗产品。我个人在实际操作中的体会是这个项目最值得花时间的不是堆传感器而是把超声波滤波、震动编码、电源抗扰和开源文档这四件事做扎实。刚开始我也走过弯路买过一堆用不上的模块后来发现三路超声波加一个 MPU6050 已经能覆盖大部分演示需求。先把单路超声波调稳再加第二路、第三路先把震动反馈做好再加语音先把裸机时间片跑通再考虑 FreeRTOS 和联网。每一步都留下测试记录最后整理成仓库别人拿到你的开源工程能照着接线、烧录、校准、复现这比任何花哨功能都更有价值。
返回列表