# 馬達編碼器解讀 馬達編碼器一般使用兩個正交 (也就是差 90°) 的霍爾感測器, 偵測編碼器上磁石的磁性變化, 我測試時的馬達編碼器如下圖: ![image](https://hackmd.io/_uploads/ryGCha9G0.png) 兩個感測器的位置如圖中標示, 當磁石轉動時, 磁石上的磁性會交替變化, 霍爾感測器就會隨之產生高低電位變化。由於兩個霍爾感測器位置正交, 所以會相差 1/4 個週期, 例如當磁石受馬達帶動**順時針**旋轉時, 感測器 ② 的變化會領先感測器 ① 的變化 1/4 個週期, 以[Desmos 網頁繪製的圖](https://www.desmos.com/calculator/gfmuvfem7d)表示如下: ![image](https://hackmd.io/_uploads/BkwToTcz0.png) 以下方的感測器 ① 來看, 每次電位改變 (圖中箭頭標示處) 時, 它改變後的電位都會和感測器 ② 相同。 如果磁石是逆時針旋轉, 變成感測器 ② 的變化會落後感測器 ① 的變化 1/4 個週期: ![image](https://hackmd.io/_uploads/H15O2p5G0.png) 同樣以下方的感測器 ① 來看, 每次電位改變 (圖中箭頭標示處) 時, 它改變後的電位都會和感測器 ② 相反。 所以只要在感測器 ① 電位變化時檢查感測器 ② 的電位, 就可以知道現在編碼器是順時鐘還是逆時鐘轉動了。 利用這樣的想法, 就可以計算感測器 ① 在編碼器順時鐘或是逆時鐘轉的電位變化次數, 以下就使用 ESP32, 在 C1 接腳設置一個電位上升時觸發的中斷, 計算從低電位變高電位的時候, 判斷編碼器磁石旋轉方向, 並以順時鐘轉遞增計數, 反之遞減計數: ```arduino= #define C1_PIN 33 // 霍爾輸出C1的接腳 #define C2_PIN 34 // 霍爾輸出C2的接腳 volatile int32_t count = 0; // 將被中斷常式改變的值,要設成volatile。 int32_t lastCount = 0; // 儲存「上次」脈衝數 void IRAM_ATTR encISR() { // 計算脈衝數的中斷處理常式 bool c2 = digitalRead(C2_PIN); // 讀取C2的狀態 if(c2) // 若c2為1(高電位)… count++; // 代表輪子那一面是順時針轉動 else count--; } void setup() { Serial.begin(115200); pinMode(C1_PIN, INPUT); pinMode(C2_PIN, INPUT); // 偵測C1腳的變化,於脈衝上升階段觸發。 attachInterrupt(C1_PIN, encISR, RISING); } void loop() { if (count != lastCount) { // 若脈衝數變動,顯示脈衝數。 lastCount = count; Serial.printf("脈衝數:%ld\n", count); } } ``` 以下是編碼器逆時鐘旋轉的結果, 可以看到計數遞減: {%youtube zsWUgUhZqRo %} 以下則是編碼器順時鐘旋轉的結果, 可以看到計數遞增: {%youtube svN_PaLkocs %} 有了變化技術後, 只要知道磁石一圈的磁性變化次數, 以及減速齒輪箱的齒輪減速比, 就可以推算最後齒輪箱轉軸的旋轉圈數, 這些都可以在馬達的規格中找到, 像是以下就是我測試的[GM25-370](https://item.taobao.com/item.htm?spm=a1z09.2.0.0.67002e8dBeRVLp&id=523820484160&_u=ns4b4pq219b): ![](https://i.imgur.com/ZiWcCqr.png) 馬達轉一圈圓形磁石上會有 11 次脈衝, 每個脈衝會出發 2 次電位變化, 總共會觸發感測器 22 次電位變化。根據底下的參數, 齒輪箱的減速比是 1:45: ![](https://i.imgur.com/EHIKX0M.png) 所以只要把剛剛的程式計出來的計數除以 22 就是馬達的轉動圈數, 再除以 45 就是實際接在齒輪箱轉軸轉動圈數, 只是馬達轉動的方向與編碼器磁石轉動的方向相反。