三轴加速度传感器在跌倒检测中的应用 前言 不仅是对老人,在很多其他情况下,跌倒的报警也是非常有帮助的,尤其是从比较高的地方跌倒下来的时候。比如人们在登山,建筑,擦窗户,刷油漆和修理屋顶的时候。 这促使人们越来越热衷于对跌倒检测以及跌倒预报仪器的研制。近年来,随着iMEMS®加速度传感器技术的发展,使得设计基于三轴加速度传感器的跌倒检测器成为可能。这种跌倒检测器的基本原理是通过测量佩戴该仪器的个体在运动过程中的三个正交方向的加速度变化来感知其身体姿态的变化,并通过算法分析判断该个体是否发生跌倒情况。当个体发生跌倒时,仪器能够配合GPS模块以及无线发送模块对这一情况进行定位及报警,以便获得相应的救助。而跌倒检测器的核心部分就是判断跌倒情况是否发生的检测原理及算法。 ADXL3451是ADI公司的一款3轴、数字输出的加速度传感器。本文将在研究跌倒检测原理的基础上,提出一种基于ADXL345的新型跌倒检测解决方案。 iMEMS加速度传感器ADXL345 ADXL345是ADI公司最近推出的基于iMEMS技术的3轴、数字输出加速度传感器。ADXL345具有+/-2g,+/-4g,+/-8g,+/-16g可变的测量范围;最高13bit分辨率;固定的4mg/LSB灵敏度;3mm*5mm*1mm超小封装;40-145uA超低功耗;标准的I2C或SPI数字接口;32级FIFO存储;以及内部多种运动状态检测和灵活的中断方式等特性。所有这些特性,使得ADXL345有助于大大简化跌倒检测算法,使其成为一款非常适合用于跌倒检测器应用的加速度传感器。 本文给出的跌倒检测解决方案,完全基于ADXL345内部的运动状态检测功能和中断功能,甚至不需要对加速度的具体数值进行实时读取和复杂的计算操作,可以使算法的复杂度降至最低。 中断系统
图1 ADXL345系统框图及管脚定义 ADXL345具有两个可编程的中断管脚:Int1和Int2。以及Data_Ready、Single_Tap、Double_Tap、Activity、Inactivity、Free_Fall、Watermark、Overrun,共计8个中断源。每个中断源可以独立地使能或禁用,还可以灵活地选择是否映射到Int1或Int2中断管脚。所有的功能都可以同时使用,只是某些功能可能需要共用中断管脚。中断功能通过INT_ENABLE寄存器的相应位来选择使能或禁用,通过INT_MAP寄存器的相应位来选择映射到Int1管脚或Int2管脚。中断功能的具体定义如下:
图2给出了有效的Single_Tap中断和Double _Tap中断的示意图。
图2 Single_Tap和Double _Tap中断示意
跌倒过程中的加速度变化特征 图3给出的是加速度在不同运动过程中的变化曲线,包括(a)步行上楼、(b)步行下楼、(c)坐下、(d)起立。假设跌倒检测器被固定在被测的人体上。其中红色的曲线是Y轴(垂直方向)的加速度曲线,其正常静止状态下应该为-1g;黑色和黄色的曲线分别是X轴(前后方向)和Z轴(左右方向)的加速度曲线,其正常静止状态下应该为0g;绿色的曲线是三轴加速度的矢量和,其正常静止状态下应该为+1g。
a. 步行上楼 b. 步行下楼
c. 坐下 d. 起立 图3 不同运动过程中的加速度变化曲线 由于老年人的运动相对比较慢,所以在普通的步行过程中,加速度变化不会很大。最明显的加速度变化就是在坐下动作中Y轴加速度(和加速度矢量和)上有一个超过3g的尖峰,这个尖峰是由于身体与椅子接触而产生的。 而跌倒过程中的加速度变化则完全不同。图4给出的是意外跌倒过程中的加速度变化曲线。通过图4和图3的比较,可以发现跌倒过程中的加速度变化有4个主要特征,这可以作为跌倒检测的准则。这4个特这在图4中以红色的方框标注,下面将对其逐一进行详细介绍。
图4 跌倒过程中的加速度变化曲线
这四个判断依据综合在一起,构成了整个的跌倒检测算法,可以对跌倒状态给出报警。当然,还要注意各个中断之间的时间间隔要在合理的范围之内。比如,除非是从很高的楼顶掉下来,否则Free_Fall中断(失重)和Activity中断(撞击)之间的时间间隔不会很长。同样,通常情况下, Activity中断(撞击)和Inactivity中断(静止)之间的时间间隔也不会很长。本文接下来会通过一个具体实例给出一组合理的取值。当然,相关中断的检测门限以及时间参数也可以根据需要而灵活设置。 另外,如果跌倒造成了严重的后果,比如,导致了人的昏迷。那么人体会在更常的一段时间内都保持静止。这个状态仍然可以通过Inactivity中断来检测。也就是说,如果发现在跌倒之后的很长时间内都保持Inactivity状态,可以再次给出一个严重报警。 典型电路连接 其他的单片机或者处理器都可以采用与图5类似的电路与ADXL345进行连接。ADXL345还可以工作在SPI模式以获得更高的数据传输速率。关于SPI工作模式的具体描述,请参考ADXL345数据手册。
图5 ADXL345与微控制器之间的典型电路连接 表1 ADXL345寄存器功能说明
利用ADXL345简化跌倒检测算法 需要指出的是,表1给出的设置值中,某些寄存器会给出两个数值,这说明在算法中会切换使用这两个数值,来达到不同的检测目的。 算法的流程图如图6所示。
图6 算法流程图 算法中,关于各种中断的门限以及时间参数的设置如下所述。
本算法已在ADuC7026微控制器中以C语言实现(见附录)。本文设计了一个实验方案对算法进行验证。实验对向前跌倒,向后跌倒,向左、右两侧跌倒等不同跌倒姿势以及跌倒后是否有长时间静止状态的情况分别进行了10次测试,表2中给出的是相关测试结果。 表2 测试结果
从这个实验中可以看出基于ADXL345的解决方案能够有效地对跌倒状态进行检测。当然,这里只是一个简单的实验方案,仍需要进行更加全面、有效和长期的实验来验证该解决方案的可靠性。 结论 附录 // Include header files #include "FallDetection.h" void IRQ_Handler() __irq // IRQ interrupt { unsigned char i; if((IRQSTA & GP_TIMER_BIT)==GP_TIMER_BIT) //TIMER1 Interrupt, interval 20ms { T1CLRI = 0; // Clear Timer1 interrupt if(DetectionStatus==0xF2) // Strike after weightlessness is detected, waiting for stable { TimerWaitForStable++; if(TimerWaitForStable>=STABLE_WINDOW) // Time out, restart { IRQCLR = GP_TIMER_BIT; // Disable ADuC7026's Timer1 interrupt DetectionStatus=0xF0; putchar(DetectionStatus); ADXL345Registers[XL345_THRESH_ACT]=STRIKE_THRESHOLD; ADXL345Registers[XL345_THRESH_INACT]=NOMOVEMENT_THRESHOLD; ADXL345Registers[XL345_TIME_INACT]=STABLE_TIME; ADXL345Registers[XL345_ACT_INACT_CTL]=XL345_INACT_Z_ENABLE | XL345_INACT_Y_ENABLE | XL345_INACT_X_ENABLE | XL345_INACT_AC | XL345_ACT_Z_ENABLE | XL345_ACT_Y_ENABLE | XL345_ACT_X_ENABLE | XL345_ACT_DC; xl345Write(4, XL345_THRESH_ACT, &ADXL345Registers[XL345_THRESH_ACT]); } } else if(DetectionStatus==0xF1) // Weightlessness is detected, waiting for strike { TimerWaitForStrike++; if(TimerWaitForStrike>=STRIKE_WINDOW) // Time out, restart { IRQCLR = GP_TIMER_BIT; // Disable ADuC7026's Timer1 interrupt DetectionStatus=0xF0; putchar(DetectionStatus); ADXL345Registers[XL345_THRESH_ACT]=STRIKE_THRESHOLD; ADXL345Registers[XL345_THRESH_INACT]=NOMOVEMENT_THRESHOLD; ADXL345Registers[XL345_TIME_INACT]=STABLE_TIME; ADXL345Registers[XL345_ACT_INACT_CTL]=XL345_INACT_Z_ENABLE | XL345_INACT_Y_ENABLE | XL345_INACT_X_ENABLE | XL345_INACT_AC | XL345_ACT_Z_ENABLE | XL345_ACT_Y_ENABLE | XL345_ACT_X_ENABLE | XL345_ACT_DC; xl345Write(4, XL345_THRESH_ACT, &ADXL345Registers[XL345_THRESH_ACT]); } } } if((IRQSTA&SPM4_IO_BIT)==SPM4_IO_BIT) // External interrupt form ADXL345 INT0 { IRQCLR = SPM4_IO_BIT; // Disable ADuC7026's external interrupt xl345Read(1, XL345_INT_SOURCE, &ADXL345Registers[XL345_INT_SOURCE]); if((ADXL345Registers[XL345_INT_SOURCE]&XL345_ACTIVITY)==XL345_ACTIVITY) // Activity interrupt asserted { if(DetectionStatus==0xF1) // Waiting for strike, and now strike is detected { DetectionStatus=0xF2; // Go to Status "F2" putchar(DetectionStatus); ADXL345Registers[XL345_THRESH_ACT]=STABLE_THRESHOLD; ADXL345Registers[XL345_THRESH_INACT]=NOMOVEMENT_THRESHOLD; ADXL345Registers[XL345_TIME_INACT =STABLE_TIME; ADXL345Registers[XL345_ACT_INACT_CTL]=XL345_INACT_Z_ENABLE | XL345_INACT_Y_ENABLE | XL345_INACT_X_ENABLE | XL345_INACT_AC | XL345_ACT_Z_ENABLE | XL345_ACT_Y_ENABLE | XL345_ACT_X_ENABLE | XL345_ACT_AC; xl345Write(4, XL345_THRESH_ACT, &ADXL345Registers[XL345_THRESH_ACT]); IRQEN|=GP_TIMER_BIT; // Enable ADuC7026's Timer1 interrupt TimerWaitForStable=0; } else if(DetectionStatus==0xF4) // Waiting for long time motionless, but a movement is detected { DetectionStatus=0xF0; // Go to Status "F0", restart putchar(DetectionStatus); ADXL345Registers[XL345_THRESH_ACT]=STRIKE_THRESHOLD; ADXL345Registers[XL345_THRESH_INACT]=NOMOVEMENT_THRESHOLD; ADXL345Registers[XL345_TIME_INACT]=STABLE_TIME; ADXL345Registers[XL345_ACT_INACT_CTL]=XL345_INACT_Z_ENABLE | XL345_INACT_Y_ENABLE | XL345_INACT_X_ENABLE | XL345_INACT_AC | XL345_ACT_Z_ENABLE | XL345_ACT_Y_ENABLE | XL345_ACT_X_ENABLE | XL345_ACT_DC; xl345Write(4, XL345_THRESH_ACT, &ADXL345Registers[XL345_THRESH_ACT]); } } else if((ADXL345Registers[XL345_INT_SOURCE]&XL345_INACTIVITY)==XL345_INACTIVITY) // Inactivity interrupt asserted { if(DetectionStatus==0xF2) // Waiting for stable, and now stable is detected { DetectionStatus=0xF3; // Go to Status "F3" IRQCLR = GP_TIMER_BIT; putchar(DetectionStatus); xl345Read(6, XL345_DATAX0, &ADXL345Registers[XL345_DATAX0]); DeltaVectorSum=0; for(i=0;i<3; i++) { Acceleration[i]=ADXL345Registers[XL345_DATAX1+i*2]&0x1F; Acceleration[i]=(Acceleration[i]<<8)|ADXL345Registers[XL345_DATAX0+i*2]; if(Acceleration[i]<0x1000) { Acceleration[i]=Acceleration[i]+0x1000; } else //if(Acceleration[i]>=4096) { Acceleration[i]=Acceleration[i]-0x1000; } if(Acceleration[i]>InitialStatus[i]) { DeltaAcceleration[i]=Acceleration[i]-InitialStatus[i]; } else { DeltaAcceleration[i]=InitialStatus[i]-Acceleration[i]; } DeltaVectorSum=DeltaVectorSum+DeltaAcceleration[i]*DeltaAcceleration[i]; } if(DeltaVectorSum>DELTA_VECTOR_SUM_THRESHOLD // The stable status is different from the initial status { DetectionStatus=0xF4; // Valid fall detection putchar(DetectionStatus); ADXL345Registers[XL345_THRESH_ACT]=STABLE_THRESHOLD; ADXL345Registers[XL345_THRESH_INACT]=NOMOVEMENT_THRESHOLD; ADXL345Registers[XL345_TIME_INACT]=NOMOVEMENT_TIME; ADXL345Registers[XL345_ACT_INACT_CTL]=XL345_INACT_Z_ENABLE | XL345_INACT_Y_ENABLE | XL345_INACT_X_ENABLE | XL345_INACT_AC | XL345_ACT_Z_ENABLE | XL345_ACT_Y_ENABLE | XL345_ACT_X_ENABLE | XL345_ACT_AC; xl345Write(4, XL345_THRESH_ACT, &ADXL345Registers[XL345_THRESH_ACT]); } else // Delta vector sum is not exceed the threshold { DetectionStatus=0xF0; // Go to Status "F0", restart putchar(DetectionStatus); ADXL345Registers[XL345_THRESH_ACT]=STRIKE_THRESHOLD; ADXL345Registers[XL345_THRESH_INACT]=NOMOVEMENT_THRESHOLD; ADXL345Registers[XL345_TIME_INACT]=STABLE_TIME; ADXL345Registers[XL345_ACT_INACT_CTL]=XL345_INACT_Z_ENABLE | XL345_INACT_Y_ENABLE | XL345_INACT_X_ENABLE | XL345_INACT_AC | XL345_ACT_Z_ENABLE | XL345_ACT_Y_ENABLE | XL345_ACT_X_ENABLE | XL345_ACT_DC; xl345Write(4, XL345_THRESH_ACT, &ADXL345Registers[XL345_THRESH_ACT]); } } else if(DetectionStatus==0xF4) // Wait for long time motionless and now it is detected { DetectionStatus=0xF5; // Valid critical fall detection putchar(DetectionStatus); ADXL345Registers[XL345_THRESH_ACT]=STRIKE_THRESHOLD; ADXL345Registers[XL345_THRESH_INACT]=NOMOVEMENT_THRESHOLD; ADXL345Registers[XL345_TIME_INACT]=STABLE_TIME; ADXL345Registers[XL345_ACT_INACT_CTL]=XL345_INACT_Z_ENABLE | XL345_INACT_Y_ENABLE | XL345_INACT_X_ENABLE | XL345_INACT_AC | XL345_ACT_Z_ENABLE | XL345_ACT_Y_ENABLE | XL345_ACT_X_ENABLE | XL345_ACT_DC; xl345Write(4, XL345_THRESH_ACT, &ADXL345Registers[XL345_THRESH_ACT]); DetectionStatus=0xF0; // Go to Status "F0", restart putchar(DetectionStatus); } } else if((ADXL345Registers[XL345_INT_SOURCE]&XL345_FREEFALL)==XL345_FREEFALL) // Free Fall interrupt asserted { if(DetectionStatus==0xF0) // Waiting for weightless, and now it is detected { DetectionStatus=0xF1; // Go to Status "F1" putchar(DetectionStatus); ADXL345Registers[XL345_THRESH_ACT]=STRIKE_THRESHOLD; ADXL345Registers[XL345_THRESH_INACT]=NOMOVEMENT_THRESHOLD; ADXL345Registers[XL345_TIME_INACT]=STABLE_TIME; ADXL345Registers[XL345_ACT_INACT_CTL]=XL345_INACT_Z_ENABLE | XL345_INACT_Y_ENABLE | XL345_INACT_X_ENABLE | XL345_INACT_AC | XL345_ACT_Z_ENABLE | XL345_ACT_Y_ENABLE | XL345_ACT_X_ENABLE | XL345_ACT_DC; xl345Write(4, XL345_THRESH_ACT, &ADXL345Registers[XL345_THRESH_ACT]); IRQEN|=GP_TIMER_BIT; // Enable ADuC7026's Timer1 interrupt TimerWaitForStrike=0; TimerFreeFall=0; } else if(DetectionStatus==0xF1) // Waiting for strike after weightless, and now a new free fall is detected { if(TimerWaitForStrike<FREE_FALL_INTERVAL) // if the Free Fall interrupt is continuously assert within the time of "FREE_FALL_INTERVAL", { // then it is consider as a continuous free fall TimerFreeFall=TimerFreeFall+TimerWaitForStrike; } else // Not a continuous free fall { TimerFreeFall=0; } TimerWaitForStrike=0; if(TimerFreeFall>=FREE_FALL_OVERTIME) // if the continuous time of free fall is longer than "FREE_FALL_OVERTIME" { // consider that a free fall from high place is detected DetectionStatus=0xFF; putchar(DetectionStatus); ADXL345Registers[XL345_THRESH_ACT =STRIKE_THRESHOLD; ADXL345Registers[XL345_THRESH_INACT]=NOMOVEMENT_THRESHOLD; ADXL345Registers[XL345_TIME_INACT]=STABLE_TIME; ADXL345Registers[XL345_ACT_INACT_CTL]=XL345_INACT_Z_ENABLE | XL345_INACT_Y_ENABLE | XL345_INACT_X_ENABLE | XL345_INACT_AC | XL345_ACT_Z_ENABLE | XL345_ACT_Y_ENABLE | XL345_ACT_X_ENABLE | XL345_ACT_DC; xl345Write(4, XL345_THRESH_ACT, &ADXL345Registers[XL345_THRESH_ACT]); DetectionStatus=0xF0; putchar(DetectionStatus); } } else { TimerFreeFall=0; } } IRQEN |=SPM4_IO_BIT; // Enable ADuC7026's external interrupt } } void main(void) { ADuC7026_Initiate(); // ADuC7026 initialization ADXL345_Initiate(); // ADXL345 initialization DetectionStatus=0xF0; // Clear detection status, Start InitialStatus[0]=0x1000; // X axis=0g, unsigned short int, 13 bit resolution, 0x1000 = 4096 = 0g, +/-0xFF = +/-256 = +/-1g InitialStatus[1]=0x0F00; // Y axis=-1g InitialStatus[2]=0x1000; // Z axis=0g IRQEN =SPM4_IO_BIT; // Enable ADuC7026's external interrupt, to receive the interrupt from ADXL345 INT0 while(1) // Endless loop, wait for interrupts { ; } } 参考资料 2ADuC7026数据手册(www.analog.com,搜索ADuC7026)
Copyright 1995-
Analog
Devices, Inc. All rights reserved. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||