跳到主要内容

电机控制

电机是 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-250mAArduino 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 和数码管。