骑行头盔碰撞检测 —— 基于 nRF52840 与 LSM6DS3 的低成本智能安全方案
💡 划重点
- 主控芯片:nRF52840(支持 BLE 5.0,内置 NFC,Cortex-M4F,性价比高)
- 核心传感器:LSM6DS3 六轴加速度计/陀螺仪(I2C 接口,低功耗)
- 执行单元:线性振动马达(PWM 驱动,提供分级触觉反馈)
- 通信方式:BLE 5.0(连接手机 App,实时上报碰撞事件与位置信息)
- 目标成本:整机物料低于 140 元人民币,适合小批量众筹或学生创客项目
- 核心价值:碰撞后 1 秒内触发手机报警,支持手动“我没事”确认,避免误报
需求洞察
目标用户:城市通勤骑行者、公路车运动爱好者、外卖配送骑手。
真实痛点:
- 骑行事故中,头盔受到剧烈撞击后,骑手可能昏迷或无法主动求救,周围路人难以及时发现。
- 智能手机虽有跌倒检测,但放在口袋或支架上,对“头盔撞击”这种头部冲击情境识别不准确。
- 骑手在无监控路段发生事故,错失黄金救援时间。
为什么值得做:
- 头盔是骑行必备装备,在既有安全器材上做“增量智能化”不需要改变用户佩戴习惯。
- nRF52840 与 LSM6DS3 物料成本低,芯片功耗极小(待机数微安),可做到充电一次使用两周。
- 相比市售同类产品(如 Lumos 头盔、Coros 头盔),成本仅为其十分之一,且功能聚焦“碰撞检测+报警”这一刚需场景。
方案设计
感知层:LSM6DS3 三轴加速度计+三轴陀螺仪,采样率 416Hz(可配置),通过 I2C 与主控通信。持续采集加速度数据,计算合成矢量幅度(SVM),用于检测瞬时冲击。
控制层:nRF52840 主控运行实时检测算法。使用滑动窗口(窗口长度 200ms)识别冲击峰值,当 SVM 超过阈值(默认 4g)且持续时间大于 5ms,判定为一次碰撞,进入“疑似碰撞状态”。若 3 秒内加速度恢复正常且未检测到二次冲击,则触发确认流程;若存在连续冲击,判定为严重碰撞,直接报警。
执行层:震动马达 PWM 驱动,分三级反馈:
- 一级(轻微撞击,SVM 2.5-4g):马达震动 2 次,提醒骑手检查头盔;
- 二级(中等碰撞,SVM 4-8g):马达震动 5 次,若 10 秒内无取消操作,自动发送短消息给紧急联系人;
- 三级(严重碰撞,SVM >8g):马达连续震动,立即通过 BLE 发送 SOS 信息(含 GPS 坐标,若有手机连接)。
日志/联网层:通过 BLE 5.0 与手机 App(iOS/Android)配对。设备本地缓存最近 50 条事件日志(时间戳+碰撞强度),手机连接后自动同步。App 内置紧急联系人设置、SOS 短信模板、墨迹天气与骑行路线记录(可选)。
物料清单
| 序号 | 物料名称 | 数量 | 用途 | 估算单价(元) | 小计(元) |
|---|---|---|---|---|---|
| 1 | nRF52840 核心板(如 Arduino Nano 33 BLE Sense 兼容版) | 1 | 主控 | 45.0 | 45.0 |
| 2 | LSM6DS3 六轴传感器模块(I2C 接口) | 1 | 碰撞检测 | 18.0 | 18.0 |
| 3 | 线性振动马达(扁平贴片式) | 1 | 震动反馈 | 6.0 | 6.0 |
| 4 | 锂电池 3.7V 500mAh 带保护板 | 1 | 供电 | 15.0 | 15.0 |
| 5 | TP4056 充电模块 | 1 | 充电管理 | 3.0 | 3.0 |
| 6 | 3D 打印头盔卡扣外壳(ABS+TPU) | 1 | 结构固定 | 12.0 | 12.0 |
| 7 | 轻触按键(6x6x5mm) | 2 | 取消报警/手动测试 | 1.0 | 2.0 |
| 8 | 100Ω电阻、0.1uF电容、接插件等 | 1套 | 外围电路 | 5.0 | 5.0 |
| 9 | RGB LED(0815 贴片) | 1 | 状态指示 | 2.0 | 2.0 |
| 10 | 尼龙扎带、魔术贴、导线 | 1套 | 安装辅料 | 2.0 | 2.0 |
| 11 | PCB 打样(5x5cm 四层板) | 1 | 整合所有器件 | 25.0(均摊10片样板则约15元) | 25.0 |
| 合计 | 135.0 元 |
(总预算 140 元内,预留约 5 元走线/焊接耗材。)
接线与结构
GPIO 分配表(基于 Arduino nRF52840):
- LSM6DS3 I2C → SDA(P0.14)、SCL(P0.15)
- 振动马达 PWM → P0.05(原方案指定)
- 按键1(取消报警)→ P0.11(带内部上拉)
- 按键2(手动测试)→ P0.12
- RGB LED → R=P0.08, G=P0.09, B=P0.10
- 电池电压检测 → AIN0(P0.02)
微调说明:指定 PWM 引脚 P0.05 在 nRF52840 上支持定时器通道(如 TIMER0 的 CC0 通道),可输出高频 PWM(20kHz)驱动马达,优于普通 GPIO 模拟 PWM(会有明显噪声)。其他引脚均避开 nRF52840 上 USB、NFC 等占用引脚,确保烧录调试无冲突。
物理结构:
- 主控、电池、传感器集成在一块 5cm×5cm 圆形 PCB 上。
- 整体通过 3D 打印的卡扣壳体安装于头盔后脑勺部位(重心低,不影响通风)。
- 振动马达贴合内衬泡沫,确保振动传导至皮肤。
- 壳体从外侧看呈流线型,厚度约 12mm,重量约 30g(含电池),对骑行风阻影响极小。
核心代码
以下为 PlatformIO + Arduino 框架下的可编译代码骨架(针对 nRF52840,使用 Adafruit BSP 或 Arduino Core)。
// 骑行头盔碰撞检测 - 核心骨架
// 需安装库:Adafruit_LSM6DS3, Adafruit Unified Sensor
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_LSM6DS3.h>
// 引脚定义
#define MOTOR_PWM_PIN (P0_05) // 指定PWM引脚
#define BTN_CANCEL_PIN (P0_11)
#define BTN_TEST_PIN (P0_12)
#define LED_R_PIN (P0_08)
#define LED_G_PIN (P0_09)
#define LED_B_PIN (P0_10)
// 碰撞阈值(单位:g)
#define THRESHOLD_LIGHT 2.5f
#define THRESHOLD_MEDIUM 4.0f
#define THRESHOLD_SEVERE 8.0f
Adafruit_LSM6DS3 lsm;
// 状态机
enum CollisionState {
IDLE,
SUSPECT, // 疑似碰撞,等待确认
CONFIRMED_LIGHT,
CONFIRMED_MEDIUM,
CONFIRMED_SEVERE
};
CollisionState state = IDLE;
uint32_t lastShockTime = 0;
float maxSVM = 0.0f;
void setup() {
Serial.begin(115200);
pinMode(LED_R_PIN, OUTPUT);
pinMode(LED_G_PIN, OUTPUT);
pinMode(LED_B_PIN, OUTPUT);
// 初始化 I2C 及传感器
if (!lsm.begin_I2C(LSM6DS3_ADDRESS)) {
// 错误指示:红灯常亮
digitalWrite(LED_R_PIN, HIGH);
while (1) delay(100);
}
// 初始化 LED(绿色闪烁一次表示启动成功)
digitalWrite(LED_G_PIN, HIGH);
delay(200);
digitalWrite(LED_G_PIN, LOW);
// 定时器 PWM 初始化
// (具体 PWM 频率/占空比设置由 Board 支持,可简化为 analogWrite)
analogWrite(MOTOR_PWM_PIN, 0);
}
void loop() {
lsm.getEvent(&accel;_event, &gyro;_event, nullptr);
// 计算合成矢量幅度 SVM = sqrt(x^2 + y^2 + z^2) - 1g 偏置
float ax = accel_event.acceleration.x / 9.8f; // 单位转换为 g
float ay = accel_event.acceleration.y / 9.8f;
float az = accel_event.acceleration.z / 9.8f;
float svm = sqrt(ax*ax + ay*ay + az*az);
// 刷新最大 SVM
uint32_t now = millis();
if (svm > maxSVM) maxSVM = svm;
// 状态机处理
switch (state) {
case IDLE:
if (svm > THRESHOLD_LIGHT) {
// 进入疑似碰撞状态,记录时间
state = SUSPECT;
lastShockTime = now;
// 点亮黄色 LED
digitalWrite(LED_R_PIN, HIGH);
digitalWrite(LED_G_PIN, HIGH);
}
break;
case SUSPECT:
// 检测二次冲击(严重碰撞)
if (svm > THRESHOLD_SEVERE) {
state = CONFIRMED_SEVERE;
triggerMotor(255, 3000); // 全速震动 3 秒
sendSOS(); // BLE 发送 SOS
}
// 3 秒内无二次冲击,进入中等碰撞判定
else if (now - lastShockTime > 3000) {
if (maxSVM >= THRESHOLD_MEDIUM) {
state = CONFIRMED_MEDIUM;
triggerMotor(180, 1000); // 中速震动
// BLE 通知手机,等待用户取消
} else if (maxSVM >= THRESHOLD_LIGHT) {
state = CONFIRMED_LIGHT;
triggerMotor(100, 500); // 短震动提醒
}
state = IDLE; // 复位
maxSVM = 0.0f;
}
// 取消按键:认定为人为误触(如取下头盔)
if (digitalRead(BTN_CANCEL_PIN) == LOW) {
state = IDLE;
maxSVM = 0.0f;
digitalWrite(LED_R_PIN, LOW);
digitalWrite(LED_G_PIN, LOW);
}
break;
default:
// 冷却 10 秒后回 IDLE
if (now > lastShockTime + 10000) {
state = IDLE;
maxSVM = 0.0f;
digitalWrite(LED_R_PIN, LOW);
digitalWrite(LED_G_PIN, LOW);
analogWrite(MOTOR_PWM_PIN, 0);
}
break;
}
}
// 震动马达控制(PWM 占空比 duty=0-255, 持续时间 ms)
void triggerMotor(uint8_t duty, uint16_t duration) {
delay(duration);
analogWrite(MOTOR_PWM_PIN, 0);
}
// BLE SOS 发送(骨架占位,需结合 BLE UART 或自定义服务)
void sendSOS() {
// 串口输出 SOS 信息(调试用)
Serial.println("SOS: Collision detected!");
// 实际项目:通过 BLE 发送带有时间戳与碰撞强度的通知
}
调试步骤
| 步骤 | 操作 | 预期结果 |
|---|---|---|
| 1 | 编译并烧录固件,打开串口监视器 | 上电后绿色 LED 闪烁一次,串口打印启动信息 |
| 2 | 水平放置头盔,观察串口打印 SVM 值 | 静止时 SVM 约为 1.0g(即 1g 重力),波动 < 0.1g |
| 3 | 用手掌轻拍头盔(约 2.5g 冲击) | 红色+绿色 LED 同时亮起,马达短震动 1 次,串口显示碰撞事件 |
| 4 | 用力拍打头盔(>4g) | 马达震动 5 次(中速),手机 App 收到通知并可取消 |
| 5 | 模拟严重碰撞(将头盔从 50cm 高处自由落到软垫上) | 马达全速震动 3 秒,BLE 发送 SOS 消息 |
| 6 | 按下取消按钮(P0.11) | 任何报警状态立即退出,LED 熄灭 |
| 7 | 手动测试按钮(P0.12) | 触发一次假碰撞事件,用于演示 |
| 8 | 持续运行 24 小时 | 电池电压从 4.2V 下降不超过 0.5V,无异常重启 |
设计图
骑行头盔碰撞检测结构flow
1
感知输入
→
2
控制处理
→
3
执行反馈
→
4
数据上报