Arduino 步进电机 vs 舵机:三种马达该怎么选?

Cartoon row of four motors on white: a silver drum stepper with a blue wire block and five coloured wires, a bright translucent-blue SG90 servo, a black MG996R servo with a pink label and silver metal gear, and a small silver-and-brass N20 gear motor with two bare copper solder tabs

要让一个部件转到某个已知角度、并且停在那里,就买舵机 —— 闸门臂、机械臂关节、云台。要让它转到一个数出来的位置、要能一圈一圈转下去、或者要顶着负载停住,就买步进电机 —— 刻度盘、滑台、送料机构。只在乎转速和方向,那就买一颗普通的直流减速电机 —— 轮子、风扇、水泵。

价钱不是决胜的那一项 —— 这三个家族回答的是不同的问题,而要最快感受到差别,就是用手轻轻推一推它们各自的输出轴。

步进电机、舵机和直流电机,真正的分别在哪里?

SG90 这样的 RC 舵机,是四样东西装在同一个壳子里:一颗小直流电机、一组齿轮、一个和输出轴联动的电位器,还有一颗负责比较的芯片。你每 20 ms 送一个脉冲,脉冲的宽度 —— 大约 1.0 ms 到 2.0 ms —— 代表一个角度。芯片拿这个宽度去和电位器的电压比,然后驱动电机,直到两边对上为止。把舵臂推离它的角度,电位器的电压跟着走,比较就失衡,舵机自己又把它推回去。这个回路同时也是它的极限:电位器只能转那么多,所以一颗 180° 的舵机不可能连续旋转,而壳子外面也没有任何东西读得到轴最后停在哪里。要做那个推的动作之前先讲一句:是轻轻拨,不是硬掰。SG90 的齿轮是尼龙的,顶着通电的电机硬掰会崩掉一颗齿 —— 而这正是 MG996R 的金属齿轮卖的那份耐受。舵盘上没装舵臂的话,折一小条美纹纸胶带就是现成的杠杆。

28BYJ-48 步进电机身上一个传感器都没有。它的转子是一块永久磁铁,四周围着线圈;按顺序给线圈通电,转子就一次一次跳到新的磁性对齐位置上,切换一次走一步。它的扭力来自一组通着电的线圈把转子按在磁定位点里,而不是来自一个纠正回路 —— 这就是为什么步进电机通电时有真正的保持扭力,也是为什么用手推它的感觉像在推一个带段落感的旋钮。让它过载,转子就滑掉一格:你程序里的步数照样往上加,没有任何东西会报告这次打滑,而这个误差会一直留在机器里,直到你重新回零为止。

GA12-N20 减速电机则是彻底放弃了位置这件事。两个端子之间加电压,轴就转;端子对调,轴就反着转;用 PWM 把电压切碎,它就慢下来。推它的轴,它就顺着转 —— 它身上没有任何东西对角度有意见。换来的是你能买到的最便宜的连续旋转,而它的减速箱把一颗又快又软的电机,换成了一颗又慢又有力的。

家族 你下的命令 旋转 保持扭力 知道自己在哪吗? 什么时候买它
28BYJ-48 步进电机 + ULN2003 一个步数 不限圈数,正反皆可 有,通电时 不知道 —— 开环,打滑也不出声 刻度盘、滑台、送料机构,任何要转超过一圈才到位的东西
SG90 微型舵机 一个绝对角度 大约 180°,再多没有 有,而且会主动纠正 内部知道,外部读不到 轻负载摇臂、翻板、锁扣、云台 —— 4.8 V 下大约 1.3 kg·cm
MG996R 金属齿舵机 一个绝对角度 大约 180°,再多没有 有,而且大得多 内部知道,外部读不到 同样的活,但真的带得动负载 —— 6 V 下大约 11 kg·cm,金属齿轮
GA12-N20 直流减速电机 转速和方向 不限圈数,正反皆可 没有 不知道,也不可能知道 轮子、风扇、水泵、输送带 —— 任何不问「转多远」的地方

做一次台面试验会用到的东西

ItemPriceQty
Arduino Uno Compatible SMD UNO R3 with Type B Cable - ATMEGA328P with CH340G-Microcontroller ProjectArduino Uno Compatible SMD UNO R3 with Type B Cable - ATMEGA328P with CH340G-Microcontroller ProjectUNOCH34RM22.90
L298N Motor Driver Module Arduino Compatible Dual H Bridge Dual DC Motor Control Arduino Robotic CarL298N Motor Driver Module Arduino Compatible Dual H Bridge Dual DC Motor Control Arduino Robotic CarLN298NBRM7.20
40pcs Dupont Wire 10cm 20cm 30cm for Breadboard DIY Experiment Jumper Wire Breadboard wire - DUPONT WIRE M-M 20CM40pcs Dupont Wire 10cm 20cm 30cm for Breadboard DIY Experiment Jumper Wire Breadboard wire - DUPONT WIRE M-M 20CMDPWMM20RM3.50
40pcs Dupont Wire 10cm 20cm 30cm for Breadboard DIY Experiment Jumper Wire Breadboard wire - DUPONT WIRE M-F 20CM40pcs Dupont Wire 10cm 20cm 30cm for Breadboard DIY Experiment Jumper Wire Breadboard wire - DUPONT WIRE M-F 20CMDPWMF20RM3.20
Data Cable Type-A Type-C MicroUSB Type-B 0.5m 1m 30cm 0.3m 100cm Data Transfer Upload Code - TYPE-A TO TYPE-B (1.0M)Data Cable Type-A Type-C MicroUSB Type-B 0.5m 1m 30cm 0.3m 100cm Data Transfer Upload Code - TYPE-A TO TYPE-B (1.0M)ATBC100RM4.90

一块 Uno 就能把四颗电机全部带起来。步进电机自己带 ULN2003 驱动板,所以要另外加的驱动只有给直流电机用的 L298N —— 螺丝端子加已经焊好的排针,没有东西要自己焊。杜邦线两种公母都拿:驱动板露出来的是公针,要公对母;舵机那一头是母座,要公对公。Type-B 线就是 Uno 用的那一条。

选错家族之后,下一个最常犯的错就是选错行程范围,而180° / 270° / 360° 舵机的分别那一篇专门解决这一题。先看舵机壳子里面实际上装了些什么:

卡通三格图:一支青色箭头分别去推每一颗电机上的白色拨杆 —— 半透明蓝色舵机的拨杆被弹回原位,银色步进电机的拨杆掉到虚线轮廓下方一格并带一个橙色警示,银色配黄铜的 N20 电机的拨杆则自由甩开
推一推就知道。舵机被推离角度会自己顶回来;步进电机先撑住,然后无声地滑掉一格,而且从来不告诉你;直流电机就只是顺着转。

一块 Arduino Uno 到底能带几颗电机?

Arduino Uno 有两本预算 —— 引脚和电流 —— 谁小谁说了算。引脚这本好数:14 个数字脚,加上 6 个可以当数字脚用的模拟脚,是 20 个,扣掉给 USB 串口的 D0 和 D1,剩 18 个。一块 ULN2003 步进驱动板吃 4 个,所以四颗步进电机装得下,还多出两个脚。一颗舵机吃 1 个脚,但 Arduino Servo 库在 Uno 上最多只支持 12 颗,而且从第一次调用 attach() 那一刻起,D9 和 D10 上的 analogWrite() 就失效 —— 不管那两个脚上有没有插舵机。一颗直流电机要两个方向脚加一个 PWM 脚,而且一定要经过驱动板 —— 绝不能直接接引脚,因为 Uno 的引脚额定只有 20 mA,而连一颗小小的 N20 堵转时都要抽几百毫安。

真正卡住你的那本预算是电流,而步进电机这个数字值得自己算一遍。28BYJ-48 每一组线圈的电阻大约 50 Ω,所以 5 V 下一组线圈大约抽 100 mA,而系统自带的 Stepper 库在每一步都保持两组线圈通电 —— 就算每颗电机大约 200 mA,转着要抽,只是停在那里保持也照样抽。表里 MG996R 的电流是 TowerPro 自己给的数字SG90 的规格书整份是围着扭力和速度写的,所以它那一行用的是典型实测电流。USB 给整块板的额度是 500 mA,这个数字由电脑那个端口,以及 Uno 插座后面那颗自恢复保险丝一起定死。圆形电源座那一路,5 V 的额度也不会更大:它后面是一颗小小的线性稳压器,把多出来的电压全部烧成热 —— 输入 9 V 时,每 100 mA 就烧掉大约 0.4 W —— 而输入 5 V 时它已经没有余量,只会把整块板拉到欠压复位。

所以解法从来不是换一块更大的板,而是加第二组电源 —— 电机走自己的 5–6 V 电源,只有信号线接到 Uno,两边的地接在一起,让脉冲有共同的参考点。ULN2003 板和 L298N 上都留了电源端子,就是给这件事用的。步进电机那一路的电压守在 5 V:ULN2003 芯片本身扛得住的电压高得多,但 28BYJ-48 是 5 V 的绕组,多出来的电压变成热,不会变成扭力。舵机一多过几颗,就把产生脉冲这件事整个搬出 Uno,交给一块 PCA9685 16 路驱动板,它自己带舵机电源输入。

家族 每颗吃几个脚 每颗吃多少电流 Uno 上的引脚上限 USB 供电下的现实上限
步进电机(ULN2003 驱动板) 4 个数字脚 约 200 mA,转与不转都一样 4 1
SG90 微型舵机 1 个(库上限 12) 转动时 100–250 mA,堵转约 360 mA 12 同一时间只动 1 颗
MG996R 金属齿舵机 1 个(库上限 12) 6 V 下 500–900 mA,堵转 2.5 A 12 0 —— 一定要自己的电源
直流电机(经 L298N) 2–3 个 几百毫安,堵转更多 6,按每块 L298N 带 2 颗算 0 —— 电机电源本来就是分开的
卡通对比图:左边一块蓝色 Arduino 板接着 USB,四颗半透明蓝色舵机的电全部从它身上拿,配一个橙色叉;右边同一块板,改由一个黑色电池盒用粗的红黑线直接喂舵机,只有细的橙色信号线接回板子,配一个青色勾
信号回板子,电从自己的电源来。四颗舵机全靠一块 USB 供电的 Uno 喂,一定把它拉到欠压复位;给它们一组电池,板子上只留信号线,然后把地接在一起。

这三个家族,实际上各自怎么下命令?

一块 Arduino Uno 可以在同一份程序里讲三种语言,下面这份就是:给舵机一个绝对角度,给步进电机一个步数,给直流电机一个方向加一个占空比。其中有三个细节,很多人是拿整个晚上换来的。第一,系统自带的 Stepper 库当初是为双极性电机写的:它把你给的四个脚当成 A+、A−、B+、B− 来看,按第 1+第 3、第 2+第 3、第 2+第 4、第 1+第 4 的配对去通电。而单极性的 28BYJ-48 要的是相邻且互相重叠的配对 —— IN1+IN2、IN2+IN3、IN3+IN4、IN4+IN1 —— 所以 IN1–IN4 照样接 D4–D7,但在程序里要写成 4, 6, 5, 7,这一步就是把一种时序映射成另一种。照数字顺序写下去,库通的那两组线圈会把转子往相反方向拉,电机就只会在原地嗡嗡响。

第二,直流电机的 PWM 脚是 D3,不是 D9 或 D10,因为一旦挂上舵机,Servo 库就把 Timer1 —— 也就是那两个脚背后的定时器 —— 拿走了。第三,在你指望 analogWrite() 有意义之前,先把 L298N 上 ENA 那颗跳线帽拔掉:那颗帽子把 ENA 长期接到板子自己的 5 V 上,于是不管你给多少占空比,电机都全速在跑 —— 一种不会报错、只会安静失效的调速。

还要注意步进电机那一行讲不出什么。stepper.step(512) 的意思是「把线圈切换 512 次」,不是「到达四分之一圈」—— 而且 28BYJ-48 的减速比接近 63.7:1,不是整数的 64:1,所以输出轴转一整圈大约是 2038 步,不是 2048 步;照那个整数去下命令,就算一步都没滑,你也会停在比原本想去的位置多大约两度的地方。步进电机是数出来的,不是量出来的;这件事要紧的场合,就加一个限位开关,回零之后再算。另外注意 stepper.step() 是阻塞的,最后一步发出去之前它不会返回,所以那段时间 loop 里其他事情全部停着 —— 一块 Uno 指挥三个家族,靠的是轮流,不是同时。

// 三个家族,三种下令方式 - Arduino UNO。
//
// Servo   :你送一个绝对角度。舵机自己找到它,并且守在那里。
// Stepper :你送一个步数。没有任何东西回报它到底有没有到。
// DC      :你送一个速度和一个方向。位置根本不在这门语言里。
//
// 电源:三颗电机全部走外部 5V 电源,不要从 Uno 的 5V 脚拿电,
// 并且把那组电源的地接到 Uno 的 GND,控制信号才有共同的参考点。

#include <Servo.h>
#include <Stepper.h>

// --- Stepper:28BYJ-48 配 ULN2003 驱动板 ------------------------------------
// 内部转子每转一圈 32 个整步,再乘上减速箱。真实的减速比是
// 63.68:1,不是整数的 64:1,所以输出轴转一圈大约 2038 步 - 这里沿用
// 惯例上的 2048,会多转大约两度。
const int STEPS_PER_REV = 2048;

// 注意顺序:Stepper 库要的是 IN1、IN3、IN2、IN4。
// IN1..IN4 接到 D4..D7,但要写成 4, 6, 5, 7,否则电机只会嗡嗡响。
Stepper stepper(STEPS_PER_REV, 4, 6, 5, 7);

// --- Servo ------------------------------------------------------------------
const int PIN_SERVO = 9;      // attach() 把 Timer1 交给 Servo,所以整份程序里
Servo arm;                    // 引脚 9 和 10 上的 analogWrite() 都会失效。

// --- DC 电机,经 L298N -------------------------------------------------------
const int PIN_DC_EN = 3;      // ENA - PWM,走 Timer2,Servo.h 不会碰它。
                              // 记得拔掉 L298N 的 ENA 跳线帽,否则这个脚不起作用。
const int PIN_DC_A  = 2;      // IN1
const int PIN_DC_B  = 8;      // IN2

void setup() {
  Serial.begin(9600);

  stepper.setSpeed(10);       // 输出轴的转速,单位 rev/min

  arm.attach(PIN_SERVO);
  arm.write(90);              // 先停在行程的中间

  pinMode(PIN_DC_EN, OUTPUT);
  pinMode(PIN_DC_A,  OUTPUT);
  pinMode(PIN_DC_B,  OUTPUT);

  Serial.println(F("Servo = angle, stepper = steps, DC = speed"));
}

void loop() {
  // 1. SERVO - 在一段固定行程里的绝对位置。
  Serial.println(F("servo -> 0 deg"));
  arm.write(0);
  delay(700);
  Serial.println(F("servo -> 180 deg"));
  arm.write(180);
  delay(700);
  arm.write(90);
  delay(700);

  // 2. STEPPER - 数出来的步数,总转动量不受限,没有任何反馈。
  Serial.println(F("stepper -> +512 steps (a quarter turn, if nothing slipped)"));
  stepper.step(512);
  delay(400);
  Serial.println(F("stepper -> -512 steps back"));
  stepper.step(-512);
  delay(400);

  // 3. DC MOTOR - 方向脚决定往哪边转,PWM 决定用多大力。
  Serial.println(F("dc -> forward, about 60% duty"));
  digitalWrite(PIN_DC_A, HIGH);
  digitalWrite(PIN_DC_B, LOW);
  analogWrite(PIN_DC_EN, 160);        // 供电电压的 160/255,不是「60% 的转速」
  delay(1500);

  Serial.println(F("dc -> coast"));
  analogWrite(PIN_DC_EN, 0);
  delay(1200);
}

亲眼看一次 28BYJ-48 真的一步一步走,顺便听一听引脚顺序写错是什么声音,可以省掉很多瞎猜:

28BYJ-48 的五条线收在一个防呆插头里,直接按上它的 ULN2003 板,所以这一对不需要另外配线。舵机那一头是母座,要配公对公杜邦线;ULN2003 和 L298N 露出来的是公针,要配公对母。要提前打算的是 N20:它到手是光的,黑色端盖上两片铜焊片,一条线都没有,所以要留几分钟拿烙铁 —— 手法在我们的烙铁与助焊剂指南里。3–6 V 的电机,用一块 DRV8833 双路驱动比 L298N 合适:L298N 的双极性输出级在 1 A 时会掉 1.8 V 到 3.2 V,电机才轮得到剩下的 —— 在 5 V 的电源上,就是三分之一到三分之二的电压在轴动起来之前已经变成热。DRV8833 自己那排排针是散着发的,所以它一样要花掉和 N20 同样的那点烙铁时间。

卡通三张特写:五条彩色步进电机线收在一个白色防呆插头里,正对上绿色驱动板上的白色插座;棕红橙三色的舵机线尾端是一个黑色三孔母座,正接上三根公针;一颗小银色电机的黑色端盖上有两片光铜焊片,旁边散着已经上锡的线头、一支烙铁和焊锡
三种完全不同的接法:步进电机的白色五针插头往绿色驱动板上一按就好,舵机线是一个吃公针的母座,而 N20 到手只有两片光铜焊片,一条线都没有。

步进电机的线圈,该串联还是并联?

步进电机的线圈要串联还是并联,是一个真实存在的选择,但只出现在把每一相绕组的两个半边分别引出来的电机上 —— 也就是八线的双极性电机,通常是 NEMA 机座那一类。把一相的两个半边串起来,这一相的电阻翻倍,电感大约变成四倍,因为电感和匝数的平方成正比:驱动器只要一半的电流就能给出同样的磁拉力,但在同样的驱动电压下,电流建立起来慢得多,所以步进频率一往上走,扭力就先垮下去。把它们并起来,电感掉到串联时的大约四分之一,而驱动器要推大约两倍的电流 —— 静止时的扭力一样,速度上去以后的扭力曲线却平坦得多。所以:要用一块普通驱动器在低速下拉得动,选串联;要速度,选并联。

28BYJ-48 不在这个选择里。它是一颗五线的单极性电机 —— 一条公共的红线接到电源,另外四条线圈端由 ULN2003 逐一拉到地 —— 根本没有第二个半绕组可以让你换接法。如果你的项目真的需要串联还是并联这个决定,那它需要的是一颗八线双极性步进电机加一块斩波恒流驱动器;如果不需要,就用 28BYJ-48 原本配的那块 ULN2003 板 —— 我们的 28BYJ-48 逐步教程把那套接线从插上插头一路带到第一次转动。

我们从真实客户身上看到的常见错误

买一颗 180° 舵机去带轮子。定位舵机内部有机械限位,也有一个会到头的电位器;不管你送什么脉冲,它都不可能连续旋转。轮子要的是直流减速电机,或者一颗本来就设计成连续旋转的舵机。

直接从 Uno 的 5 V 脚给电机供电。板子做到一半自己重启、舵机一直抖,最常见的原因就是这个:启动电流和堵转电流把 5 V 那条电源拉到单片机的欠压门槛以下。

以为步进电机知道自己在哪。卡过一次料,或者遇到一个它跟不上的步进频率之后,程序里的步数和轴的真实位置就对不上了,而且没有任何东西会提示你。要么在设计里加一个回零开关,要么接受这份漂移。

买了一颗裸电机,却没有东西接得上去。N20 到手是两片焊片,一条线都没有 —— 要么把烙铁的时间算进去,要么挑一颗原厂就带线的电机。

常见问题

Arduino 用步进电机还是舵机,该选哪一个?

要「转到这个角度然后守住」,而且在大约 180° 以内,用舵机;要「转一个数出来的量」,或者要超过一圈,用步进电机。舵机会自我纠正,因为它量得到自己的轴;步进电机什么都不量,所以它可以一直转下去,但会无声地丢步。

一块 Arduino 可以控制几颗步进电机?

论引脚,Uno 装得下四块 ULN2003 板 —— 18 个可用脚,每块吃 4 个 —— 但靠 USB 供电只有一颗跑得舒服。每颗 28BYJ-48 持续抽大约 200 mA,所以四颗需要一组大约 1 A 的外部 5 V 电源,地要和 Uno 接在一起。

步进电机的线圈该串联还是并联?

串联在低速下用更小的驱动电流换到更大的扭力;并联要大约两倍的电流,但在较高的步进频率下扭力守得住。这个选择只存在于八线的双极性步进电机上。28BYJ-48 是五线单极性的,两种接法都做不了。

步进电机一般用来做什么?

任何既要转到一个可重复的位置、又要转得比舵机那段行程更远的场合:打印机和扫描仪的机构、3D 打印机的轴、相机滑轨、旋转显示装置、阀门、分配器和刻度指示盘。而停下来时还有保持扭力,往往才是它真正被选中的原因。

步进电机比直流电机好在哪里?

不用任何传感器就能定位,因为每一个脉冲都是一个已知的增量;停下来时有真正的保持扭力,而直流电机完全没有;还有不靠减速箱就能跑得又慢又稳。代价是要一块四线的驱动器、就算停着也持续耗电,以及一旦丢步不会有任何提示。

最后更新:2026 年 8 月。有问题?WhatsApp 联系我们

Leave a Reply

Your email address will not be published. Required fields are marked *