ESP8266_Servo

faf4r發表於2024-03-31

Servo的使用,以SG90舵機為例

舵機控制說明 (Servo.h裡時間單位都是微秒us,角度是°)

舵機透過脈衝寬度的時間來控制(PWM),頻率是50Hz的(即一個週期是20ms)。(!!!脈寬是本質)

SG90舵機的控制引數範圍是:0°: 0.5ms , 180°: 2.5ms

然後對於每一度,將脈寬範圍除以180°即得。

servo.attach(GIO, pulse_width_min, pulse_width_max); 這裡就可以設定上面的脈寬min和max(出於安全考慮,Servo的預設值是1000,2000,導致實際執行時並不是滿的180°)

使用,實際就是設定脈寬:

servo.write(degree_OR_pulse_width_in_us);

當值<200時,引數為度數,根據上面除法得到每度的脈寬然後內部設定對應脈寬(範圍內);

超過200後,值代表脈寬(範圍內),直接寫入脈寬,和servo.writeMicroseconds()一樣。

注意超出範圍的值將被設為最低或最大值

舵機執行的實際脈寬:可用servo.read()檢視度數,servo.readMicroseconds()檢視實際脈寬。

總之,使用Servo的時候,要先確定自己舵機的pwm控制引數,然後在attach的時候設定好,才能得到對應的角度。

測試程式碼

#include <Servo.h>

Servo my_ser;

void setup()
{
    Serial.begin(115200);
    Serial.println();Serial.println();

    my_ser.attach(2, 500, 2500); //將舵機訊號連線到GPIO2, D4,設定高電平脈衝時間上下限(保證實際轉動角度的引數)
    my_ser.write(0);
    delay(100);
}

//展示了脈寬變化和對應的實際脈寬
void loop()
{
    //degree change
    for (int i = 0; i < 200; i+=1) {
      my_ser.write(i);
      Serial.printf("i: %d\tdegree: %d\tpulse_width_us: %d\n", i, my_ser.read(), my_ser.readMicroseconds());
      delay(200);
    }

    //pulse width change
    for (int i = 200; i < 2600; i+=1) {
      my_ser.write(i);  //等價於my_ser.writeMicroseconds(i);
      Serial.printf("i: %d\tdegree: %d\tpulse_width_us: %d\n", i, my_ser.read(), my_ser.readMicroseconds());
      delay(200);
    }
}

用analog直接控制脈衝

analogWriteFreq(freq);:設定頻率,一般50Hz

analogWriteRange(range);:設定步長,即將一個週期分成多少份,使用時的單位就是份數了

analogWrite(PIN, value);:將PIN的脈寬設為value份數。取值範圍為(0, range),實際就是設定脈寬多少

#include <Servo.h>

const uint8_t servo = 2;  //舵機在GPIO2
Servo my_ser;

void setup() {
  Serial.begin(115200);
  Serial.println();

  analogWriteFreq(50);    //設定頻率為50Hz,即週期20ms
  analogWriteRange(200);  //將20ms分成200份,每份0.1ms

  my_ser.attach(servo);
  
  analogWrite(servo, 5);  //初始化
  delay(500);
  analogWrite(LED_BUILTIN, 200);
  delay(200);
}

void loop() {
  for (int i = 5; i < 26; i++) {
    analogWrite(servo, i);
    Serial.printf("i: %d\tdegree: %d\tpulse_width_us: %d\n", i, my_ser.read(), my_ser.readMicroseconds());
    delay(1000);
  }
}

值得注意的是,輸出始終為i: i可變 degree: 90 pulse_width_us: 1500,而其它值不變,沒試my_ser.write,但是用analog就沒什麼必要了,且它的read都不可用了的樣子,值一直不變。

參考資料

程式碼裡的Servo.h

另外,arduino常有不程式碼提示的問題,我看網上說好像要把專案放在設定裡那個位置才行,不過有時候又可以,我又懶得放那,就沒試了。

analog:[【萬物皆可PWM!使用ESP8266驅動SG90舵機!】