arduino r4 wifi
dfrobot sen0240心肌电传感器
资料准备
通过查询资料,发现心肌电传感器母版上传出的数据线为模拟信号,供电可以使用3.3V~5V 直流供电,因此设计就简单了,直接在arduino板卡上选择一个模拟口便可。
出于接线便捷性的考虑,我选择了跟地和供电最接近的A0口,以方便调试。
软件安装
直接去arduino上下载arduino IDE的安装文件,下载位置如下:DOWNLOAD
下载好后点击安装,安装好后启动软件,设置好库的存储位置

库安装
设置好库的存储位置后,需要去github上下载到心肌电传感器所需的滤波器实现库,库的链接如下:EMG_Filter
下载好后,将库文件解压至arduino设置好后的路径下,具体存储方法如下:

校准软件编写
#if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" #else #include "WProgram.h" #endif #include "EMGFilters.h" #define SensorInputPin A0 //输入脚 EMGFilters myFilter; SAMPLE_FREQUENCY sampleRate = SAMPLE_FREQ_500HZ; NOTCH_FREQUENCY humFreq = NOTCH_FREQ_50HZ; void setup() { myFilter.init(sampleRate, humFreq, true, true, true); Serial.begin(115200); } void loop() { int data = analogRead(SensorInputPin); int dataAfterFilter = myFilter.update(data); // 库中提供的滤波处理 int envelope = sq(dataAfterFilter); //对滤波后的信号作平方处理,用于对幅度进行增强 Serial.println(envelope); delayMicroseconds(500); // 500us后再去读取下一次,也就是说,采样率在2K }
由于每个人的心肌电都不一样,而且即使是同一个人,也没法保证每次佩戴都是同一位置,此时需要在佩戴后重新做一次校准,或许后面看频域数据后,可能不需要再去做校准了,毕竟看的不是幅度,而是每个操作时的频谱变化趋势,有可能不同的动作,所获得的频谱图是相对固定的(频域幅度可能会有变化,但各频率之间比例变化不大)。
获取标定数据
软件编写好后,烧录至arduino r4 wifi板卡上,再佩戴好心肌电传感器,看打印数据,当人不动时,打印数据在100以内,说明心肌电传感器已经佩戴好,若超过这个值,说明没贴对位置。
确认佩戴好后,反复握拳,看能拿到的最大值,由于打印太多,因此我仅关注了最高位,最高位的值为7,因为是三位数,因此我就直接当作700来选取。
效果测试软件编写
#if defined(ARDUINO) && ARDUINO >= 100 #include "Arduino.h" #else #include "WProgram.h" #endif #include "EMGFilters.h" #define SensorInputPin A0 //输入脚 unsigned long threshold = 700; // 我这次实验佩戴时,检测到最大的值为700左右 unsigned long EMG_num = 0; // 触发次数 EMGFilters myFilter; SAMPLE_FREQUENCY sampleRate = SAMPLE_FREQ_500HZ; NOTCH_FREQUENCY humFreq = NOTCH_FREQ_50HZ; void setup() { myFilter.init(sampleRate, humFreq, true, true, true); Serial.begin(115200); } void loop() { int data = analogRead(SensorInputPin); int dataAfterFilter = myFilter.update(data); // 库中提供的滤波处理 int envelope = sq(dataAfterFilter); //对滤波后的信号作平方处理,用于对幅度进行增强 envelope = (envelope > threshold) ? envelope : 0; // 如果幅度超过了一定值,则认为是有动作 if (getEMGCount(envelope)) { EMG_num++; Serial.print("EMG_num: "); Serial.println(EMG_num); } delayMicroseconds(500); // 500us后再去读取下一次,也就是说,采样率在2K } // 如果信号持续200ms超过了门限值,则认为运动了一次 int getEMGCount(int gforce_envelope) { static long integralData = 0; static long integralDataEve = 0; static bool remainFlag = false; static unsigned long timeMillis = 0; static unsigned long timeBeginzero = 0; static long fistNum = 0; static int TimeStandard = 200; integralDataEve = integralData; integralData += gforce_envelope; if ((integralDataEve == integralData) && (integralDataEve != 0)) { timeMillis = millis(); if (remainFlag) { timeBeginzero = timeMillis; remainFlag = false; return 0; } if ((timeMillis - timeBeginzero) > TimeStandard) { integralDataEve = integralData = 0; return 1; } return 0; } else { remainFlag = true; return 0; } }
实验结果
由于仅仅是对数据进行了幅度上的拉大处理,未对数据进行更加复杂的运算,如采集后使用短时傅里叶去看频谱,看看不同操作时的频率信息等,导致不少动作都能触发判定为操作了,在我此次实验中,就遇到了两种操作会触发操作了,一个是手握拳,另一个是大拇指和食指之间的滑动操作。
EMG_num: 1 EMG_num: 2 EMG_num: 3 EMG_num: 4 EMG_num: 5 EMG_num: 6 EMG_num: 7 EMG_num: 8 EMG_num: 9 EMG_num: 10 EMG_num: 11 EMG_num: 12
下一步计划
既然按照官方的demo并不能很好的区分手部操作,那就尝试换一些方法看看,计划看看快速傅里叶变化后能不能明显区分不同动作。
我要赚赏金
