有沒有想過我們的世界是如何走向沉浸式現(xiàn)實(shí)的。我們不斷尋找新的方式和方法來使用虛擬現(xiàn)實(shí)、混合現(xiàn)實(shí)、增強(qiáng)現(xiàn)實(shí)等與周圍環(huán)境進(jìn)行交互。每天都有新設(shè)備出現(xiàn),這些快節(jié)奏的技術(shù)給我們留下了深刻的印象。
這些沉浸式技術(shù)用于游戲、互動(dòng)活動(dòng)、娛樂和許多其他應(yīng)用。在本教程中,我們將了解這種交互方法,它為您提供了一種與系統(tǒng)交互的新方法,而不是使用無聊的鼠標(biāo)。我們的游戲愛好者一定知道,幾年前任天堂的一家游戲公司推出了一種 3D 交互方法的想法,該方法在稱為 Wii 控制器的手持控制器的幫助下與他們的控制臺(tái)進(jìn)行交互。它使用加速度計(jì)來定位您的游戲手勢(shì)并將其無線發(fā)送到系統(tǒng)。
受這個(gè)想法的啟發(fā),我們將制作一個(gè)“空中鼠標(biāo)”,只需通過在空中移動(dòng)控制臺(tái)就可以與系統(tǒng)交互,但我們不會(huì)使用 3 維坐標(biāo)參考,我們只會(huì)使用 2 維坐標(biāo)參考,所以我們可以模仿計(jì)算機(jī)鼠標(biāo)的動(dòng)作,因?yàn)槭髽?biāo)在 X 和 Y 兩個(gè)維度上工作。
這款無線 3D Air Mouse背后的概念非常簡(jiǎn)單,我們將使用加速度計(jì)來獲取“Air mouse”沿 x 和 y 軸的動(dòng)作和運(yùn)動(dòng)的加速度值,然后根據(jù)加速度計(jì)我們將控制鼠標(biāo)光標(biāo)并在計(jì)算機(jī)上運(yùn)行的 python 軟件驅(qū)動(dòng)程序的幫助下執(zhí)行某些操作。
先決條件
Arduino Nano(任何型號(hào))
加速度計(jì) ADXL335 模塊
藍(lán)牙 HC-05 模塊
按按鈕
Python 安裝的計(jì)算機(jī)
電路原理圖
要通過手部的動(dòng)作控制計(jì)算機(jī),您需要一個(gè)加速度計(jì),它可以沿 X 軸和 Y 軸發(fā)出加速度,并使整個(gè)系統(tǒng)無線化,藍(lán)牙模塊用于將信號(hào)無線傳輸?shù)侥南到y(tǒng)。
這里使用了 ADXL335 加速度計(jì),它是一個(gè)基于 MEMS 的三軸模塊,輸出沿 X、Y 和 Z 軸的加速度,但如前所述,用于控制鼠標(biāo),我們只需要沿 X 和 Y 軸的加速度。
這里加速度計(jì)的 Xout 和 Yout 引腳連接到 Arduino 的 Analog、A0 和 A1 引腳,用于將信號(hào)從 Arduino 傳輸?shù)较到y(tǒng)此處使用藍(lán)牙模塊 HC-05,因?yàn)樗{(lán)牙通過 Tx 和 Rx 工作引腳連接,因此我們使用軟件串行引腳 D2 和 D3。它是使用軟件串行連接的,因?yàn)槿绻覀儗⑺{(lán)牙與硬件串行連接并開始通過 python 控制臺(tái)獲取讀數(shù),它將顯示不匹配波特率的錯(cuò)誤,因?yàn)樗{(lán)牙將以自己的波特率與 python 通信。通過使用包括 Arduino 在內(nèi)的不同微控制器完成各種基于藍(lán)牙的項(xiàng)目,了解有關(guān)使用藍(lán)牙模塊的更多信息。
這里我們使用了三個(gè)按鈕 - 一個(gè)用于觸發(fā) Air 鼠標(biāo),另外兩個(gè)用于左右單擊,如下圖所示:
空中鼠標(biāo)的流程
流程圖顯示了基于 Arduino 的 Air Mouse 的處理流程:
1.系統(tǒng)不斷檢查機(jī)械扳機(jī)是否被按下,直到?jīng)]有按下,我們可以用電腦鼠標(biāo)正常工作。
2.當(dāng)系統(tǒng)檢測(cè)到按鍵按下時(shí),鼠標(biāo)的控制權(quán)轉(zhuǎn)移到空中鼠標(biāo)。
3. 按下觸發(fā)按鈕時(shí),系統(tǒng)開始將鼠標(biāo)的讀數(shù)傳輸?shù)接?jì)算機(jī)。系統(tǒng)讀數(shù)包括加速度計(jì)讀數(shù),以及左鍵和右鍵的讀數(shù)。
4.系統(tǒng)讀數(shù)由1字節(jié)或8位的數(shù)據(jù)流組成,其中前三位為X坐標(biāo),后三位為Y坐標(biāo),倒數(shù)第二位為獲取狀態(tài)位鼠標(biāo)左鍵的狀態(tài),最后一位是獲取右鍵狀態(tài)的狀態(tài)位。
5.前三位的取值,即X坐標(biāo)的范圍為100《=Xcord《=999,而Y坐標(biāo)的取值范圍為100《=Ycord《=800。右鍵單擊和左鍵單擊的值是二進(jìn)制值 0 或 1,其中 1 表示單擊,0 表示用戶未單擊。
6. 為了不讓按鈕的彈跳影響光標(biāo)的位置,每次點(diǎn)擊鼠標(biāo)的觸發(fā)按鈕后都會(huì)保持 4 秒的已知延遲。
7. 空中鼠標(biāo)的左右點(diǎn)擊,我們必須先按下左鍵或右鍵,然后按下觸發(fā)鍵移動(dòng)到我們想要的空中鼠標(biāo)位置。
為空中鼠標(biāo)編程 Arduino
應(yīng)將 Arduino 編程為讀取 X 軸和 Y 軸的加速度值。最后給出了完整的程序,下面是代碼中的重要片段。
設(shè)置全局變量
如前所述,我們將使用軟件串行引腳連接藍(lán)牙模塊。因此,要設(shè)置軟件串行,我們需要聲明軟件串行庫(kù)并設(shè)置 Tx 和 Rx 的引腳。在 Arduino Nano 和 Uno 中,引腳 2 和 3 可以作為軟件串行工作。接下來,我們從軟件串行庫(kù)中聲明藍(lán)牙對(duì)象,以設(shè)置 Tx 和 Rx 的引腳。
?
#include const int rxpin = 2, txpin = 3; 軟件串行藍(lán)牙(rxpin,txpin); 常量 int x=A0; 常量 int y=A1; 整數(shù) xh, yh; int xcord,ycord; 常量 int 觸發(fā)器 = 5; 詮釋 lstate = 0; int rstate = 0; 常量 int lclick = 6; 常量 int rclick = 7; 常量 int led = 8;
?
無效設(shè)置()
在setup函數(shù)中,我們將設(shè)置變量來告訴程序它們將作為輸入還是輸出。觸發(fā)按鈕將被設(shè)置為輸入上拉,左右點(diǎn)擊被聲明為輸入并設(shè)置為高以使其充當(dāng)輸入上拉。
還將串行和藍(lán)牙通信的波特率設(shè)置為 9600。
?
無效設(shè)置() { pinMode(x,INPUT); pinMode(y,輸入); pinMode(觸發(fā)器,INPUT_PULLUP) pinMode(lclick,INPUT); pinMode(rclick,輸入); pinMode(LED,輸出); 數(shù)字寫入(lclick,HIGH); digitalWrite(rclick,HIGH); 序列號(hào).開始(9600); 藍(lán)牙.開始(9600); }
?
無效循環(huán)()
因?yàn)槲覀冃枰|發(fā)按鈕來告訴我們何時(shí)需要向系統(tǒng)發(fā)送數(shù)據(jù)流,所以我們?cè)趙hile循環(huán)中設(shè)置了整個(gè)代碼,它將持續(xù)監(jiān)控上拉觸發(fā)器的數(shù)字狀態(tài),當(dāng)它變低時(shí)它會(huì)將其進(jìn)一步傳遞以進(jìn)行處理。
由于我們已經(jīng)連接了一個(gè) LED 來讓我們知道按下觸發(fā)按鈕時(shí)系統(tǒng)的狀態(tài),我們最初將 LED 在while循環(huán)之外設(shè)置為低電平,因?yàn)樗悄J(rèn)條件,而在while循環(huán)內(nèi)部設(shè)置為高電平,這將點(diǎn)亮 LED每當(dāng)按下觸發(fā)按鈕時(shí)。
為了讀取左右單擊按鈕的狀態(tài),我們?nèi)致暶髁藘蓚€(gè)變量lclick和rclick?,它們的值最初設(shè)置為 0。
并在循環(huán)中,根據(jù)左右按鈕的數(shù)字狀態(tài)設(shè)置這些變量的值,以檢查按鈕是否被按下。
我們將使用模擬讀取函數(shù)讀取加速度計(jì)的 X 和 Y 輸出引腳的值,并將這些值映射到屏幕大小,以使鼠標(biāo)指針在整個(gè)屏幕上移動(dòng)。由于屏幕大小是屏幕中的像素,我們需要相應(yīng)地設(shè)置它,并且由于我們需要輸出值是三位數(shù),我們特意將 X 的范圍設(shè)置為 100<=X<=999 和類似的Y 的值為 100<=Y<=800。請(qǐng)記住,像素是從左上角讀取的,即左上角的值是 (0,0),但是由于我們已經(jīng)為 x 和 y 聲明了三位數(shù)字,我們的值將從點(diǎn) (100,100) 讀取。
此外,在Serial.print和bluetooth.print函數(shù)的幫助下,在串行和藍(lán)牙上打印坐標(biāo)值和點(diǎn)擊狀態(tài),它們有助于通過藍(lán)牙在串行監(jiān)視器和系統(tǒng)上獲取值。
最后,由于按鈕的彈跳,可能會(huì)重復(fù)單個(gè)值,這會(huì)導(dǎo)致鼠標(biāo)光標(biāo)停留在單個(gè)位置上,因此為了擺脫這種情況,我們必須添加此延遲。
?
無效循環(huán)() { 數(shù)字寫入(領(lǐng)導(dǎo),低); 而(digitalRead(觸發(fā)器)==LOW) { digitalWrite(LED,HIGH); lstate = digitalRead(lclick); rstate = digitalRead(rclick); xh=模擬讀取(x); yh=analogRead(y); xcord=map(xh,286,429,100,999); ycord=map(yh,282,427,100,800); 串行打印(xcord); Serial.print(ycord); if (lstate == LOW) Serial.print(1); 否則 Serial.print(0); if (rstate == LOW) Serial.print(1); 否則 Serial.print(0); 藍(lán)牙.print(xcord); 藍(lán)牙.print(ycord); if (lstate == LOW) bluetooth.print(1); 否則 bluetooth.print(0); if (rstate == LOW) bluetooth.print(1); 否則 bluetooth.print(0); 延遲(4000); } }
?
計(jì)算機(jī)的Python 驅(qū)動(dòng)程序腳本
到目前為止,我們已經(jīng)完成了硬件及其固件部分,現(xiàn)在要讓空中鼠標(biāo)工作,我們需要一個(gè)驅(qū)動(dòng)程序腳本,可以將空中鼠標(biāo)的信號(hào)解碼為光標(biāo)移動(dòng),所以為此,我們選擇了Python。Python是一種腳本語言,這里的腳本是指它可以幫助我們控制其他程序,因?yàn)檫@里我們控制的是鼠標(biāo)光標(biāo)。
因此,打開您的 python shell 并使用以下命令安裝以下庫(kù):
?
pip install 串行 pip install pyautogui
?
serial是 python的庫(kù),它可以幫助我們從串行接口(例如 com 端口)獲取數(shù)據(jù),還可以讓我們對(duì)其進(jìn)行操作,而pyautogui是 python 的庫(kù),用于控制 GUI 功能,在本例中為鼠標(biāo)。
現(xiàn)在我們來看看驅(qū)動(dòng)的代碼,首先我們需要導(dǎo)入serial和pyautogui庫(kù),然后從serial庫(kù)中,我們必須設(shè)置通信的com端口,波特率為9600,與Bluetooth.serial相同。為此,您必須將藍(lán)牙模塊連接到系統(tǒng),然后在系統(tǒng)設(shè)置中檢查它連接到哪個(gè) com 端口。
接下來的事情是讀取從藍(lán)牙到系統(tǒng)的串行通信,并在 while 1 的幫助下保持其連續(xù)運(yùn)行,使其余代碼保持連續(xù)循環(huán)。
如前所述,Arduino 發(fā)送 8 位,前 6 位用于坐標(biāo),后 2 位用于單擊按鈕的狀態(tài)。因此,在ser.read的幫助下讀取所有位并將其長(zhǎng)度設(shè)置為 8 位。
接下來,通過切片將光標(biāo)坐標(biāo)和點(diǎn)擊的位分割,然后進(jìn)一步將光標(biāo)位分別切割為 X 和 Y 坐標(biāo)。左鍵和右鍵也一樣。
現(xiàn)在從通信中,我們得到一個(gè)字節(jié)字符串,我們需要將其轉(zhuǎn)換為整數(shù),以便它們適合坐標(biāo),我們通過解碼它們?nèi)缓髮⑺鼈冾愋娃D(zhuǎn)換為整數(shù)來做到這一點(diǎn)。
現(xiàn)在要移動(dòng)光標(biāo),我們使用 pyautogui?moveto函數(shù),該函數(shù)將這些整數(shù)坐標(biāo)作為參數(shù)并將光標(biāo)移動(dòng)到該位置。
接下來檢查點(diǎn)擊,我們使用最后兩位和 pyautogui 的 click 函數(shù)來做到這一點(diǎn),它的默認(rèn)點(diǎn)擊是左一個(gè),但是我們可以通過將按鈕值聲明為右來將其設(shè)置為右,我們也可以定義點(diǎn)擊次數(shù)通過將 clicks 參數(shù)設(shè)置為 2 將其設(shè)置為雙擊。
以下是要在計(jì)算機(jī)上運(yùn)行的完整 Python 代碼:
?
導(dǎo)入串口 import pyautogui ser=serial.Serial('com3',9600) while 1: k=ser.read(8) cursor=k[:6] click=k[6:] x=cursor[:3] y= cursor[3:] l=click[0] r=click[1] xcor=int(x.decode('utf-8')) ycor=int(y.decode('utf-8')) pyautogui.moveTo (xcor,ycor) 如果 l==49: pyautogui.click(clicks=2) elif r==49: pyautogui.click(button='right', clicks=2)
?
測(cè)試 Arduino 空中鼠標(biāo)
因此,要操作 Air Mouse,請(qǐng)為其連接電源。它可以來自 Arduino Nano USB 插槽或來自使用 7805 IC 的 5v 穩(wěn)壓電源。然后通過設(shè)置藍(lán)牙連接到的 com 端口來運(yùn)行 python 驅(qū)動(dòng)程序腳本。當(dāng)腳本運(yùn)行時(shí),您會(huì)看到藍(lán)牙閃爍的時(shí)間滯后,這意味著它已連接到您的系統(tǒng)。然后操作它點(diǎn)擊觸發(fā)按鈕,你會(huì)看到坐標(biāo)的位置會(huì)改變,如果你想要左擊或右擊,然后先按下左或右按鈕和觸發(fā)按鈕,你會(huì)看到點(diǎn)擊的動(dòng)作光標(biāo)位置的改變。
Python腳本:
導(dǎo)入串口
import pyautogui
ser=serial.Serial('com3',9600)
while 1:
k=ser.read(8)
cursor=k[:6]
click=k[6:]
x=cursor[:3]
y= cursor[3:]
l=click[0]
r=click[1]
xcor=int(x.decode('utf-8'))
ycor=int(y.decode('utf-8'))
pyautogui.moveTo (xcor,ycor)
如果 l==49:
pyautogui.click(clicks=2)
elif r==49:
pyautogui.click(button='right', clicks=2)
Arduino代碼:
#include
const int rxpin = 2, txpin = 3;
軟件串行藍(lán)牙(rxpin,txpin);
常量 int x=A0;
常量 int y=A1;
整數(shù) xh, yh;
int xcord,ycord;
常量 int 觸發(fā)器 = 5;
詮釋 lstate = 0;
int rstate = 0;
常量 int lclick = 6;
常量 int rclick = 7;
常量 int led = 8;
無效設(shè)置()
{
pinMode(x,INPUT);
pinMode(y,輸入);
pinMode(觸發(fā)器,INPUT_PULLUP);
pinMode(lclick,輸入);
pinMode(rclick,輸入);
pinMode(LED,輸出);
數(shù)字寫入(lclick,HIGH);
digitalWrite(rclick,HIGH);
序列號(hào).開始(9600);
藍(lán)牙.開始(9600);
}
無效循環(huán)()
{
數(shù)字寫入(領(lǐng)導(dǎo),低);
而(digitalRead(觸發(fā)器)==LOW)
{
digitalWrite(LED,HIGH);
lstate = digitalRead(lclick);
rstate = digitalRead(rclick);
xh=模擬讀?。▁);
yh=analogRead(y);
xcord=map(xh,286,429,100,999);
ycord=map(yh,282,427,100,800);
串行打?。▁cord);
Serial.print(ycord);
if (lstate == LOW)
Serial.print(1);
否則
Serial.print(0);
if (rstate == LOW)
Serial.print(1);
否則
Serial.print(0);
藍(lán)牙.print(xcord);
藍(lán)牙.print(ycord);
if (lstate == LOW)
bluetooth.print(1);
否則
bluetooth.print(0);
if (rstate == LOW)
bluetooth.print(1);
否則
bluetooth.print(0);
延遲(4000);
}
}
Python驅(qū)動(dòng)腳本
導(dǎo)入串口
import pyautogui
ser=serial.Serial('com3',9600)
while 1:
k=ser.read(8)
cursor=k[:6]
click=k[6:]
x=cursor[:3]
y= cursor[3:]
l=click[0]
r=click[1]
xcor=int(x.decode('utf-8'))
ycor=int(y.decode('utf-8'))
pyautogui.moveTo (xcor,ycor)
如果 l==49:
pyautogui.click(clicks=2)
elif r==49:
pyautogui.click(button='right', clicks=2)
?
評(píng)論