步驟1:所需部件
Arduino Mega
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的藍牙模塊,你可以開始構建硬件。
我建議在一塊穿孔板上構建所有硬件并將其作為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)
{
}
完成!
-
Arduino
+關注
關注
188文章
6478瀏覽量
188290
發布評論請先 登錄
相關推薦
如何用OpenCV進行手勢識別--基于米爾全志T527開發板

Cortex-A55國產處理器_教學實驗箱_操作案例分享:5-21 手勢識別實驗
如何用Jacinto內部的GPtimer輸出PWM信號控制屏幕背光

評論