电机控制
电机是 Arduino 项目中最常用的执行器之一。本章将介绍三种常见电机的控制方法:直流电机、舵机和步进电机。
直流电机控制
直流电机是最简单的电机类型,通过改变电压大小和极性来控制转速和方向。
为什么需要电机驱动
Arduino 的 IO 引脚只能提供约 40mA 电流,而直流电机通常需要几百毫安。因此需要电机驱动模块。
L298N 电机驱动模块
L298N 是最常用的双路电机驱动模块,可同时控制两个直流电机。
硬件连接:
L298N ENA ── D9(PWM 调速)
L298N IN1 ── D8(方向控制)
L298N IN2 ── D7(方向控制)
L298N OUT1 ── 电机 A 正极
L298N OUT2 ── 电机 A 负极
L298N +12V ── 外部电源正极(7-12V)
L298N GND ── 外部电源负极 + Arduino GND
L298N +5V ── 可选,给 Arduino 供电
代码示例
const int ENA = 9; // PWM 调速
const int IN1 = 8; // 方向控制
const int IN2 = 7; // 方向控制
void setup() {
pinMode(ENA, OUTPUT);
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
Serial.begin(9600);
}
void loop() {
Serial.println("正转,全速");
motorForward(255);
delay(2000);
Serial.println("停止");
motorStop();
delay(1000);
Serial.println("反转,半速");
motorBackward(128);
delay(2000);
Serial.println("停止");
motorStop();
delay(1000);
// 加速测试
Serial.println("加速测试");
for (int speed = 0; speed <= 255; speed += 5) {
motorForward(speed);
delay(100);
}
motorStop();
delay(1000);
}
// 正转
void motorForward(int speed) {
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(ENA, speed);
}
// 反转
void motorBackward(int speed) {
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
analogWrite(ENA, speed);
}
// 停止(刹车)
void motorStop() {
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
analogWrite(ENA, 0);
}
// 自由停止(惯性滑行)
void motorCoast() {
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
}
舵机控制
舵机(Servo)可以精确控制角度,常用于机器人关节、航模控制等。
舵机工作原理
舵机通过 PWM 信号控制角度:
- 0.5ms 脉冲 = 0°
- 1.5ms 脉冲 = 90°
- 2.5ms 脉冲 = 180°
硬件连接
舵机红线(VCC)── 5V(外部电源推荐)
舵机棕线(GND)── GND
舵机黄线(SIG)── D9(PWM 引脚)
电源提示
多个舵机同时工作时,不要使用 Arduino 的 5V 供电,应使用外部 5V 电源。
代码示例
#include <Servo.h>
Servo myServo;
const int SERVO_PIN = 9;
void setup() {
myServo.attach(SERVO_PIN);
Serial.begin(9600);
// 初始化到中间位置
myServo.write(90);
Serial.println("舵机初始化完成");
}
void loop() {
// 从 0 度转到 180 度
Serial.println("0° -> 180°");
for (int angle = 0; angle <= 180; angle++) {
myServo.write(angle);
delay(15); // 给舵机足够时间转动
}
delay(500);
// 从 180 度转回 0 度
Serial.println("180° -> 0°");
for (int angle = 180; angle >= 0; angle--) {
myServo.write(angle);
delay(15);
}
delay(500);
}
电位器控制舵机
#include <Servo.h>
Servo myServo;
const int SERVO_PIN = 9;
const int POT_PIN = A0;
void setup() {
myServo.attach(SERVO_PIN);
Serial.begin(9600);
}
void loop() {
int potValue = analogRead(POT_PIN);
// 将 0-1023 映射到 0-180
int angle = map(potValue, 0, 1023, 0, 180);
myServo.write(angle);
Serial.print("电位器: ");
Serial.print(potValue);
Serial.print(" | 角度: ");
Serial.println(angle);
delay(15);
}
多舵机控制
Arduino Uno 可以同时控制最多 12 个舵机(使用 Servo 库):
#include <Servo.h>
Servo servo1;
Servo servo2;
Servo servo3;
void setup() {
servo1.attach(9);
servo2.attach(10);
servo3.attach(11);
}
void loop() {
// 同时控制多个舵机
servo1.write(0);
servo2.write(90);
servo3.write(180);
delay(1000);
servo1.write(90);
servo2.write(0);
servo3.write(90);
delay(1000);
}
步进电机控制
步进电机可以精确控制转动角度,适合需要精确定位的应用。
28BYJ-48 步进电机 + ULN2003 驱动板
这是最常用的步进电机组合,价格低廉,适合入门。
硬件连接:
ULN2003 IN1 ── D8
ULN2003 IN2 ── D9
ULN2003 IN3 ── D10
ULN2003 IN4 ── D11
ULN2003 + ── 5V
ULN2003 - ── GND
代码示例
const int IN1 = 8;
const int IN2 = 9;
const int IN3 = 10;
const int IN4 = 11;
// 单四拍步序
const int steps[] = {0b1000, 0b0100, 0b0010, 0b0001};
// 双四拍步序(扭矩更大)
// const int steps[] = {0b1100, 0b0110, 0b0011, 0b1001};
// 八拍步序(更平滑)
// const int steps[] = {0b1000, 0b1100, 0b0100, 0b0110, 0b0010, 0b0011, 0b0001, 0b1001};
const int numSteps = 4;
int currentStep = 0;
void setup() {
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(IN3, OUTPUT);
pinMode(IN4, OUTPUT);
Serial.begin(9600);
}
void loop() {
Serial.println("正转一圈");
rotate(2048, true); // 28BYJ-48 一圈约 2048 步
delay(1000);
Serial.println("反转半圈");
rotate(1024, false);
delay(1000);
}
// 转动指定步数
void rotate(int steps, bool clockwise) {
for (int i = 0; i < steps; i++) {
stepMotor(clockwise);
delay(2); // 控制速度
}
}
// 单步执行
void stepMotor(bool clockwise) {
if (clockwise) {
currentStep++;
} else {
currentStep--;
}
currentStep = (currentStep + numSteps) % numSteps;
int pattern = steps[currentStep];
digitalWrite(IN1, pattern & 0b1000);
digitalWrite(IN2, pattern & 0b0100);
digitalWrite(IN3, pattern & 0b0010);
digitalWrite(IN4, pattern & 0b0001);
}
使用 Stepper 库
Arduino 内置 Stepper 库简化步进电机控制:
#include <Stepper.h>
// 28BYJ-48 一圈的步数
const int STEPS_PER_REV = 2048;
// 创建步进电机对象,参数为每圈步数和引脚
Stepper myStepper(STEPS_PER_REV, 8, 10, 9, 11);
void setup() {
// 设置转速(RPM)
myStepper.setSpeed(10);
Serial.begin(9600);
}
void loop() {
Serial.println("顺时针转一圈");
myStepper.step(STEPS_PER_REV);
delay(1000);
Serial.println("逆时针转半圈");
myStepper.step(-STEPS_PER_REV / 2);
delay(1000);
}
综合示例:机械臂控制
使用多个舵机控制简单机械臂:
#include <Servo.h>
Servo baseServo; // 底座旋转
Servo shoulderServo; // 肩部
Servo elbowServo; // 肘部
Servo gripperServo; // 夹爪
void setup() {
baseServo.attach(9);
shoulderServo.attach(10);
elbowServo.attach(11);
gripperServo.attach(12);
Serial.begin(9600);
Serial.println("机械臂初始化完成");
// 复位到初始位置
moveToPosition(90, 90, 90, 0);
}
void loop() {
// 示例动作序列
Serial.println("动作 1:抓取");
moveToPosition(45, 120, 60, 0); // 移动到物体上方
delay(500);
moveToPosition(45, 100, 80, 0); // 下降
delay(500);
gripperServo.write(90); // 夹紧
delay(500);
moveToPosition(45, 120, 60, 90); // 抬起
delay(1000);
Serial.println("动作 2:放置");
moveToPosition(135, 120, 60, 90); // 移动到放置点
delay(500);
moveToPosition(135, 100, 80, 90); // 下降
delay(500);
gripperServo.write(0); // 松开
delay(500);
moveToPosition(135, 120, 60, 0); // 抬起
delay(2000);
}
// 平滑移动到指定位置
void moveToPosition(int base, int shoulder, int elbow, int gripper) {
// 使用简单的线性插值实现平滑移动
int startBase = baseServo.read();
int startShoulder = shoulderServo.read();
int startElbow = elbowServo.read();
int startGripper = gripperServo.read();
int steps = 20; // 插值步数
for (int i = 0; i <= steps; i++) {
float t = (float)i / steps;
baseServo.write(startBase + (base - startBase) * t);
shoulderServo.write(startShoulder + (shoulder - startShoulder) * t);
elbowServo.write(startElbow + (elbow - startElbow) * t);
gripperServo.write(startGripper + (gripper - startGripper) * t);
delay(20);
}
}
电机选择指南
| 电机类型 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 直流电机 | 转速高、成本低 | 无法精确定位 | 车轮驱动、风扇 |
| 舵机 | 角度精确控制 | 转动范围有限 | 机械臂、航模 |
| 步进电机 | 精确步进、可定位 | 转速较低 | 3D 打印机、CNC |
电源注意事项
电流需求参考
| 设备 | 典型电流 | 建议电源 |
|---|---|---|
| 小舵机(9g) | 100-250mA | Arduino 5V |
| 标准舵机 | 500mA-1A | 外部 5V 2A |
| 大扭矩舵机 | 2-3A | 外部 5V 5A |
| 直流电机 | 500mA-2A | 外部 7-12V |
| 步进电机 | 100-500mA | 外部 5V 2A |
电源接线示例
外部电源 5V 2A ──┬── 舵机 VCC
├── L298N +12V
外部电源 GND ────┬── 舵机 GND
├── L298N GND
├── Arduino GND(必须共地)
Arduino 5V ────── 传感器、逻辑电路
Arduino GND ───── 传感器、逻辑电路
下一步
掌握了电机控制后,我们将学习如何使用各种显示设备,如 LCD、OLED 和数码管。