從 0 開始,手打一把專屬的藍牙雙模人體工學鍵盤 (7) 軌跡球

李松錡
6 min readOct 29, 2017

--

此為系列文,目前已完成的文章列表:

  1. 從 0 開始,手打一把專屬的藍牙雙模人體工學鍵盤 (0)
  2. 從 0 開始,手打一把專屬的藍牙雙模人體工學鍵盤 (1) 製作左手
  3. 從 0 開始,手打一把專屬的藍牙雙模人體工學鍵盤 (2) 設定 BLE
  4. 從 0 開始,手打一把專屬的藍牙雙模人體工學鍵盤 (3) Debounce
  5. 從 0 開始,手打一把專屬的藍牙雙模人體工學鍵盤 (4) 定義 keyboardMgr class
  6. 從 0 開始,手打一把專屬的藍牙雙模人體工學鍵盤 (5) 製作右手
  7. 從 0 開始,手打一把專屬的藍牙雙模人體工學鍵盤 (6) 基礎鍵盤
  8. 從 0 開始,手打一把專屬的藍牙雙模人體工學鍵盤 (7) 軌跡球

到目前為止,我們的電路和 Arduino 的程式已經寫出了一個具有實用性的鍵盤了,但之前為軌跡球預留的線還醜醜的留在外面,今天我們就要把軌跡球模組也放上去,讓你有一個快速使用的小滑鼠啦~

不小心被大家看到我使用的是靜音紅軸 (粉紅軸)

其實線亂成一團,一開始我也不知道哪條線連到 Arduino Pro Micro 上面哪一個 pin 腳,所以我是拿著三用電錶一根一根慢慢測到底連到 Pro Micro 上面哪個孔,然後才焊上去的。其實主要是 pin 5, 6, 9, 10 這 4 根 pin 腳具有 PWM 的功能,所以我會想把他連到 blackberry mini trackball 上面的 led 腳,這樣就可以控制燈號的亮度。剩下的上下左右則隨意使用剩下的 pin 腳即可。

這個軌跡球模組使用的是霍爾效應,他可以偵測到軌跡球上面的球朝某個方向滾動了,但沒辦法偵測出滾動的速度有多快,而當 pin 腳呈現高電壓時表示在該方向上有移動事件發生,反之則沒有。因此我們可以有一個非常簡單的實作版本:

if (digitalRead(one_direction)) {
// send mouse move event
}

這樣就可以做偵測了。但實際上應用的時候,這樣是挺不舒服的,因為考慮到人的使用習慣,一般我們會有兩種使用的方式:

  1. 連續動得很快很勤: 這種時候通常是我們想要大幅移動滑鼠的位置
  2. 動得比較慢比較小心: 這種時候是滑鼠快到我們預期的位置,所以要做減速跟比較精細的定位

而這個設計更可以在 Macbook 上面的觸控板體現出來。那麼我們要怎麼模擬出這個功能呢? 我在以前的專案裡面有做過一個設計,那在我們這次的範例程式中,我把整個軌跡球重寫,重新整理成一個軌跡球的 class,裡面用了兩個 class 去應對軌跡球的功能,分別是 Direction 和 TrackballLed 這兩個 class,一個去控制在某個軸上面的移動大小及方向,另一個則是用來控制 LED 燈的 (我做了呼吸燈的特效)。

那我們前面提到人的使用習慣有兩種,那要怎麼實現這兩種功能呢? 首先我們就要來看看在這兩種情境下,Arduino 監測到的數據有什麼不同了。因為 Arduino 的掃描速度其實並不慢,因此在動得很快的情境下,會看到在那個方向上 Arduino 會不斷的偵測到在那個方向上的 pin 腳有連續的高電壓狀態,而在動得很慢的時候,Arduino 偵測到在那個方向上的 pin 腳電壓狀態會呈現高低電壓交錯,也就是會讀到斷斷續續的有滾動那顆軌跡球。利用這個特性,我們就能夠分辨出現在是哪個情境。知道這點以後,我有一個最簡單的想法,就是看這次的滾動能夠持續多久,如果持續得越久的話,我就讓每次接收到滾到時候移動的距離變大。最簡單的想法,我們可以套用一個線性函數,

y 軸是移動的像素量,x 軸則是連續偵測到移動的時間間隔。當剛偵測到移動時,就只會移動最基本量的移動距離。隨著移動事件不間斷,每次送給電腦要移動的像素點量就會提高一些

然後我們一樣把偵測到這次開始移動的時間記錄下來,然後如同我們在 KeyBtn 裡面做的事情一樣,就先記著這件事,等到下次再次讀取是否有變化的時候,只要沒有偵測到暫停移動了,那每次移動的像素點數就會越來越多,如此就滿足我們前面提到的那個情境。

雖然我們做了這樣的處理,但使用起來會發現… 線性的函數動起來不夠過癮,行為太單調,跟我們預期有的表現不太相符,所以我改用了非線性函數來模擬人的感受。在這裡,我選用了一個最好實作的函數: 指數函數

和前一張圖有類似的特性,但在初期會比較連續移動的初期十分平緩,過了一個界線後會急劇增加移動的像素點數

上圖是個示意圖,有點誇張化前期平緩的樣子,但基本概念就是這個樣子。透過這樣的設計,這樣使用起來會更符合人的移動期望。除此之外,還有一個要處理的問題是我們應該要限制一次移動的像素點上限,因為在函數的後期其實會增長得非常快,不然僅是做出了一次快速移動的動作後,你的滑鼠會瞬間撞到螢幕的邊邊。

有了以上這些概念之後,可以去看我在 direction 這個 class 裡面的實作,接著我們就可以把軌跡球模組加入到 keyboardMgr 裡面了! 因為我們把軌跡球的模組抽象成了 trackball 這個 class,所以我們可以在 keyboardMgr 裡面宣告一個軌跡球的 object,然後每次只要在 keyboardMgr.exec() 裡面都固定執行一次就可以了 (或者你也可以不要把他放入到 keyboardMgr 裡面,把它當成一個獨立的裝置,放在 Arduino 的主程式中,然後在 void loop() 裡面呼叫完 keyboardMgr.exec() 以後,再呼叫 trackball.handleTrackball())。

做到這裡,你的軌跡球模組也能夠運作了,對我來說才算是做出一個完整的基本版鍵盤。那下一回是我們的最終回,我們要幹嘛呢? 其實這個鍵盤到現在已經可以做出來了,大家如果有每回每回都跟著做的話,這次就可以把鍵盤做完,然後實際拿來使用了。目前的鍵盤,礙於藍牙模組是訂製好的,無法做客製化,裡面有很多不必要的運算及設計,所以在快速打字的時候是會有點卡卡的,主要是左手在短時間內快速的傳送按鍵事件幾次後,會突然的變慢。這個問題我們會在下一次最終回的時候,向大家介紹如何用軟體去做補償,把這個不適感降低。

--

--