前陣子在 IG 上看到了一個非常漂亮的 Arduino Hourglass 專案。
因為覺得非常漂亮,就決定自己也來做一個。
材料
- 控制板:Arduino 系列 (ATMEGA 2560) 或是 ESP 系列 (ESP32 DEVKit v1)
- 顯示:8 x 8 LED 矩陣顯示器含 MAX7219 IC 的模組,共兩個。
- 感測器:陀螺儀和加速度計的 MPU 6050。
電路圖
MAX 7219 可以幫助我們輕鬆地透過串流資料來控制 LED 矩陣的每一個點的亮或是暗。
最有趣的地方是,它可以與其它的 MAX 7219 進行鏈接,這代表可以用固定數量的 GPIO 來控制多個 LED 矩陣。
因此我們將 LED 沙漏的上半部分與下半部分鏈接起來,並將串流資料的相關腳位接到 ESP32 控制器。
感測器部分使用 MPU 6050, 內建加速度計和陀螺儀。
為了模擬沙漏中的沙子受到地球重力影響而下落的物理特性,所以要透過加速度計來偵測重力作用在沙漏上的方向。
ESP32 DEVKIT V1 開發板上的 ESP-WROOM-32 MCU 上的程式碼要負責:
- 建立 LED 矩陣沙漏的抽象資料模型
- 接收 MPU 6050 的加速度計資料,並判斷當前重力作用在沙漏的方向
- 將資料模型的資料顯示在兩個 MAX 7219 的 LED 矩陣上。
LED 矩陣沙漏的資料模型
LED 沙漏分成上下兩個區塊,無論是哪一個區塊,其中的沙粒都要表現出受到重力的影響,使得砂粒下落的行為。
因此只要建立好一個區塊資料模型並重覆使用即可,因為無論是上或是下的區塊,表現出的概念都是相同的;給予區塊重力方向,使得沙粒向下落下。
首先將代表沙漏某一個區塊的 LED 矩陣放在直角坐標系內。如果以實際的視覺效果會像是下圖這樣:
假定有一(藍色)沙粒在座標 (7, 7) ,則它受重力的影響會有三種可能性(紅色)分別是:
- 正下方座標 (6, 6)
- 右下方座標 (7, 6)
- 左下方座標 (6, 7)
實際上,假設不考慮其它物理特性的話,在這裡傾向的做法是,若正下方沒有其它沙粒存在,優先讓沙粒從 (7, 7) 移動到 (6, 6),這樣子的表現會更像實物。
而左下和右下的方向,若是兩邊也都沒有沙粒存在,則亂數決定其落下方向,避免總是讓沙粒呈現固定的行為。
而若是只有一邊沒有沙粒存在,就讓它往沒有沙粒的方向落下。
最後,三個方向都有沙粒的存在的話,就不動作。
依此邏輯,依序遍歷每一個座標並作處理,就可以產生沙粒落下的一個幀 (frame) 畫面。
假設當前沙粒座標為 (x, y) 則:
- 正下方座標 (x-1, y-1)
- 右下方座標 (x, y-1)
- 左下方座標 (x-1, y)
不斷地重覆去執行 “遍歷每一個座標” 的循環,可以產生無數個幀,並依序且按照設定好的時間間隔 (fps),將每一個座標的沙粒狀態顯示在 LED 矩陣上,就可以呈現出沙粒落下的動畫。
沙漏可能豎放也可能橫放,也就是重力會作用在沙漏的上下左右,共四個方向。
在此我們只要將基礎座標系進行對應的旋轉後,依然可以使用上面提到的處理方法來呈現沙粒重力方向移動的畫面。就像下圖這樣:
當重力作用在沙漏的右側時,我們將基礎座標系旋轉 90度產生新的參考座標系後,繼續使用上面提到的方法遍歷參考座標係,即可讓沙粒向右移動。
也就是說重力作用在沙漏的:
- 由上到下的方向:參考座標系 = 基礎座標系旋轉 0 度
- 由下到上的方向:參考座標系 = 基礎座標系旋轉 180 度
- 由左到右的方向:參考座標系 = 基礎座標系旋轉 90 度
- 由右到左的方向:參考座標系 = 基礎座標系旋轉 270 度
由基礎座標系的座標求出參考座標系的座標,可以使用矩陣的旋轉和平移達成。
重力方向
重力的方向偵測,則由 MPU 6050 在每一幀畫面產生前,讀取加速度計的 X, Y, Z 三個方向的加速度值判斷。
原始碼
LED 沙漏程式碼請參考: