矫正坐姿背带贴片:75 元内让驼背提醒“贴”身又安静
💡 划重点
- 用 XIAO ESP32-S3 做大脑,MPU6050 感知躯干前倾角,震动马达贴在肩胛之间提醒。目标成本 75 元以内,适合学生和白领日常佩戴。I2C 接 D5/D6,震动马达接 D7,USB-C 充电。核心逻辑是“持续前倾超过阈值 30 秒才震”,避免频繁误扰。
需求洞察
长时间低头写作业、盯屏幕,颈椎和腰椎压力会成倍增加。学生党一坐两小时,白领一开视频会就忘了姿势。市面上矫正带多是弹性拉扯,靠“勒”让人挺直,时间久了肩背酸痛;智能矫姿器又常卖到 200 元以上,还要专用 App。
真实痛点有三个:第一,忘记自己正在驼背,需要一个“不打扰但有效”的触觉提醒;第二,不愿意每天充电,所以续航要撑过一周;第三,佩戴要隐蔽,不能像背背佳一样显眼。这个项目把贴片缝在背带内侧,用低功耗芯片做角度判断,只在持续不良姿势时震动,不闪灯、不响铃。75 元内能覆盖核心器件,学生和普通白领都愿意试。
方案设计
感知层:MPU6050 六轴传感器,取俯仰角(pitch)判断躯干前倾。加速度计在静态下已经够用,陀螺仪用来过滤快速晃动。采样率 20Hz,窗口 1 秒做均值,减少走路、弯腰捡东西造成的误报。
控制层:XIAO ESP32-S3 负责数据融合、阈值判断、计时和电池管理。前倾角超过 25° 且持续 30 秒,触发震动;回到 15° 以下持续 5 秒,解除计时。设置 10 秒最短震动间隔,防止连续打扰。
执行层:震动马达通过 NPN 三极管或 MOSFET 驱动,GPIO 7 输出 PWM 控制强度。轻震 0.8 秒为“提醒”,强震 1.5 秒为“警告”,两者不用声音,课堂和会议室都能用。
日志/联网层:ESP32-S3 自带 Wi-Fi 和 BLE。日常开启 BLE 广播,手机端可接收姿势事件计数;需要分析时连 Wi-Fi 上传简易 CSV 到本地服务器。默认不联网,只有按键触发才同步,省电且隐私友好。
物料清单
| 物料 | 数量 | 用途 | 估算单价 |
|---|---|---|---|
| XIAO ESP32-S3 | 1 | 主控,负责角度计算与 BLE | 32 元 |
| MPU6050 模块 | 1 | 采集三轴加速度和角速度 | 8 元 |
| 微型震动马达 | 1 | 触觉提醒 | 5 元 |
| 3.7V 锂电 400mAh | 1 | 供电,可 USB-C 充电 | 12 元 |
| TP4056 充电板 | 1 | 锂电充电保护 | 4 元 |
| MOSFET 或 NPN 三极管 | 1 | 驱动震动马达 | 1 元 |
| 电阻、电容、导线 | 若干 | 限流、滤波、连接 | 4 元 |
| 弹力背带 + 贴片布套 | 1 | 佩戴结构 | 6 元 |
| 合计 | 72 元 |
接线与结构
MPU6050 的 SDA 接 XIAO ESP32-S3 的 D5,SCL 接 D6,VCC 接 3.3V,GND 共地。震动马达正极接 3.7V 锂电正极,负极接 MOSFET 漏极,MOSFET 栅极接 D7,源极接地,栅极串 100Ω 电阻到 D7,并加 10kΩ 下拉。TP4056 的 OUT+ 接升压或直接给 XIAO 的 5V 引脚(XIAO 内部有 LDO),OUT- 接地。充电口用 TP4056 的 USB-C 母座,不用额外开孔。
结构上,MPU6050 和主控、电池分两层:传感器放在背带正对胸椎的位置,减少衣服晃动影响;主控和电池放在腰侧小袋,用排线连到传感器。震动马达缝在肩胛骨中间,隔着内衬震动,不直接贴皮肤。整体厚度控制在 8mm 以内,外穿校服或衬衫看不出。
核心代码
以下为 Arduino 骨架,基于 XIAO ESP32-S3 和 MPU6050 库:
#include <Wire.h>
#include <MPU6050.h>
MPU6050 mpu;
const int motorPin = 7;
const float THRESHOLD = 25.0;
const float RELEASE = 15.0;
const unsigned long BAD_MS = 30000;
const unsigned long GOOD_MS = 5000;
unsigned long badSince = 0, goodSince = 0, lastBuzz = 0;
bool badActive = false;
void setup() {
Wire.begin(5, 6);
mpu.initialize();
pinMode(motorPin, OUTPUT);
digitalWrite(motorPin, LOW);
}
float readPitch() {
int16_t ax, ay, az;
mpu.getAcceleration(&ax;, &ay;, &az;);
float axf = ax / 16384.0, ayf = ay / 16384.0, azf = az / 16384.0;
return atan2(-axf, sqrt(ayf*ayf + azf*azf)) * 180.0 / PI;
}
void buzz(int ms) {
analogWrite(motorPin, 180);
delay(ms);
analogWrite(motorPin, 0);
}
void loop() {
float pitch = readPitch();
unsigned long now = millis();
if (pitch > THRESHOLD) {
goodSince = 0;
if (badSince == 0) badSince = now;
if (!badActive && now - badSince > BAD_MS && now - lastBuzz > 10000) {
badActive = true;
lastBuzz = now;
buzz(800);
if (pitch > 35) buzz(1500);
}
} else if (pitch < RELEASE) {
badSince = 0;
if (badActive) {
if (goodSince == 0) goodSince = now;
if (now - goodSince > GOOD_MS) badActive = false;
}
}
delay(50);
}
阈值和持续时间可在代码头部调整。若误报多,把 THRESHOLD 调到 30;若觉得反应慢,把 BAD_MS 降到 20000。
调试步骤
- 先只烧录 I2C 扫描,确认 MPU6050 地址为 0x68 或 0x69。
- 串口打印 pitch 值,坐直时应该接近 0°,前倾 30° 时读数约 25~35°。
- 用手持传感器模拟前倾,观察 30 秒后是否震动,回正 5 秒后是否停止。
- 戴上背带做真实测试,记录误报次数,调整阈值和最短间隔。
- 测电池续航:400mAh 在 20Hz 采样、BLE 广播下约 8~10 小时;关闭 BLE 可到 20 小时以上。
- 充电测试:USB-C 接入 TP4056,红灯转绿灯约 1 小时,充电时设备可继续工作。