驱动——伺服电机的输出控制

我们将会编写程序, 并学习使用PWM控制伺服电机。

前言

伺服电机

伺服电机因其常用于航模控制方向舵变化,也常被称为舵机。 常用的SG90伺服电机,有三个接口,分别是:

  • 棕色: GND

  • 红色: VCC 4.8-7.2V

  • 桔色线: 脉冲输入

棕色接GND;红色接Robozone Board的5v;桔色接GPIO13;

../../../_images/servo_sg901.jpg ../../../_images/servo_jx.png

180度电机PWM控制的对应关系:

输入信号脉冲宽度—-舵机输出轴转角

0.5ms —- 0度

1.0ms —- 45度

1.5ms —- 90度

2.0ms —- 135度

2.5ms —- 180度

备注

脉冲宽度调制(英语:Pulse-width modulation,缩写:PWM), 简称脉宽调制,是将模拟信号变换为脉冲的一种技术,一般变换后脉冲的周期固定, 但脉冲的工作周期会依模拟信号的大小而改变。简单来说, PWM技术是一种对模拟信号电平的数字编码方法, 通过使用高分辨率计数器(调制频率)调制方波的占空比, 从而实现对一个模拟信号的电平进行编码。

编写代码

设置PWM占空比函数的参数。

int freq = 50;      // 1/50秒,50Hz的频率,20ms的周期,这个变量用来存储时钟基准。
int channel = 8;    // 通道(高速通道(0 ~ 7)由80MHz时钟驱动,低速通道(8 ~ 15)由 1MHz 时钟驱动。)
int resolution = 8; // 分辨率设置为8,就是2的8次方,用256的数值来映射角度,看下方的占空比函数。

定义占空比函数。

int calculatePWM(int degree) //定义函数用于输出PWM的占空比
{ //0-180度
//20ms周期内,高电平持续时长0.5-2.5ms,对应0-180度舵机角度,参考上面的180度对应图。
const float deadZone = 6.4;//对应0.5ms(0.5ms/(20ms/256))
const float max = 32;//对应2.5ms(2.5ms/(20ms/256))
if (degree < 0)
    degree = 0;
if (degree > 180)
    degree = 180;
return (int)(((max - deadZone) / 180) * degree + deadZone); //返回度数对应的高电平的数值
}

初始化中设置通道频率与分辨率,并将通道与引脚连接。

void setup()
    {
    Serial.begin(9600);
    ledcSetup(channel, freq, resolution); // 用于设置 LEDC 通道的频率和分辨率。
    ledcAttachPin(led, channel);          // 将通道与对应的引脚连接
    }

通过for循环实现伺服电机从0度转至180度,注意需要延时等待伺服电机转至位置。

void loop()
    {
    for (int d = 0; d <= 180; d += 10)
    {
        ledcWrite(channel, calculatePWM(d)); // 输出PWM,设置 LEDC 通道的占空比。
        Serial.printf("value=%d,calcu=%d\n", d, calculatePWM(d));
        delay(1000);
    }
    }

最后整个程序便是:

 1      #include <Arduino.h>
 2     int freq = 50;      // 1/50秒,50Hz的频率,20ms的周期,这个变量用来存储时钟基准。
 3     int channel = 8;    // 通道(高速通道(0 ~ 7)由80MHz时钟驱动,低速通道(8 ~ 15)由 1MHz 时钟驱动。)
 4     int resolution = 8; // 分辨率设置为8,就是2的8次方,用256的数值来映射角度,看下方的占空比函数。
 5     const int led = 13;
 6
 7     int calculatePWM(int degree) //定义函数用于输出PWM的占空比
 8     { //0-180度
 9     //20ms周期内,高电平持续时长0.5-2.5ms,对应0-180度舵机角度,参考上面的180度对应图。
10     const float deadZone = 6.4;//对应0.5ms(0.5ms/(20ms/256))
11     const float max = 32;//对应2.5ms(2.5ms/(20ms/256))
12     if (degree < 0)
13         degree = 0;
14     if (degree > 180)
15         degree = 180;
16     return (int)(((max - deadZone) / 180) * degree + deadZone); //返回度数对应的高电平的数值
17     }
18
19     void setup()
20     {
21     Serial.begin(9600);
22     ledcSetup(channel, freq, resolution); // 用于设置 LEDC 通道的频率和分辨率。
23     ledcAttachPin(led, channel);          // 将通道与对应的引脚连接
24     }
25
26     void loop()
27     {
28     for (int d = 0; d <= 180; d += 10)
29     {
30         ledcWrite(channel, calculatePWM(d)); // 输出PWM,设置 LEDC 通道的占空比。
31         Serial.printf("value=%d,calcu=%d\n", d, calculatePWM(d));
32         delay(1000);
33     }
34     }

上传单片机