使用 Arduino 控制伺服电机:实现完整的控制体系

1.什么是伺服电机?

伺服电机是一个闭环系统,它使用位置反馈来控制其运动和最终位置。伺服电机有多种类型,其主要特点是能够精确控制其轴的位置。

在工业型伺服电机中,位置反馈传感器通常是高精度编码器,而在较小的 RC 或业余伺服电机中,位置传感器通常是简单的电位器。这些设备捕获的实际位置被反馈到误差检测器,并与目标位置进行比较。然后控制器根据误差修正电机的实际位置,使其与目标位置相匹配。

在本教程中,我们将详细了解爱好伺服电机。我们将解释这些伺服系统如何工作以及如何使用 Arduino 控制它们。

Hobby 舵机是用于控制 RC 玩具汽车、船、飞机等的小型执行器。工科学生还使用它们来制作机器人原型、制造机械臂、仿生机器人、类人机器人等。

2.伺服电机如何工作?

伺服电机内部有四个主要组件,直流电机,齿轮减速器,电位器和控制电路。直流电机是高速、低扭矩的,但齿轮减速器(变速箱)可以将输出轴转动速度降低到 60 RPM(转每分钟) 左右,同时增加扭矩。

电位器安装在末级齿轮或输出轴上,因此随着电机旋转,电位器也随之旋转。电位器会产生与输出轴绝对角度相关的电压(输出轴转速越快,电位器的电压越大)。在控制电路中,完成电位器电压与来自信号线的电压进行比较。如果两者不相等,控制器会激活集成的 H 桥,使电机能够沿任一方向旋转,直到两个电压信号的差值达到零,此刻舵机达到目标位置,停止转动。

ps解释一下H桥电路:
通过H桥电路来完成电机的通断、正反控制。

通过信号线发送一系列脉冲来控制伺服电机。控制信号的频率应为 50Hz 或每 20ms 出现一个脉冲。脉冲宽度决定了伺服的角位置,这些类型的伺服电机通常可以旋转 180 度(它们有行程的物理限制)。
一般来说,1ms 持续时间的脉冲对应 0 度位置,1.5ms 持续时间对应 90 度,2ms 对应 180 度。尽管脉冲的最小和最大持续时间有时会因不同品牌而异,0 度位置为 0.5 毫秒,180 度位置为 2.5 毫秒。

3.适用于 Arduino 项目的流行 RC / Hobby Servos

RC 或爱好有许多不同的型号和制造商。选择伺服电机时
的主要考虑因素是其扭矩、工作电压、电流消耗和尺寸。

以下是制造商中最受欢迎的两种伺服型号,SG90 微型伺服和 MG996R。

SG90微型伺服技术规格:
堵转转矩 1.2kg·cm @4.8V, 1.6kg·cm @6V,
工作电压 3.5 – 6V
空载电流 100毫安
失速电流 650毫安
最大速度 0.12s 60 度
重量 9克

MG996R伺服技术规格:
堵转转矩 11kg.cm @4.8v, 13kg.cm @6V
工作电压 4.8 – 7.2V
空载电流 220mA @4.8V, 250mA @6V
失速电流 650毫安
最大速度 0.20 秒内 60 度
重量 55克

4.Arduino伺服电机控制

我将使用 MG996R,这是一款高扭矩伺服系统,具有金属齿轮,失速扭矩为 10 kgcm。高扭矩是有代价的,那就是伺服的失速电流,即 2.5A。运行电流从500mA到900mA,工作电压从4.8到7.2V。

电流额定值表明我们不能将此伺服直接连接到 Arduino(否则会烧坏arduino电路板),但我们必须为该舵机使用单独的电源。

5.伺服电机工作的电路原理图

我们只需要将舵机的控制引脚连接到Arduino板的任意数字引脚,将地线和正极线连接到外部5V电源,还将Arduino地连接到舵机地。

如果我们使用小舵机,S90 微型伺服,可以直接从 5V Arduino 引脚为其供电。
S90 Micro Servo 的电流消耗较低,空载运行电流约为 100-200mA,但失速电流约为 500-700mA。另一方面,如果通过 USB 供电,Arduino 5V 引脚只能输出大约 500mA,或者通过桶形连接器供电时最高 1A。

尽管可以将这些 9g 伺服电机直接运行到 Arduino,但为了更稳定的工作,我建议始终为它们使用外部电源。

6.伺服电机控制Arduino代码

现在让我们看一下控制伺服电机的Arduino代码。代码非常简单。我们只需要定义伺服连接的引脚,将该引脚定义为输出,并在循环部分生成具有特定持续时间和频率的脉冲,如前所述。

/*
     Servo Motor Control - 50Hz Pulse Train Generator
           by Dejan, https://howtomechatronics.com
*/

#define servoPin 9

void setup() {
  pinMode(servoPin, OUTPUT);
}

void loop() {
   // A pulse each 20ms
    digitalWrite(servoPin, HIGH);
    delayMicroseconds(1450); // Duration of the pusle in microseconds
    digitalWrite(servoPin, LOW);
    delayMicroseconds(18550); // 20ms - duration of the pusle
    // Pulses duration: 600 - 0deg; 1450 - 90deg; 2300 - 180deg
}

经过一些测试,我想出了以下值,用于与我的伺服一起工作的脉冲持续时间。持续时间为 0.6 毫秒的脉冲对应于 0 度位置,1.45 毫秒对应 90 度,2.3 毫秒对应 180 度。

我将万用表与伺服串联连接以检查电流消耗。我注意到的最大电流消耗在失速时高达 0.63A。那是因为这不是原来的 TowerPro MG996R 舵机,而是更便宜的复制品,显然性能更差。

不过,让我们看一下使用 Arduino 控制舵机的更方便的方法。那是使用 Arduino 伺服库。

/*
     Servo Motor Control using the Arduino Servo Library
           by Dejan, https://howtomechatronics.com
*/

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

void setup() {
  myservo.attach(9,600,2300);  // (pin, min, max)
}

void loop() {
  myservo.write(0);  // tell servo to go to a particular angle
  delay(1000);
  
  myservo.write(90);              
  delay(500); 
  
  myservo.write(135);              
  delay(500);
  
  myservo.write(180);              
  delay(1500);                     
}

在这里,我们只需要包含库,定义伺服对象,并使用 attach() 函数定义舵机连接的引脚以及定义脉冲持续时间的最小值和最大值。然后使用 write() 函数,我们只需将舵机的位置设置为 0 到 180 度。

7.使用 Arduino 控制多个伺服电机

Arduino 伺服库支持大多数 Arduino 板,并且单个arduino板同时最多可以控制 12 个伺服器,使用 Arduino Mega 板可同时控制 48 个伺服器。最重要的是,使用 Arduino 控制多个伺服电机就像控制一个伺服电机一样简单。

下面是控制多个舵机的示例代码:

/*
     Controlling multiple servo motors with Arduino
     by Dejan, https://howtomechatronics.com
*/

#include <Servo.h>

Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;
Servo servo5;

void setup() {
  servo1.attach(8);
  servo2.attach(9);
  servo3.attach(10);
  servo4.attach(11);
  servo5.attach(12);
}

void loop() {
  // move all servos to position 0
  servo1.write(0);
  servo2.write(0);
  servo3.write(0);
  servo4.write(0);
  servo5.write(0);
  delay(2000);

  // move all servos to position 90
  servo1.write(90);
  servo2.write(90);
  servo3.write(90);
  servo4.write(90);
  servo5.write(90);
  delay(2000);

  // move all servos to position 180
  servo1.write(180);
  servo2.write(180);
  servo3.write(180);
  servo4.write(180);
  servo5.write(180);
  delay(2000);
}

因此,我们只需为每个舵机从 Servo 类创建对象,并定义连接到哪个 Arduino 引脚。当然,我们可以设置任何舵机随时移动到任何位置。

例如,您还可以查看我的Arduino Ant Hexapod Robot项目,其中我使用 Arduino MEGA 板来控制 22 个伺服电机。

8.Arduino 和 PCA9685 PWM/伺服驱动器

还有另一种使用 Arduino 控制伺服系统的方法,那就是使用 PCA9685 伺服驱动器。这是一个 16 通道 12 位 PWM 伺服驱动器,它使用 I2C 总线与 Arduino 通信。它有一个内置时钟,因此它可以驱动 16 个伺服系统自由运行,或独立于 Arduino运动。

更酷的是,我们可以在单个 I2C 总线上以链接的方式连接多达 62 个PCA9685 伺服驱动器。所以理论上我们可以只使用 一块Arduino 板上的两个 I2C 引脚来控制多达 992 个舵机。6 个地址选择引脚用于为每个附加驱动器设置不同的 I2C 寻址。我们只需要根据此表连接焊盘。

这是电路原理图,我们需要为伺服系统提供单独的电源。
现在让我们看一下Arduino代码。为了控制这个伺服驱动器,我们将使用可以从GitHub下载的 PCA9685 库

Arduino 和 PCA9685 代码

/*
     Servo Motor Control using Arduino and PCA9685 Driver
           by Dejan, https://howtomechatronics.com
           
     Library: https://github.com/NachtRaveVL/PCA9685-Arduino
*/

#include <Wire.h>
#include "PCA9685.h"

PCA9685 driver;

// PCA9685 outputs = 12-bit = 4096 steps
// 2.5% of 20ms = 0.5ms ; 12.5% of 20ms = 2.5ms
// 2.5% of 4096 = 102 steps; 12.5% of 4096 = 512 steps
PCA9685_ServoEvaluator pwmServo(102, 470); // (-90deg, +90deg)

// Second Servo
// PCA9685_ServoEvaluator pwmServo2(102, 310, 505); // (0deg, 90deg, 180deg)


void setup() {
  Wire.begin();                 // Wire must be started first
  Wire.setClock(400000);        // Supported baud rates are 100kHz, 400kHz, and 1000kHz
  driver.resetDevices();        // Software resets all PCA9685 devices on Wire line

  driver.init(B000000);         // Address pins A5-A0 set to B000000
  driver.setPWMFrequency(50);   // Set frequency to 50Hz
}
void loop() {
  driver.setChannelPWM(0, pwmServo.pwmForAngle(-90));
  delay(1000);
  driver.setChannelPWM(0, pwmServo.pwmForAngle(0));
  delay(1000);
  driver.setChannelPWM(0, pwmServo.pwmForAngle(90));
  delay(1000);
}

首先我们需要包含库并定义 PCA9685 对象。然后使用 Servo_Evaluator 实例定义驱动器的脉冲持续时间或 PWM 输出。请注意,输出是 12 位的,或者说是 4096 步的分辨率。因此,0.5ms 或 0 度位置的最小脉冲持续时间对应 102 步,而 2.5ms 或 180 度位置的最大脉冲持续时间对应 512 步。但如前所述,这些值应根据您的伺服电机进行调整。值从 102 到 470,对应于 0 到 180 度的位置。
在设置部分,我们需要定义 I2C 时钟频率,设置驱动地址并将频率设置为 50Hz。
在循环部分,使用setChannelPWM()和pwmForAngle()函数,我们只需将伺服设置为所需的角度。
我将第二个伺服器连接到驱动器,正如我所料,它的定位与第一个不同,那是因为我使用的伺服器是廉价副本,它们不太可靠。然而,这不是一个大问题,因为使用Servo_Evaluator实例我们可以为每个伺服设置不同的输出设置。我们还可以调整 90 度位置,以防它不在中间。这样,所有伺服系统都将以相同的角度工作并定位。

9.使用 Arduino 和 PCA9685 驱动程序控制大量伺服系统

我们将再看一个示例,它使用多个链接的 PCA9685 驱动器控制大量伺服系统。

为此,我们需要将驱动器相互连接并连接适当的地址选择焊盘。下面是电路原理图:

现在让我们看一下Arduino代码。

/*
     Servo Motor Control using Arduino and PCA9685 Driver
           by Dejan, https://howtomechatronics.com
           
     Library: https://github.com/NachtRaveVL/PCA9685-Arduino
*/

#include <Wire.h>
#include "PCA9685.h"

PCA9685 driver;

// PCA9685 outputs = 12-bit = 4096 steps
// 2.5% of 20ms = 0.5ms ; 12.5% of 20ms = 2.5ms
// 2.5% of 4096 = 102 steps; 12.5% of 4096 = 512 steps
PCA9685_ServoEvaluator pwmServo(102, 470); // (-90deg, +90deg)

// Second Servo
PCA9685_ServoEvaluator pwmServo2(102, 310, 505); // (0deg, 90deg, 180deg)


void setup() {
  Wire.begin();                 // Wire must be started first
  Wire.setClock(400000);        // Supported baud rates are 100kHz, 400kHz, and 1000kHz
  driver.resetDevices();        // Software resets all PCA9685 devices on Wire line

  driver.init(B000000);         // Address pins A5-A0 set to B000000
  driver.setPWMFrequency(50);   // Set frequency to 50Hz
}
void loop() {
  driver.setChannelPWM(0, pwmServo.pwmForAngle(-90));
  delay(1000);
  driver.setChannelPWM(0, pwmServo.pwmForAngle(0));
  delay(1000);
  driver.setChannelPWM(0, pwmServo.pwmForAngle(90));
  delay(1000);
}

所以我们应该为每个舵机控制板创建单独的 PCA9685 对象,定义每个驱动程序的地址并将频率设置为 50Hz。现在只需使用 setChannelPWM() 和 pwmForAngle() 函数,我们就可以在任何驱动器上设置任何伺服来定位我们想要的任何角度。

10.故障排除

伺服电机抖动并且 Arduino 板被自动重置

这是使用SG90 Micro Servo 和 MG996R 舵机的常见问题。这样做的原因是,如前所述,它们在工作时会消耗相当大的电流。这可能会导致 Arduino 板重置,尤其是当您直接从 Arduino 5V 引脚为伺服供电时。

为了解决这个问题,您可以在 GND 和 5V 引脚之间使用一个电容器。它将充当去耦电容器,当直流电机启动时,它将在启动时为系统提供额外的电流。

伺服电机不会在 0 到 180 度的整个范围内移动

这是这些爱好伺服器的另一个常见问题。正如我们前面所解释的,1ms(0.5ms)的脉冲宽度对应于 0 度位置,2ms(2.5ms)对应于 180 度。但是,这些值可能因伺服和不同制造商而异。

为了解决这个问题,我们需要用 Arduino 调整发送到伺服电机的脉冲宽度。幸运的是,使用 Arduino Servo 库,我们可以轻松地在attach()函数中调整脉冲宽度值。

attach()函数可以采用两个附加参数,即最小和最大脉冲宽度(以微秒为单位)。最小(0 度)角度的默认值为 544 微秒(0.544 毫秒)和 2400 微秒(2.4 毫秒)。因此,通过调整这些值,我们可以微调伺服的力矩范围。

  myservo.attach(9,600,2300);  // (pin, min, max)

尺寸和 3D 模型

我制作了两种最流行的舵机: SG90 Micro Servo 和 MG996R 的 3D 模型。您可以从下面的链接下载加载它们。

SG90 微型舵机模型


MG996R舵机模型

MG996R 伺服电机 3D 模型:下载

11.结论

因此,我们几乎涵盖了我们需要了解的关于在 Arduino 中使用伺服电机的所有信息。当然,这类伺服电机的制造商和型号有很多,并且每个都有自己独特的功能,可能与我们上面解释的有所不同。

使用电机创建出色的机器人、自动化项目的可能性是无穷无尽的,但是为您的应用选择正确的模型非常重要。

我希望你喜欢这个教程并学到了一些新东西。随时在下面的评论部分提出任何问题,并确保您可以访问我的Arduino 项目集

12.常见问题 (FAQ)

如何在 Arduino 中使用舵机?

使用带有 Arduino 的伺服电机非常容易。伺服电机只有 3 根线,其中两根是 GND 和 5V 用于供电,第三根线是连接到 Arduino 板的控制线。

Arduino 可以运行舵机吗?

我们可以直接从 Arduino 运行伺服电机,但我们可能会遇到电源问题。如果伺服电机消耗超过 500mA 的电流,Arduino 板可能会断电并复位。最好始终为舵机使用单独的电源。

一个 Arduino 可以控制多少个伺服电机?

使用 Arduino Servo 库,大多数 Arduino 板最多可以控制 12 个伺服电机,使用 Arduino Mega 板控制最多可以控制 48 个伺服电机。不要忘记,我们需要为伺服电机使用单独电源(不要用Arduino 板给舵机供电)。

物联沃分享整理
物联沃-IOTWORD物联网 » 使用 Arduino 控制伺服电机:实现完整的控制体系

发表评论