Arudino 與 86Duino Servo 函式庫 PWM 抖動現象之比較

一、簡介

86Diuno 的 Servo 函式庫和 Arudino 的 Servo 函式庫,可以輸出多軸 PWM(Pulse Width Modulation)信號來控制多顆伺服機,藉由改變 PWM 的工作週期(又稱為 Duty,即 HIGH 的時間長短)來控制伺服機的角度,如下示意圖所示:

tumblr_lyjj1y0L021qf00w4

從上面的示意圖來看,伺服機的 PWM 週期為 20ms,我們可以輸入 900us ~ 2400us 的工作週期,讓伺服機從 0 度轉動到 180 度,而 86Duino 和 Arduino 的 Servo 函式庫,能同時送出多組這樣的 PWM 信號來控制多顆伺服機。

本文要說明的 PWM 抖動,指的是 PWM 的 “Duty” 會存在不固定的抖動現象,發生這個現象的原因,與控制板產生 PWM 的方式有關,下面我們來看幾個控制板產生 PWM 信號的方式:

  1. 透過內建或外接的 PWM 硬體來產生 PWM 信號
  2. 用軟體模擬方式來產生 PWM 信號

第一種方式,因為有透過外部或內建的 PWM 硬體在運作,產生出來的 PWM 信號精準、可靠。以 86Duino 和 Arduino 為例,兩者都有內建 PWM 硬體,例如我們呼叫 analogWrite() 函式後,PWM 硬體便開始獨立運作並送出我們指定的 PWM 波形,用這個方式送出的 PWM 不會有抖動的問題。

第二種方式,通常是控制板在沒有內建或外接 PWM 硬體的情況下,才會使用的方法:軟體模擬,有時候,在需要更多組 PWM 信號的場合,也會用這個方法來產生更多組的 PWM 信號(例如:控制多軸 RC 伺服機機器人)。以 86Duino 和 Arduino 為例,雖然兩者都有內建硬體 PWM,但為了能輸出更多組 PWM 來控制多顆 RC 伺服機,其內建的 Servo 函式庫,使用了軟體模擬方式來實作多組 PWM 信號輸出。

使用軟體模擬方式產生的 PWM 信號和硬體產生的 PWM 不一樣,大部分會存在 PWM 抖動的情形,下面我們使用示波器,在 Arduino Mega 2560 上實際量測 Servo 函式庫輸出的 PWM 信號,並觀察 Duty 抖動的情況:

二、軟體模擬的實作方法

從上面我們知道,軟體模擬出來的 PWM 會有抖動現象,但具體的成因是什麼呢? 成因就在於軟體模擬的實作方法,下面我們來看軟體模擬實作的簡要介紹:

軟體模擬,指的是我們藉由程式,操控控制板上的 GPIO 和 Timer(計時器),透過兩者共同運作來模擬 PWM 輸出。其中,GPIO 負責控制腳位的 HIGH 和 LOW,計時器負責在 Duty 和 period 時間點發出中斷,讓程式進入中斷副程式來更新 GPIO 的 HIGH/LOW狀態。

上面我們要注意的是 “中斷” 這個行為。在一顆功能豐富的 CPU 上可以處理多個中斷,但是當有多個中斷 “同時” 請 CPU 處理時,CPU 只能依照優先級順序一個一個處理,也就是說,如果我們使用的計時器中斷和其他中斷同時發生,計時器中斷可能不會 “即時” 被 CPU 響應,必需等待 CPU 把優先級高的中斷事件處理完後,才會處理計時器中斷,造成每次進入中斷副程式的時間會飄動,可能長也可能短,所以 GPIO 的 HIGH/LOW 狀態無法在準確的時間點更新,因而形成 PWM 抖動現象。

PWM 抖動的幅度(範圍大小),受到 CPU 處理速度、是否同時有其它中斷、中斷優先級、I/O 硬體設計等影響,造成的抖動可能大也可能小,以 Arduino Mega 2560 為例,使用 Servo 函式庫送出 1 組 Duty 為 1500us 的 PWM,實際量測的 Duty 大約會在 1501us ~ 1509us 之間抖動,抖動範圍約 8us。

三、PWM 抖動造成的影響(以 Arduino Servo 函式庫為例)

在 Arduino Mega 2560 上,我們接上一顆高精度的伺服機,例如 KONDO KRS4000 系列的伺服機,然後使用 Servo 函式庫送出 Duty 1500us 的 PWM 給這顆伺服機,從下面影片可以看到,已經轉到 1500us 角度的伺服機,會因為 PWM Duty 的抖動而產生小幅震動(此例子的 PWM Duty 的抖動範圍約 8us):

高精度的伺服機會反應微小的 PWM 抖動,但一般我們在市面上常見的 SG-90MG995/996系列,它們因為解析度較低,所以不會響應 8us 的 PWM 抖動,也就沒有影片中的情形。

接下來,如果一次啟用 40 組以上的 PWM,然後改成接上一顆低解析度的 SG-90 伺服機,會怎麼樣呢?

可以看到低解析度的伺服機也出現抖動情形了,這是因為在 Arduino 的 Servo 函式庫中,為了輸出更多組 PWM 而自動開啟第二組、第三組計時器中斷,造成兩兩中斷互相干擾,惡化了 PWM 抖動情形。惡化現象使 Duty 的誤差範圍最高達到 77us 左右,這個誤差足以讓低解析度的伺服機響應,因此產生抖動。

四、86Duino Servo 函式庫

從前面我們知道,如果能讓 PWM 的抖動範圍盡可能小,市面上那些常見的伺服機就不容易出現抖動情形,因此我們在 86Duino 的 Servo 函式庫(以及 Servo86 函式庫)中做了以下改善:

  1. 一旦進入中斷副程式,便關閉所有中斷,使執行權不會被其他高特權級的中斷搶走,有效降低 PWM 抖動。
  2. 使用內建的 PWM 硬體計時器機制,提早進入中斷副程式中等待時間到達,有效降低 PWM 抖動。
  3. 即使啟用了 45 組 PWM,仍然只使用一個計時器中斷,不會有多組計時器中斷造成 PWM 抖動惡化的情形。

使用上述的改善方法,可以讓 86Duino 在啟用 45 組 PWM 時,每一組 PWM 仍然保持 1us ~ 2us 的抖動範圍。

下表是我們在 Arduino UNO、Leonardo、Mega、DUE 和 86Duino 上,使用各自的 Servo 函式庫並啟用 1 組 PWM 所量測出來的 Duty 誤差範圍:

pwm_jiter

下表是我們在 Arduino Mega、Arduino DUE 和 86Duino 上,使用各自的 Servo 函式庫並啟用 45 組 PWM 所量測出來的 Duty 誤差範圍:

pwm_jiter

由上面可以看到 86Duino 在 PWM 抖動抑制上有良好的改善,另外,在原本就能輸出硬體 PWM 的腳位(腳位旁有標示~符號),86Duino Servo 函式庫也會自動改用硬體 PWM 來輸出,達到零抖動的目的。


黑客天地主頁面

The text of the 86Duino reference is licensed under a Creative Commons Attribution-ShareAlike 3.0 License.