1. 项目概述:用传感器技术辅助管理抽动症状
在辅助技术与个性化医疗设备领域,开源硬件平台如Arduino为我们打开了一扇低成本、高灵活性的创新之门。今天分享的这个项目,源于一个实际的需求:如何为受抽动秽语综合征(Tourette Syndrome)或类似运动性抽动困扰的朋友,提供一个 discreet(不显眼)且有效的自我觉察辅助工具。这类神经系统状况导致的非自主性动作或发声,虽然通常无害,但可能在社交、学习或工作中带来困扰。药物治疗并非对所有人都适用,且可能存在副作用。行为干预,如习惯逆转训练,其核心之一是提高个体对抽动前兆或动作本身的觉察力。传统方法可能需要治疗师或家人频繁提醒,而这在很多时候并不现实。
这个项目的核心思路,就是利用传感器技术将这个过程自动化。我们制作一个名为“Ticcer”的可穿戴设备,其核心是一个弯曲传感器(Flex Sensor)。你可以把它想象成一个微型的、可感知弯曲程度的“尺子”。当它被贴在容易发生抽动动作的身体部位(如手腕、颈部)时,任何弯曲动作都会改变其内部电阻。通过Arduino微控制器读取这个变化,我们就能量化“动作”的幅度。设定一个合理的阈值后,设备就能区分“正常活动”和“可能是一次抽动”。一旦检测到抽动,设备会通过蓝牙模块,悄无声息地向你的手机发送一个提醒。这个震动或声音提示,就像一个温和的“哨兵”,帮助你及时意识到动作的发生,为后续可能的干预(如有意识地延迟或转换动作)创造了一个时间窗口。
整个项目非常适合对电子制作、编程感兴趣的创客、康复工程学生,或有兴趣为家人朋友定制辅助工具的开发者。它不涉及复杂的医学诊断,而是一个聚焦于“监测与提醒”的辅助工具。下面,我将从设计思路、硬件选型、软件实现到调试封装,完整拆解这个项目的每一个环节,并分享我在实际制作中踩过的坑和总结的经验。
2. 核心硬件选型与电路设计解析
一套稳定可靠的硬件是项目成功的基石。这里的选型原则是:在满足功能需求的前提下,优先考虑易得性、可靠性和佩戴舒适性。
2.1 微控制器:为何是Arduino Uno?
项目原型选择了Arduino Uno,这是一个非常稳妥且明智的起点。Uno板载了ATmega328P微处理器,具有14路数字I/O口和6路模拟输入口(A0-A5),这对于读取弯曲传感器的模拟信号绰绰有余。其5V的工作电压与大多数传感器、模块兼容,且通过USB供电或外部电池供电都非常方便。丰富的社区资源和库文件支持,能让开发者快速上手。
注意:在实际制作可穿戴设备时,Uno的尺寸可能偏大。在完成原型验证后,强烈建议更换为更小巧的版本,如Arduino Nano或Seeed Studio的XIAO系列。Nano在功能上与Uno几乎完全一致,但体积小得多,更适合集成到最终外壳中。我在后续迭代中就换用了Nano,并使用了3.7V锂聚合物电池供电,大大提升了设备的便携性和佩戴友好度。
2.2 感知核心:弯曲传感器的工作原理与选型
弯曲传感器是本项目的“眼睛”。市面上常见的有两种:一种是基于碳脂(Carbon Ink)的电阻式弯曲传感器,另一种是光纤弯曲传感器。我们使用的是前者,型号如SparkFun SEN-10264(2.2英寸)。
它的工作原理很简单:传感器主体是一段附着有特殊导电碳脂材料的柔性塑料片。当塑料片保持平直时,碳脂路径的电阻相对较低(例如约10kΩ)。当你弯曲它时,碳脂层被拉伸,内部导电粒子间的距离增大,导致电阻值升高。弯曲弧度越大,电阻值增加越多。这种电阻变化与弯曲程度在一定范围内呈较好的线性关系,非常适合用于检测关节或肢体的弯曲动作。
选购时需要注意几个参数:
- 阻值范围:平直电阻和最大弯曲电阻。SEN-10264的典型值约为平直10kΩ,弯曲90度时约40-60kΩ。了解这个范围有助于我们设计后续的读取电路。
- 尺寸与柔性:根据你要监测的身体部位选择长度。2.2英寸适合手腕、手指;更长或更短的型号可用于颈部或脚踝。
- 耐用性:碳脂传感器反复弯折会有寿命限制,选择有柔性封装、弯折寿命较高的产品。
2.3 信号调理:不可或缺的分压电路
Arduino的模拟输入口(ADC)测量的是电压(0-5V),而不是电阻。因此,我们需要一个电路将弯曲传感器的电阻变化转换为电压变化。最经典、最可靠的方法就是使用一个分压电路。
具体做法是,将弯曲传感器与一个固定电阻串联,接在Arduino的5V和GND之间。传感器的可变电阻和固定电阻共同对5V电压进行分压。我们从这两个电阻的连接点(即中间节点)引出信号线,接入Arduino的模拟输入口(如A0)。根据欧姆定律,该点的电压 V_out = 5V * (R_fixed / (R_sensor + R_fixed))。
当传感器平直(R_sensor小)时,V_out较高;当传感器弯曲(R_sensor大)时,V_out较低。这样,我们就得到了一个随弯曲程度变化的电压信号。
固定电阻R_fixed的取值是关键。它的理想值应接近传感器阻值变化范围的中值。对于平直10kΩ,最大弯曲60kΩ的传感器,其中值约35kΩ。但常用标准电阻值中没有35kΩ,因此选择10kΩ是一个很好的折中方案。它能使输出电压在传感器整个阻值变化范围内都有显著的变化,提供较好的测量灵敏度。项目原文中提到的10kΩ电阻即用于此目的。
2.4 无线通信:HC-06蓝牙模块的连接
为了实现无线提醒,我们选用HC-06蓝牙串口模块。它价格低廉,易于使用,通过串口(UART)与Arduino通信,可以将数据无线传输到智能手机。
接线非常简单:
- VCC-> Arduino5V
- GND-> ArduinoGND
- TX-> ArduinoRX(数字引脚0)
- RX-> ArduinoTX(数字引脚1)
这里有一个非常重要的细节:HC-06的工作电压是3.3V,但其RX/TX引脚可以容忍5V电平。因此,我们可以直接将Arduino的5V-TX引脚连接到HC-06的RX。但是,为了更安全,或者在使用3.3V逻辑电平的微控制器(如ESP32)时,需要在Arduino的TX和HC-06的RX之间串联一个1kΩ左右的电阻,或者使用电平转换模块。
实操心得:初次上电时,HC-06的LED会快速闪烁,进入配对模式。默认配对码通常是“1234”或“0000”。务必先通过USB给Arduino供电并上传一个空程序(或后续的通信程序),让蓝牙模块进入正常工作状态,再用手机搜索配对。如果先接电池,模块可能无法被正确初始化。
2.5 供电方案:从原型到可穿戴
原型阶段,通过USB线供电是最方便的。但要实现可穿戴,必须考虑电池供电。
- 方案一(原文):使用带DC插头的电池盒(如4节AA电池或9V电池)接入Arduino的电源插座。这是最直接的方法,但电池盒体积大。
- 方案二(推荐):使用一块3.7V的锂聚合物电池(如常见的10440、14500电池或软包电池)配合一个微型5V升压模块,或者直接给Arduino Nano的VIN引脚供电(需在5-12V之间)。更优雅的方案是使用像Adafruit Feather或Seeed XIAO这样集成了充电管理芯片的开发板,搭配小容量锂电池,可以实现充电宝充电,体积小巧。
3. 软件实现:从数据读取到蓝牙通信
硬件连接好后,大脑(程序)的编写就至关重要了。代码需要完成三件事:稳定读取传感器数据、智能判断是否超过阈值、通过蓝牙发送通知。
3.1 Arduino程序框架与传感器数据读取
首先,我们需要编写Arduino端的程序。核心是利用analogRead()函数读取分压电路中间点的电压值。Arduino的ADC是10位精度,会将0-5V的电压映射为0-1023的整数。
// 定义引脚 const int flexSensorPin = A0; void setup() { Serial.begin(9600); // 初始化串口,用于调试和蓝牙通信 } void loop() { int sensorValue = analogRead(flexSensorPin); // 读取原始ADC值 Serial.println(sensorValue); // 打印到串口监视器,用于校准 delay(50); // 短暂延迟,避免数据刷太快 }上传这段代码后,打开Arduino IDE的串口监视器(波特率设为9600),弯曲传感器,你会看到数值在变化。平直时数值较高(例如~800),弯曲时数值降低(可能到~300)。这些原始数据是我们进行阈值判断的基础。
3.2 阈值校准算法的实现
直接使用原始ADC值进行判断可能受噪声干扰。常见的做法是进行滑动平均滤波。例如,我们取最近10次读数的平均值,这能有效平滑掉偶然的抖动。
const int numReadings = 10; int readings[numReadings]; int readIndex = 0; int total = 0; int average = 0; void setup() { // ... 其他初始化 for (int i = 0; i < numReadings; i++) { readings[i] = 0; } } void loop() { total = total - readings[readIndex]; // 减去最旧的读数 readings[readIndex] = analogRead(flexSensorPin); // 读取新值 total = total + readings[readIndex]; // 加上新值 readIndex = (readIndex + 1) % numReadings; // 循环索引 average = total / numReadings; // 计算平均值 // 判断逻辑将基于这个平滑后的 average 值 Serial.println(average); delay(50); }接下来是核心逻辑:判断抽动。我们需要设定一个阈值(threshold)。当平滑后的传感器数值低于这个阈值时(因为弯曲导致电压降低),认为发生了一次有效的弯曲(可能是抽动)。
int threshold = 500; // 这是一个示例阈值,需要根据校准确定 void loop() { // ... 计算平均值的代码 if (average < threshold) { // 检测到可能的一次抽动 Serial.println("Tic Detected!"); // 通过串口发送标识符 // 这里可以添加防抖逻辑,避免单次动作重复触发 delay(200); // 简单的防抖延时,200ms内不再检测 } }如何确定这个阈值?这就是校准过程。用户需佩戴好传感器,在串口监视器中观察。首先进行几次正常的放松状态下的微小动作,记录平均值(这代表了“基线”)。然后,主动模拟几次典型的抽动动作,记录这几次动作中传感器读数的平均值。阈值应设在这两个值之间,更靠近抽动值但略高一点,以确保能捕捉到抽动,同时尽量避免误报。例如,基线值约600,抽动值约350,那么阈值可以设为450-500。
3.3 蓝牙通信协议与手机端交互设计
当检测到抽动后,我们需要通过HC-06蓝牙模块通知手机。HC-06本质上是一个无线串口,Arduino通过Serial对象发送的数据,会原样传输到已配对的手机。
因此,代码非常简单,在检测到抽动后,向串口发送一个特定的字符串即可。
void loop() { // ... 计算平均值和阈值判断的代码 if (average < threshold) { Serial.println("TIC"); // 发送一个简单的识别码 // 或者可以发送传感器数值: Serial.println(average); delay(200); // 防抖延时 } }手机端需要一个配套的App来接收这个字符串。对于快速原型开发,我强烈推荐使用MIT App Inventor或Kodular这类图形化编程工具。它们不需要你精通Java或Kotlin,通过拖拽组件就能创建Android应用。
一个最简单的伴侣App应包含以下功能:
- 蓝牙连接组件:列出并连接HC-06模块。
- 蓝牙客户端组件:接收来自Arduino的数据。
- 逻辑判断:当接收到“TIC”字符串时,触发提醒。
- 提醒方式:可以是手机震动、发出提示音、或在屏幕上显示一条通知。为了兼顾隐私和及时性,震动是很好的选择。
在MIT App Inventor中,你可以设置当“蓝牙客户端.收到文本”时,如果收到的文本包含“TIC”,则执行“手机传感器.震动”(持续200毫秒)的操作。这样,一个完整的“检测-无线传输-提醒”闭环就实现了。
注意事项:蓝牙通信的稳定性是关键。在实际使用中,要确保手机和设备的距离在有效范围内(通常10米内无障碍物)。编写代码时,可以考虑加入连接状态检查和断线重连机制。在App端,可以设计一个简单的连接按钮和状态指示灯。
4. 设备组装、佩戴校准与优化
有了硬件和软件,接下来就是将它们可靠地整合在一起,并针对实际使用场景进行优化。
4.1 从面包板到稳定原型:焊接与封装
在开发阶段,面包板无可替代。但作为可穿戴设备,面包板的连接太容易松脱。焊接是必须的步骤。
- 准备焊接:将弯曲传感器的引线、10kΩ电阻、杜邦线(建议使用硅胶线,更柔软)预先上好锡。
- 搭建最小系统:你可以在一小块洞洞板(Perfboard)上焊接一个包含Arduino Nano(或Uno的缩小版)、分压电路(传感器和电阻)、以及HC-06模块插座的紧凑电路。务必参考电路图,并再三检查连接,特别是电源正负极不要接反。
- 电源管理:焊接一个JST-PH接口用于连接锂电池,或者一个微型开关用于控制电源。这能极大提升使用便利性和安全性。
封装外壳不仅能保护电路,还能让设备更易于佩戴和被人接受。3D打印是最佳选择。你可以在Thingiverse等网站搜索“Arduino Nano case”、“wearable sensor enclosure”等关键词,找到许多现成模型进行修改。设计外壳时需考虑:
- 为弯曲传感器留出柔软的走线通道。
- 为蓝牙模块的天线部分(通常是模块上没有元件的区域)留出空间,避免金属屏蔽信号。
- 设计合理的穿戴固定方式,如预留魔术贴绑带孔、别针扣等。
4.2 传感器佩戴与个性化校准实战
这是决定设备是否好用的关键一步。不同的身体部位和不同的抽动形式,需要不同的佩戴方案。
- 手腕/手指抽动:可以将传感器用弹性绷带或运动护腕固定在关节背面(弯曲侧)。确保传感器与皮肤或紧身衣物贴合,能跟随关节一起弯曲,但又不能过紧导致传感器被预弯曲。
- 颈部/头部抽动:这可能更具挑战性。可以考虑将传感器缝在衣领内侧,或者使用柔软的颈带固定。需要测试传感器是否能有效捕捉到头部扭动或耸肩的动作。
校准流程(务必让用户参与):
- 静态基线采集:让用户处于放松、无抽动的姿势,运行设备,在串口监视器中记录一段时间的稳定读数,取平均值作为“静态基线值”。
- 动态阈值测试:请用户主动做出几次典型的抽动动作。同时,助手(或用户自己用另一部手机看串口)记录下每次抽动发生时传感器读数的“谷值”(最小值)。
- 设定阈值:分析数据。阈值应设定在“静态基线值”和“抽动谷值”之间。一个保守的策略是:
阈值 = 静态基线值 - (静态基线值 - 平均抽动谷值) * 0.7。例如,基线600,平均谷值300,差值为300,乘以0.7是210,那么阈值可设为600-210=390。这个值比基线低,但比抽动谷值高,有一定的缓冲空间。 - 实地测试与微调:将阈值写入代码,让用户在日常生活中试用。观察两种错误:漏报(发生了抽动但没提醒)和误报(正常动作被误认为抽动)。根据反馈,逐步调整阈值,直到找到一个平衡点。可能需要为一天中的不同活动(如静坐、走路)设置不同的阈值,这可以通过在App端增加模式切换来实现。
4.3 功耗优化与续航提升技巧
如果使用电池供电,功耗直接决定了设备的续航和实用性。
- 降低系统时钟频率:对于ATmega328P芯片,可以通过修改熔丝位或使用库函数来降低主频(如从16MHz降到8MHz),能显著降低功耗。
- 使用睡眠模式:Arduino可以在检测间隙进入深度睡眠。例如,每100毫秒唤醒一次,读取传感器数据,判断后继续睡眠。这需要用到
<avr/sleep.h>库,并可能涉及外部中断唤醒,实现起来稍复杂,但节能效果极佳。 - 关闭无用模块:在代码中,可以控制蓝牙模块的开关。不需要连接时,将其断电。但HC-06模块重新配对需要时间,可能影响体验。可以考虑使用像HM-10(BLE 4.0)这样的低功耗蓝牙模块,其待机功耗远低于HC-06。
- 降低采样率:在不影响检测效果的前提下,增加
delay()时间或降低传感器读取频率。对于抽动检测,50-100ms的采样间隔通常足够,不必达到毫秒级。
5. 常见问题排查与进阶优化方向
即使按照步骤操作,你也可能会遇到一些问题。下面是一些常见故障及其解决方法。
5.1 硬件连接与电源问题排查表
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| Arduino不上电,指示灯不亮 | 1. 电源未接通或接触不良。 2. 电池电量耗尽或反接。 3. 电源线或插座损坏。 | 1. 检查所有电源连接点,重新插拔。 2. 用万用表测量电池电压,检查正负极。 3. 尝试更换USB线或电池盒。 |
| 弯曲传感器读数无变化 | 1. 传感器损坏(过度弯折导致内部断裂)。 2. 分压电路连接错误。 3. 模拟输入引脚错误或损坏。 | 1. 用万用表电阻档测量传感器两端电阻,弯曲时阻值应变大。 2. 对照电路图,检查传感器、电阻、杜邦线与Arduino的连接。 3. 换一个模拟引脚(如A1)测试代码。 |
| 蓝牙模块无法被手机搜索到 | 1. 模块未正确供电(VCC/GND接反或电压不足)。 2. 模块处于非配对模式。 3. 模块已与其他设备配对。 | 1. 检查模块指示灯:快闪(约每秒2次)为配对模式,慢闪(约每秒1次)为已连接。 2. 尝试给模块重新上电。 3. 在手机蓝牙设置中忘记已配对设备,重新搜索。 |
| 蓝牙连接后数据收发不稳定 | 1. 距离过远或有障碍物。 2. 手机端App权限未开启。 3. 串口波特率不匹配。 | 1. 确保设备在近距离(3-5米)无障碍环境下使用。 2. 检查手机是否授予App定位和蓝牙权限(Android新版本需要)。 3. 确认Arduino代码 Serial.begin()的波特率与手机App设置的一致(常用9600)。 |
| 设备误报率极高(正常动作也触发) | 1. 阈值设置过低。 2. 传感器佩戴过松,随身体晃动产生噪声。 3. 电源噪声干扰。 | 1. 重新进行校准,适当提高阈值。 2. 加固传感器佩戴,确保其与身体部位相对固定。 3. 在Arduino的5V和GND之间并联一个100uF的电解电容,稳定电源。 |
5.2 软件调试与数据逻辑纠错
- 串口监视器看不到数据:首先检查Arduino IDE中是否选择了正确的端口和板型。然后检查代码中
Serial.begin(9600)的波特率是否与监视器右下角的波特率设置一致。 - 数据跳动剧烈:这是模拟信号的典型噪声。除了前面提到的滑动平均滤波,还可以使用中值滤波(取一段时间内读数的中位数)或卡尔曼滤波(更复杂但效果更好)。Arduino有相关的滤波库可以简化操作。
- 检测延迟感明显:这可能是防抖延时 (
delay) 设置过长,或者滤波窗口 (numReadings) 过大导致的。在保证不误报的前提下,尽量减少这些值。也可以采用非阻塞式的定时器(如millis()函数)来替代delay(),让系统在等待期间也能处理其他任务。
5.3 项目扩展与个性化升级思路
这个基础版本有很大的扩展空间:
- 多传感器融合:可以连接多个弯曲传感器到Arduino的不同模拟引脚,同时监测多个部位(如左右手)。代码上需要为每个传感器独立设置数组、计算平均值和阈值。
- 数据记录与分析:在SD卡模块或通过蓝牙将传感器数据(而不仅仅是“TIC”事件)实时发送到手机App进行记录。长期的数据日志可以帮助用户和治疗师了解抽动的频率、强度与时间分布模式,评估干预效果。
- 自适应阈值:人体的状态和肌肉张力在一天中会有变化。可以编写算法让阈值能根据近期(如过去一分钟)的基线读数动态微调,提高设备在不同活动场景下的适应性。
- 多样化反馈:除了手机提醒,设备本身可以集成一个微型震动马达(如硬币马达)或LED灯,提供更直接、私密的触觉或视觉反馈。这对于不想依赖手机或需要在特定场合(如课堂)静音的场景非常有用。
- 升级主控平台:将Arduino更换为ESP32。ESP32集成了Wi-Fi和蓝牙,性能更强,功耗管理更好,可以直接连接物联网平台,实现远程数据查看或家人提醒功能。
在制作过程中,我最大的体会是,辅助技术的价值不仅在于技术本身,更在于对使用者需求的深度理解和共情。这个设备不是一个冰冷的诊断工具,而是一个温和的、可定制的伙伴。它的有效性很大程度上取决于校准过程是否充分、佩戴是否舒适、提醒方式是否恰当。因此,在整个开发过程中,与潜在用户的密切沟通和迭代测试至关重要。从原型到可用的产品,中间需要大量的打磨和优化,但看到它最终能为有需要的人提供一丝帮助,这一切努力都是值得的。