背景
我们有注意到,meta最新的ai眼镜,上了心肌电手环,可以通过食指和拇指间的运动来实现界面的操作。刚好有朋友也在找带上手环就能操作的方案,就想看看心肌电能不能做到。
继上篇的进展
上篇链接:【肌电传感器(OYMotion)试用】---心肌电传感器初步使用-电子产品世界论坛
初步使用时,感觉纯幅度看数据没啥特别的规律,遂考虑转化成频域去看,但是转化到频域去看时,又发现如果不结合幅度看,频域数据很不准(因为噪声大,不操作时频率乱跳,操作时也没发现明显的频率变化差异),因此又做了个类似于vad检测的效果,在增加这种检测地过程中,发现在幅度域其实是能找到一些规律的。
目前找到的规律如下:
仅从幅度看,心机电检测的信号,其实与手指的肌肉收缩程度强相关(也可以认为是手指的用力程度相关)。
基于此规律,我们仅需要对滤波后的数据进行平滑处理,找到手指不同操作方式的心机电对应的平滑后的值范围,便可初步地实现手指不同操作执行不同功能的效果(meta的效果),虽然还是会有小小的误判或者漏判。
具体代码
数据平滑部分
const uint16_t samples = 256;
double temp_data[samples];
double average_level(void)
{
int i = 0;
double average = 0;
while(i < samples)
{
average += temp_data[i];
i++;
}
return average / samples;
}
double get_avarage_level(int gforce_envelope)
{
static int current_index = 0;
temp_data[current_index] = gforce_envelope;
current_index++;
current_index = current_index % samples;
return average_level();
}这部分代码其实就是实现了个滑动窗平滑滤波器。
主loop函数
void loop()
{
int data = analogRead(SensorInputPin);
int dataAfterFilter = myFilter.update(data); // filter processing
int envelope = sq(dataAfterFilter); //Get envelope by squaring the input
static int nCount = 0;
static double level = 0;
static double level_max = 0;
level = get_avarage_level(envelope);
if(level < 1)
{
nCount++;
if(nCount > samples)
{
if(level_max > 0)
{
//Serial.println(level_max,2);
if((level_max > 10) && (level_max < 100))
{
Serial.println("Front");
}
else if((level_max > 1) && (level_max <= 10))
{
Serial.println("Left/Right");
}
level_max = 0;
}
}
}
else
{
if(level_max < level)
{
level_max = level;
}
nCount = 0;
}
delayMicroseconds(500);
}这里面主要是涉及到三个等级,1, 10,100,之所以选取这几个值,主要是因为手指不操作的情况下,心肌电读到的平滑后的数据值大致是1以下,也就是说,如果平滑后的数据是在0.7以下,就可以认为是未操作。而食指左右滑动时读到的值在1至10之间,因此在这个范围内,认为是手指左右滑动。而拇指前后滑动的变化值大致在10至100之间,在此范围内,可认为是拇指前后滑动。至于大于100的值过滤掉,纯粹是为了降低异常操作误判的概率(比如握拳等操作)。
实现效果

可以看到,基本上能够识别食指左右滑动和拇指前后滑动,能勉强实现meta手环的效果。但也可以看出,效果并不算好,还得继续找合适的方法进行优化。
我要赚赏金
