1.介绍
活动状态有很多种,主要有站立、坐、走路、浅睡、深睡、跑步、未佩戴,当然这里的每一个状态的识别都是需要有算法的,对原始数据进行分析,然后去编写算法,当然还有机器学习,刚开始算法根据人的身高和体重(用户自行输入),进行算法匹配,而后面通过采集该用户的各种状态的数据并分析,给出最合适的算法,同时还可以像另一个选手的作品【跑步姿势训练鞋】识别用户走路的姿态,给用户建议,不过这个有一定的难度,这次作品就不做了。
2.状态识别
这次作品主要识别三种姿态,未活动,走路和工作。【未活动】是这个是最好检测,的只要检测三轴的方向是否长时间未改变,那么就可以知道佩戴者处于未活动。如果要识别是睡眠还是未活动,这个需要有进一步的算法,暂时略过。
走路的话,其实也是比较好识别的,人在走路过程中,手是晃动的,那么三轴的方向是变化的,就如同下图1一样,戴着【RSL10-SENSE-GEVK】设备时走出分骚的步伐时的三轴角度变化。
图1
加速度驱动就不过多的分析了,拿到三轴的方向数据之后,模拟走路输出的波形如下图2所示。
图2
其中蓝色是X轴,红色是Y轴,绿色是Z轴。可以看到红色数据变化最大。
那么正常走路的情况下分析X轴就可以了,其中一个波峰或一个波谷就是一步,那么就可以通过这个特性编写计步检测算法,为了预防晃动导致的计步,会有一个前十步的统计,当走了十步之后才会真正开始计步,当然也会加上这十步,如果一次走路未满十步,则会被判断为晃动,具体的实现的代码如下:
int16_t last_y_org = 0;
int16_t last_y_peak = 0;
uint8_t walk_status = 0; //0未走路,1走路中
uint32_t step_cnt = 0; //当前步数
uint8_t step_after = 0; //前十步统计
uint8_t stap_dif_cnt = 0; //数值不同
//检测走路
uint8_t activity_walk_detect(int16_t y_org)
{
if(last_y_org == y_org)
{
stap_dif_cnt++; //数值一直相同
if(stap_dif_cnt >= 10)
{
stap_dif_cnt = 0;
walk_status = 0;//当前未走路
step_after = 0; //前十步清零
}
return walk_status;
}
last_y_org = y_org;
if(last_y_peak > 0) //峰值大于0
{
if(last_y_org < 0) //小于0
{
if(walk_status == 0)
{
step_after++;
if(step_after >= 10)
{
step_after = 0;
step_cnt += 10;
walk_status = 1;
}
}
else
{
step_cnt++;//步数+1
}
stap_dif_cnt = 0;
}
else
{
stap_dif_cnt++; //数值一直相同
if(stap_dif_cnt >= 10)
{
stap_dif_cnt = 0;
walk_status = 0;//当前未走路
step_after = 0; //前十步清零
}
}
}
else
{
if(last_y_org > 0) //小于0
{
if(walk_status == 0)
{
step_after++;
if(step_after >= 10)
{
step_after = 0;
step_cnt += 10;
walk_status = 1;
}
}
else
{
step_cnt++;//步数+1
}
stap_dif_cnt = 0;
}
else
{
stap_dif_cnt++; //数值一直相同
if(stap_dif_cnt >= 10)
{
stap_dif_cnt = 0;
walk_status = 0;//当前未走路
step_after = 0; //前十步清零
}
}
}
last_y_peak = last_y_org;
return walk_status;
}
通过上面的算法,对应着刚才的波形数据,实际得出的步数波形如下图3所示:
图3
其中蓝色为前十步统计,红色为实际步数,绿色为计步状态,可以看到十步之后,实际步数开始直接加上10步,然后就在稳步增长,可以对比图2和图3查看。
接下来就是工作状态了,由于只有三个状态,所以除了未活动和走路就是工作状态了,这里写的比较简单,当不是走路时且三轴方向有变化,就被当作为工作状态,具体代码如下:
//检测工作
int16_t global_x_org = 0;
int16_t global_y_org = 0;
int16_t global_z_org = 0;
uint8_t no_work_cnt = 10;
//检测工作,只要动就是工作
uint8_t activity_work_detect(int16_t x_org, int16_t y_org, int16_t z_org)
{
if(abs(global_x_org - x_org) > 100 || abs(global_y_org - y_org) > 100 || abs(global_z_org - z_org) > 100)
{
global_x_org = x_org;
global_y_org = y_org;
global_z_org = z_org;
no_work_cnt = 10;
return 1;
}
else
{
if(no_work_cnt > 0)
no_work_cnt--;
if(no_work_cnt == 0)
return 0;
}
return 1;
}
最后就是这代码的整合,然后通过广播发送给矿井外设备了,整合的代码如下:
//传入数据
void activity_update_data(bhy_data_vector_t act_data)
{
uint8_t ret_value = 0;
ret_value = activity_walk_detect(act_data.y);
printf("walk:%d,%d,%d\n", step_after, step_cnt, ret_value);
if(ret_value > 0) //在走路中,不检测是否在工作
{
now_status = WALK;
return;
}
ret_value = activity_work_detect(act_data.x, act_data.y, act_data.z);
printf("work:%d,%d\n", no_work_cnt, ret_value);
if(ret_value > 0)
{
now_status = WORK;
return;
}
else
{
now_status = NO_ACTIVITY;
}
}
//获取当前状态
ACTIVITY_STATUS activity_get_status(void)
{
return now_status;
}
3.总结
活动状态检测其实还有很多状态要识别的,由于时间问题暂时就写了这三个状态,能够简单的识别走路,工作和未活动对于这个作品来说够用了,下一篇写状态灯和模式相关的内容。
本帖最后由 w494143467 于 2021-6-27 13:23 编辑引用: sipower 发表于 2021-6-23 16:21 厉害 那个动画的走姿太骚包啦,哈哈哈
哈哈,突然想到的,娱乐一下哈。