电子说
步骤1:所需部件
Arduino Mega
0.96英寸I2C OLED显示屏
MPU -6050加速度计陀螺仪组合
HC-05蓝牙模块
FTDI编程器
Perfboard
推送按钮* 2
电池
以及其他一些常见的电子元件和工具,如烙铁,USB电缆等。..。..
《请使用上述会员链接购买上述任何组件,这将有助于项目的未来存在。
步骤2:配置HC-05蓝牙模块为HID(人机接口设备)设备
是项目,我们需要向PC发送命令来更改幻灯片,因为我们不希望任何接收器插入PC的USB端口,我们可以进一步使用蓝牙。
默认情况下,最常见的蓝牙模块HC-05中的固件只能作为从属设备使用。
我们需要兼容蓝牙的HID(人机接口设备)模块配置为无线蓝牙键盘,用于向PC发送命令以更改幻灯片。
我们有两个HID设备选项,一个是直接购买这样的兼容HID的蓝牙模块RN-42,其费用是普通蓝牙模块的10倍或者将RN-42的固件刷到HC- 05,两个模块都基于类似的硬件。
我已经学会了从Brian Lough和Evan Kale那里更改HC-05的固件,他们在解释如何更换固件方面做得非常出色,再次在这里复制它是没有意义的,所以我想留下他们的视频链接,并给你我的固件文件。
步骤3:构建硬件
既然你有一个兼容HID的蓝牙模块,你可以开始构建硬件。
从这里下载Fritzing电路原理图文件。
我建议在一块穿孔板上构建所有硬件并将其作为Arduino mega的屏蔽。
步骤4:构建软件
这是项目中最重要的部分,即代码。
在实际打开我的代码之前,我想推荐一下如果您使用的是Arduino IDE,则转到首选项并启用“代码折叠”,现在您可以折叠代码的各个部分以清楚地了解代码。
您可以从以下位置找到最新的代码我的Github页面。
代码中有很多部分,让我单独解释每个部分。
如果您有任何疑问,请将其评论下来,我将很乐意为您提供帮助。
步骤5:记录手势
识别手势过程的第一步是记录手势,并记录手势,我们正在使用加速度计读数来自MPU-6050。
我为录制手势创建的函数是take_reading(),在代码中引用它。
为了清楚手势,样本大小需要很大,并且为了加快处理速度,手势大小需要很小,我发现50适合这两种情况。现在,如果我们想要记录更长的手势,我们可以平均每2或3个元素来获得50个元素的手势。
#define DOF 3 //3-degrees of freedom acc_x, acc-y, acc_z
#define avg_lenght 2 //average out every 2 elements of reading
#define sample_size 50
int reading[DOF][avg_lenght*sample_size]; //creating a 2-D array to store readings
//taking readings
for(i=0; i{
MPU6050.update();
reading[0][i] = mpu6050.getAccX(); //taking readings of acceleration in g‘s, 1g, 1.2g
reading[0][i] = reading[0][i]*50 + 50; //ofsetting the value to 50
if(reading[0][i]《0) //limiting its value from 0 to 100
reading[0][i]=0;
else if(reading[0][i]》100)
reading[0][i]=100;
//repeating the same for remaining 2 degrees of freedom, acc_y, acc_z
}
我们已经读取了读数,但这些不是sample_size元素,这些是sample_size * avg_lenght元素,我们需要sample_size元素,所以我们需要将它平均化。
if(avg_lenght》1) //if we need to average
{
for(i=0; i {
for(j=0; j {
for(k=0; k {
sum=sum+reading[i][avg_lenght*j+k]; //add every avg_lenght elemens
}
temp_values[i][j]=sum/avg_lenhgt; //save avg of avg_lenght elements here
sum=0;
}
}
}
else if(avg-lenght==1) //no need to average
{
for(i=0; i {
for(j=0; j temp_values[i][j]=reading[i][j]; //simply copying values to temp_values
}
}
现在读取所有DOF的读数并保存到temp_values数组。
步骤6:将记录的手势保存为主手势
既然我们知道如何记录手势,我们需要一种方法将其保存为主手势所以我们可以稍后比较一个手势。
我创建的用于将手势复制到主手势数组的函数是copy_reading(from,to master,master _select),请参阅代码。
for(i=0; i{
for(j=0; j {
master[master_select][i][j] = temp_values[i][j];
}
}
现在,我们可以录制手势,将其保存为主手势。
步骤7:将手势保存到EEPROM
我们已经保存了主手势,但是一旦断电,所有保存到现在的手势都将丢失。我们需要一些方法来保存它们,以便我们可以在设备再次通电后再次检索它们。
我们可以使用外部I2C EEPROM并将它们连接到Arduino,但这会增加成本,我们不会不想要。
我们确实可以使用Arduino的内部EEPROM来保存手势。为此,我们需要包含EEPROM.h库,我们准备好了。
将主手势保存到EEPROM的功能是EEPROM_write()。
int master_select; //to select which master to select to EEPROM
//save 0-49 for master-0-x, 50-99 for master-0-y, 100-149 for master-0-z 。..。.
for(i=0; i{
for(j=0; j {
addr=(master_select*sample_size)+(i*DOF)+j;
EEPROM.write(addr, master[master_select][i][j]); //write value of master to specific address
delay(5); //time to write to EEPROM
}
}
从EEPROM检索主手势的功能是EEPROM_read()。
int master_select
for(i=0; i{
for(j=0; j {
addr=(master_select*sample_size)+(i*DOF)+j;
master[master_select][i][j]=EEPROM.read(addr); //save value from EEPROM to master gesture
delay(5);
}
}
步骤8:动态时间扭曲算法
11月我们可以记录手势和主手势,我们需要比较两者,这是DTW算法发挥作用的地方。..。..
代码中DTW的功能是calc_DTW_score(),函数abs_sum()和Min()将用于DTW计算。
什么是动态时间扭曲(DTW)算法?
这是一个算法,可以找到任何两个相似的算法时变系列。它最初是为语音识别目的而开发的。有关详细信息,请访问维基百科。
DTW_score越高,两个时间序列匹配的越少。为了检测匹配一对系列,我们可以将它与多个系列进行比较,无论哪个系列的DTW得分最小,它都是匹配系列。
如何实现它?
我没有找到任何简单的库(适合在Arduino的16 Mhz处理器上运行)或为Arduino编写的代码,所以我需要建立它。我编写的整个算法最简单,我可以得到它,它基于这个视频。
你只能找到我在这里实现的DTW算法。
上图是DTW计算的矩阵,第一行和第一列的突出显示元素是我们要比较的元素。其余的元素是计算DTW分数所必需的。
cell = difference of corresponding elements of arrays comparing + minimum of previously computed 3 values
由于我们将使用差异和最小元素,我创建了两个单独的函数“abs_sub”和“Min”进一步使用。
元素(1,1),(2,1)和& (1,2)只是数组相应元素的差异,所以代码如下所示。
a[1][1]=abs_sub(a[1][0], a[0][1]); //first element
a[2][1]=abs_sub(a[2][0], a[0][1]);
a[1][2]=abs_sub(a[1][0], a[0][2]);
第二行和第二列的其余元素是差值+分钟先前计算的3个值,即前一个元素。
x=1 //first row remaining elements
for(y=2; y a[x][y] = abs_sum(a[x][0], a[0][y]) + a[x][y-1];
y=1 //first coulum remaining elements
for(x=2; x a[x][y] = abs_sub(a[x][0], a[0][y]) + a[x-1][y]
现在,可以计算其余元素
for(x=2; x{
for(y=2; y {
a[x][y] = abs_sub(a[x][0], a[0][y]) + Min(a[x][y-1], a[x-1][y], a[x-1][y-1])
}
}
现在我们已经计算了在整个DTW矩阵中,我们现在可以通过将从右下角到左上角的下3个元素的最小值相加来计算DTW分数,请参阅上面的图像以获得更清晰。
x = sample_size; //moving to bottom right
y = sample_size;
DTW_score = a[x][y]; //sarting adding from there
while(x!=0 && y!=0) //till top left is reached
{
if(a[x-1][y-1]《=a[x][y-1] && a[x-1][y-1]《=a[x-1][y]) //if diagonal is minimum
{
DTW_score = DTW_score + a[x-1][y-1]; //add it
x--; //go to its position
y--;
}
else if() //if top is minimum
{
DTW_score = DTW_score + a[x][y-1];
y--;
}
else //add its side
{
DTW_score = DTW_score + a[x-1][y];
x--;
}
//repeat until top left is reached
}
return DTW_score; //done calculating DTW score
到达左上角时完成DTW_score的计算。现在这个分数可以用来比较任何两个系列的相似程度。
步骤9:添加动作如果手势匹配
我们现在有DTW算法将手势与几个主手势进行比较,我们需要设置动作来做手势与主手势匹配。
代码中的函数是do_action(int a)。
你可以用键盘做所有事情,可能会增加视频播放的音量或通过多次按键操作(ctrl + shift + esc)来打开任务管理器,也可以使用Autohotkey等启动应用程序。
您可以输入所有内容使用此USB HID表的命令。
要输入数字,字符或短语,您可以使用Bluetooth_HID.write/print(“某些字符或短语”);并且要从USB HID表输入密钥,您需要使用Bluetooth_HID.print(“something”,HEX);
PowerPoint演示文稿中的一些命令
n - 转到下一张幻灯片
p - 转到上一张幻灯片
w - 显示白色屏幕
b - 显示黑屏
if(a==0) //do action corresponding to master 0 gesture
{
bluetooth_HID.write(“n”); //send keystroke n from HID Bluetooth module as sent from wireless keyboard
}
//actions for remainging masters
步骤10:创建用户界面
我们拥有识别手势和其他所需的所有功能,现在我们需要一个用户界面来访问所有功能。
如果你不想创建用户界面,你可以去使用我创建的最简单的代码并根据需要对其进行修改。
这里我在void循环中创建了用户界面。..
第一步是初始化通过清洁并设置文本大小和文本位置来显示
#define display_init display.clearDisplay();display.setTextSize(1);display.setTextColor(WHITE);display.setCursor(0,0)
之后,我们可以在显示屏上显示所需的文字
while(1)
{
display_init; //initialize display
display.println(“What?”);
display.println(“ a. test gesture”);
display.println(“ b. record master”);
display.println(“ c. update EEPROM”);
display_set_cursor(line); //function we have created to display a cursor on selected line
display.display(); //update the screen
//press down_button to move cursor down
if(down_buton_pressed)
{
delay(10); //to remove button bouncing
line++ //go to next line
if(line》2) //if reached to last line
line=0; //go to first line
}
//press select_button to select option where cursor is present
if(select_button_pressed)
{
delay(10); //to remove button bouncing
break; //go to next lines by crossing while(1)
}
}
if(line==0) //if option on line 0 is selected, to test gesture
{
display_init; //initialize display
display.println(“recording gesture”);
display.display();
digitalWrite(13, HIGH);
take_reading();
digitalWrite(13, LOW);
display_init;
display.println(“done recording gesture”);
display.display();
for(i=0; i DTW_score[i]=calc_DTW_score(temp_values, master, i);
min_score=DTW_score[0]; //finding minimum of all DTW_scores
for(i=1; i {
if(DTW_score[i] min_score=DTW_score[i];
}
for(i=0; i {
if(min_score==DTW_score[i])
break; //exit from for loop
}
display_init;
display.println(“master is: ”);
display.println(i); //display master on screen
display.display();
do_action(i); //do corresponding action to master gesture
delay(2000); //display on screen for 2 seconds
}
else if(line==1) //similarly for line 1 and line 2
{
}
else if(line==2)
{
}
完成!
全部0条评论
快来发表一下你的评论吧 !