Arduino筆記(74):PCA9685控制Servo伺服馬達

我的部落格中有一篇被瀏覽次數很高的文章,是有關於伺服馬達的控制(Arduino筆記(15):控制伺服馬達 SERVO),那是說明單一個伺服馬達的控制,可外接電源使用 Arduino PWM的接腳來控制。如果要控制兩個伺服馬達,可用L293D或L298P直流電機驅動模組,如果要控制4個伺服馬達,可用CNC步進馬達控制驅動板,搭配 A4988或DRV8825;如果要控制4個伺服馬達,可用3D控制板套件,搭配 A4988或DRV8825。
如果超過上述的電機數量,就要改用PCA9685,PCA9685是一款16通道(可連接16個電機)12位 PWM I2C總線控制的伺服電機驅動模組,這個模組可以很容易地連接Arduino或樹莓派,並可以用簡易的程式來控制單個或多個伺服電機,如雙足或六足機器人等,或任何您想要的東西。

伺服馬達有三根電線從背面伸出,通常是橙色,紅色和棕色,但可能因伺服馬達而異。一條提供正電壓(+5 V,通常是紅色),黑色線接地,第三條橙色線提供PWM信號控制用,作為告訴電動機它應該旋轉哪個角度。


一般舵機大多使用50HZ的控制頻率,脈寬為0.5ms ~2.5ms,12位元解析度(4096),相關精度計算如下:
  • PWM週期: 1/50 sec =  0.02s = 20ms = 20000us
  • 時間解析度:20000 us / 4096 = 4.88us
  • 最大與最小脈寬時間差:2.5ms - 0.5ms = 2ms = 2000us 
  • 最大脈寬時間可分的份數:2000us / 4.88us = 410
  • 0-180度的舵機,角度解析度:180度 / 410 = 0.439度

[安裝Adafruit-PWM-Servo-Driver-Library]

本實作需要安裝以下程式庫:
程式庫(Library)安裝方法請參考另一篇文章:  Arduino筆記:安裝 Arduino IDE 程式庫(Library)

[Adafruit_PWMServoDriver函式庫]

瞭解上述這些概念後,我使用Adafruit 的 PWM Servo Device函式庫的函式來驅動伺服電機,這些驅動程序使用I2C進行通信,需要2個接腳(SDA、SCL)。以下是函式庫的用法說明:
  • setPWMFreq(freq)
   freq:代表以Hz為單位的頻率的數字,介於40和1600之間
此功能可用於調節 PWM 的頻率,這個頻率確定IC每秒產生多少個完整「脈衝」。也就是頻率決定了每個脈衝從開始到結束的持續時間有多長,同時考慮了脈衝的高段和低段。
頻率在 PWM 中很重要,因為在很小的佔空比下將頻率設置得太高會引起問題,因為信號的「上升時間」(從0V變為VCC所需的時間)可能比信號的上升時間更長。信號處於活動狀態,PWM 輸出將變得平滑,甚至可能無法達到 VCC,而導致許多問題。

  • setPWM(channel, on, off)
   channel:連接伺服馬達的通道值,介於0..15之間,亦即 PCA9685 上接伺服馬達排針的編號
   on:信號從低到高轉變時的標記(介於0..4095之間)
   off:信號從高電平轉換為低電平時的標記(介於0..4095之間)
此功能設置特定通道上PWM 脈衝的高電位開始和結束。您可以在信號開啟和關閉之間的0到4095之間指定「刻度」值。通道值是指定16個 PWM 輸出中的哪一個。

[接線圖]

PCA9685Arduino UNO
VCC5V
GNDGND
SDAA4(SDA)
SCLA5(SCL)




[程式]

以下程式以搖桿左右及上下控制伺服馬達的正轉或反轉,並判斷搖桿的X軸或Y軸是否移動來設定伺服馬達的位置。
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
 
// 呼叫伺服驅動程式函數,預設I2C位址為 0x40
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

#define MIN_PULSE_WIDTH       544
#define MAX_PULSE_WIDTH       2400
#define FREQUENCY             50

// 定義伺服機使用的輸出Port
int motorA = 0;

#define JoyX A0   // 搖桿 X 軸的接腳連接 Uno A0
#define JoyY A1   // 搖桿 Y 軸的接腳連接 Uno A1

void setup() {
  Serial.begin(9600);
  Serial.println("16 channel PWM test!");
  pwm.begin();
  pwm.setPWMFreq(FREQUENCY);  // This is the maximum PWM frequency
}
 
void loop() {

  int valX = analogRead(JoyX); // Read current value of Joystick 1 X axis
  int valY = analogRead(JoyY); // Read current value of Joystick 1 Y axis
  int pulse_wide, pulse_width;

  // 判斷搖桿X軸是否移動
  if (valX < 490 || valX > 510){
     // 將搖桿讀取的值轉換為高低脈衝間的對應值
     pulse_wide = map(valX, 0, 1023, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
  }
  // 判斷搖桿Y軸是否移動
  if (valY < 490 || valY > 510){
     // 將搖桿讀取的值轉換為高低脈衝間的對應值
     pulse_wide = map(valY, 0, 1023, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
  }
  // 轉換脈衝寬度
  pulse_width = int(float(pulse_wide) / 1000000 * FREQUENCY * 4096);
  Serial.print(pulse_wide);
  Serial.print("    ");
  Serial.println(pulse_width);
    
  // 讓伺服馬達移動到該位置 
  pwm.setPWM(motorA, 0, pulse_width);
}

[結果]




[參考資料]

Post a Comment

較新的 較舊