引言
你是否注意到,這些年我們越來越少在演講中看到演講人用鐳射筆給觀眾指示所講的內容。先說鐳射筆,鐳射筆的工作原理是射出一束鐳射,照射到幕布上並反射到觀眾的眼睛裡,於是大家可以看到一個很亮的紅色光點。但現在因為大尺寸螢幕越來越便宜,我們越來越少使用幕布這種傳統投影顯示裝置了,畢竟螢幕的顯示效果要更好。而螢幕為了保證良好的顯示效果,往往都會在表面的玻璃上使用大量抗反射技術。這些抗反射技術的運用大大減弱了鐳射的反射,所以終端使用者看到的紅色光點就不那麼顯眼了,鐳射筆的效果大打折扣。
那麼有沒有可能用大家出門唯一願意攜帶的手機來替代鐳射筆呢?我嘗試了下面兩種方案。
3D 模擬方案
簡單來說就是用手機內建的姿態感測器和加速度感測器來構建出手機和螢幕在三維空間中的方位和姿態,再以此模擬計算如果從手機發出一束鐳射,會照射到螢幕上的哪個位置,並在螢幕上的相應位置繪製一個紅點,這樣來實現手機模擬鐳射筆的效果。
如上圖所示,假設一塊螢幕的兩條鄰邊分別平行與 X 軸和 Z 軸。當手機從 A 點沿著螢幕的一條邊移動到 B 點,再從 B 點沿著螢幕的另一條邊移動到 C 點,我們就可以計算出螢幕在以 A 點為原點的三維空間中的具體位置。
計算方法其實很簡單,比如當我們計算從 A 到 B 的過程時,只需要用手機上的加速度感測器取出時時刻刻手機在 x 軸方向上的加速度,再乘以時間,就可以得到手機時時刻刻在 x 軸方向的速度,速度再乘以時間就可以得出手機在 x 軸方向移動了多少距離。簡單說就是對手機在 x 軸方向的加速度做了兩次時間維度上的積分。
能夠通過把手機從 A 點移動到 B 點和 C 點來計算出螢幕的位置,自然也可以在接下來計算出任意時刻手機相對螢幕的空間位置和姿態方向,並模擬計算從手機射出一束鐳射會照射到螢幕的哪個位置。
可是,實驗過後我發現這個方案雖然在理論上是可行的,但因為累積誤差的存在,實際並不可行。
我們拿手機從 A 點移動到 B 點這個最基礎的場景來舉例。當一個人拿著手機從 A 移動到 B 的時候,手機的加速度、速度和移動距離可以用下面三幅圖來描述。
橫軸 t 表示時間,縱軸 a、v、d 分別表示手機在 x 方向的加速度、速度和移動距離。
第一幅圖中,加速度前半程是正的,後半程是負的,所以手機在 x 方向上先加速後減速,速度從 0 增長到最大,後又慢慢減為 0,而移動距離一開始因為速度比較慢,所以增長慢,中間速度達到最大值,移動距離也增長得最快,最後速度歸 0,移動距離也不在增長。
可問題就出在加速度上。本來加速度正的部分的積分和負的部分的積分,也就是藍色區域的面積和黃色區域的面積,是完全一致的,這樣當運動過程結束時手機的速度就會恢復為 0,但實際情況並非如此。
首先,真實世界的物理量是連續的,加速度當然也是連續的,但在手機上通過作業系統提供的各種介面取到的加速度是不可能連續的,而是每 16ms 才能取一個值。於是在計算藍色和黃色區域的面積的時候,只能通過計算若干個矩形的面積並求和來得到一個近似值。
其次,手機作業系統通過介面提供的加速度和真實的加速度必然是有差別的,任何測量都有誤差,只有真實的值才會使得藍色和黃色區域的面積完全相同。
所以,由於上述的兩個原因,在手機從 A 點移動到 B 點後,我們經過測量加速度和計算速度,最後會發現手機到達 B 點後速度依然沒有歸 0,而速度沒有歸 0 意味著系統以為手機依然在勻速沿 x 軸移動,最終使得整個系統都不可用。
3D 模擬方案的根本問題在於我們需要對一個存在誤差的量做時間上的積分,我們都知道誤差並不可怕,幾乎所有的測量量都有誤差,比較可怕的是累積誤差,它會讓你的系統執行一段時間後完全失控,而 3D 模擬方案更糟糕的地方在於這個誤差是在時間維度上累積的,而時間不會停止。
姿態模擬方案
在 3D 模擬方案失敗後,我又想到一個簡化版的方案,既然加速度因為有誤差而無法使用,那能不能考慮簡單一點,只用沒有累積誤差的方向感測器來實現控制呢?
假設手機的初始位置是正對螢幕的正中心,那麼只要知道手機到螢幕的距離,以及手機繞 x 軸旋轉的角度 beta,就可以算出紅色光電會向上移動多少距離了。但我們沒有距離感測器,前面也說了不能用加速度來計算距離,那我們乾脆再進一步簡化,不考慮距離,只考慮角度。
我們認為設定手機手機初始位置正對螢幕正中,繞 x 軸向上旋轉 25 度時,紅點從螢幕正中移動到螢幕頂部,繞 x 軸向下旋轉 25 度時,紅點移動到螢幕底部。手機繞 z 軸左右旋轉 25 度時,紅點分別移動到螢幕的最左邊和最右邊。這樣,我們就可以只用一個簡單的姿態感測器實現模擬鐳射筆的效果了。
實驗表明,這種方案完全可行,而且程式碼邏輯簡單。當然,這種方式假定了手機的初始姿態,其實也假定了手機到螢幕的距離(可以思考一下為啥也假定了手機到螢幕的距離^_^),使用者在使用的時候可能會稍微感到有一點點不自然。同時,為了更好更方便的控制體驗,還需要加一些讓使用者重置手機姿態的功能。
Demo
本文中所講的姿態模擬方案,大家可以在 Laser Pen Demo 體驗,相關程式碼在 Laser Pen - Github 的 example 目錄下。 在 pc 瀏覽器中開啟 demo 頁面後稍等幾秒,你應該會看到頁面的頭部生成了一個二維碼。
當手機上的控制頁面顯示「Connected」的時候,你就可以嘗試揮動手機來控制 pc 頁面上的小紅點啦。
關於這個 demo 還有兩點說明。
首先,demo 中獲取的手機姿態資料是通過 WebRTC 技術直接發到 pc 頁面的,所以你完全不用擔心有個人敏感資訊洩露的問題。
其次,demo 的主要通訊手段雖然是 WebRTC,但 WebRTC 連結建立的過程是需要一些訊息推送手段的,所以 demo 也用到了 socket.io
最後,demo 用了一個免費的後端服務,這個服務一段時間沒有人訪問後會自動停止,下次再訪問就得等將近兩分鐘服務才能啟起來。所以如果你開啟 pc 頁面後發現二維碼沒有顯示出來,可以先去喝杯水,再回來重新整理一下頁面試試。
最後
歡迎大家 star、pr、issue 我的專案 Laser Pen - Github
歡迎關注我的微信公眾號:老虎的小窩