← 返回文章库

差速驱动底盘与运动控制:让小车听话地走直线、转弯、原地自转

最后更新 2026-06-20
⏱ 约 16 分钟 🟡 涉接线/强电
你将学到
  • 用运动学直觉理解差速驱动如何靠左右轮速差实现直行、转弯、原地自转
  • 在双路电机驱动之上封装 forward/backward/turnLeft/turnRight/spin/stop 六个动作
  • 看懂"同型号电机也跑偏"的根因,并明白为什么这件事会把你逼向编码器闭环
  • 完成走正方形回起点的挑战,亲手体会无闭环时的误差累积

你按上一篇把电机驱动板接好了,电机也会转了。于是你写下"两个轮子一起正转",满心期待小车笔直冲出去——结果它走了不到半米就明显往一边偏,再走两米已经歪到桌子边缘。你没接错线,电机也是同一批买的同型号,可它就是不走直线。

这不是你的 bug,这是差速驱动底盘的"出厂特性"。理解它为什么跑偏,恰恰是理解整个底盘运动逻辑的入口。

如果你还没把双路电机转起来,先回 双路电机驱动接线 那篇——驱动板怎么接 TB6612/L298N、IN1/IN2 怎么定方向、PWM 引脚接哪、电机供电怎么单独走,那篇讲透了。本篇不重复电机代码细节,只管一件事:两个轮子怎么配合,才能让整台车走出你想要的轨迹。

差速驱动:两个轮子,一身本事

差速驱动(Differential Drive)的硬件极简:两个独立驱动的轮子,外加一个不出力的万向轮(或牛眼轮)做支撑。左右两个轮子各接一路电机驱动,能独立控制转速和方向。万向轮只负责让车身站稳,自己不参与驱动,往哪偏都行。

就这么三个轮子,靠"左右轮速差"(这就是"差速"二字的来历)能走出全部你需要的动作。运动学直觉其实只有三条,记住就够用:

  • 左右同速、同向 → 直行。两轮一样快往前,车就往前;一样快往后,车就倒退。
  • 左快右慢(同向) → 往慢的那侧转。左轮跑得快、右轮跑得慢,车头就向右偏,画出一道弧线。速差越大,弧越急。
  • 左右反向、等速 → 原地自转。左轮前转、右轮后转,车不前进也不后退,绕着自己车身中心点转圈。这就是差速底盘最爽的能力:零转弯半径,在窄过道里也能掉头。

你不用记任何公式。把两个轮子想象成你划船的两只桨:两桨一起划船直走,左桨用力船右拐,一桨前推一桨后拉船原地打转。差速小车就是一条只有两只桨的船。

观点先放这儿:差速驱动是新手第一台小车的唯一正确选择。 麦克纳姆轮能横移很炫,但四个轮子、四路驱动、运动学解算复杂,调试地狱;阿克曼转向(像真车那样前轮打方向)结构又比差速复杂。差速用最少的零件给你最完整的平面运动能力,先用它把"底盘怎么动"这件事吃透,再去碰花活。

把六个动作封装成函数

光知道"左快右慢往右转"还不够,每次都手写两路 PWM 太啰嗦也容易错。正确做法是封装一层动作 API:上层只管喊 forward()turnLeft(),底层怎么拨弄两路电机由函数兜住。这样你的主程序读起来就是人话。

下面这段以 ESP32 + TB6612 风格的双路驱动为例。每路电机要两个方向引脚定转向、一个 PWM 引脚定速度。引脚号只是示意,以你自己的接线为准;方向引脚的高低电平对应正转还是反转,也取决于你电机线的接法,跑反了对调一下即可(排查表里会说)。

ESP32 的 PWM 走 LEDC 通道,需要先 setup 再用 ledcWrite 给占空比,细节见 Arduino-ESP32 LEDC 文档。如果你用的是 Arduino UNO,把 ledcWrite 换成 analogWrite 即可,逻辑完全一样。

// ===== 引脚示意(以你的接线为准) =====
// 左电机
const int L_IN1 = 25, L_IN2 = 26, L_PWM = 27;
// 右电机
const int R_IN1 = 32, R_IN2 = 33, R_PWM = 14;

const int CH_L = 0, CH_R = 1;   // LEDC 通道
const int PWM_FREQ = 20000;     // 20kHz,超声频段,电机不啸叫
const int PWM_RES  = 8;         // 8位,占空比 0~255

void setupMotors() {
  pinMode(L_IN1, OUTPUT); pinMode(L_IN2, OUTPUT);
  pinMode(R_IN1, OUTPUT); pinMode(R_IN2, OUTPUT);
  ledcSetup(CH_L, PWM_FREQ, PWM_RES); ledcAttachPin(L_PWM, CH_L);
  ledcSetup(CH_R, PWM_FREQ, PWM_RES); ledcAttachPin(R_PWM, CH_R);
}

// 单侧电机底层控制:dir=+1 前转 / -1 后转 / 0 停; speed=0~255
void leftMotor(int dir, int speed) {
  digitalWrite(L_IN1, dir > 0); digitalWrite(L_IN2, dir < 0);
  ledcWrite(CH_L, dir == 0 ? 0 : speed);
}
void rightMotor(int dir, int speed) {
  digitalWrite(R_IN1, dir > 0); digitalWrite(R_IN2, dir < 0);
  ledcWrite(CH_R, dir == 0 ? 0 : speed);
}

// ===== 六个动作:全用"左右轮 dir+speed"表达 =====
void forward(int spd)  { leftMotor(+1, spd); rightMotor(+1, spd); } // 同速同向→直行
void backward(int spd) { leftMotor(-1, spd); rightMotor(-1, spd); } // 同速反向→后退
void turnLeft(int spd) { leftMotor(+1, spd/3); rightMotor(+1, spd); } // 左慢右快→左拐弧线
void turnRight(int spd){ leftMotor(+1, spd); rightMotor(+1, spd/3); } // 左快右慢→右拐弧线
void spin(int dir, int spd) {            // dir=+1 顺时针 / -1 逆时针 原地自转
  leftMotor(dir, spd); rightMotor(-dir, spd);  // 左右反向→零半径旋转
}
void stop() { leftMotor(0, 0); rightMotor(0, 0); }

turnLeft/turnRight:我没让一个轮子完全停下,而是给慢侧留了 spd/3,这样转出来的是平滑弧线而不是急拐,整车更稳。想要更急的弯,把慢侧调成 0;想要原地转,那就是 spin() 的活儿。六个动作全部归结为"给左右轮各一个方向和一个速度"——这就是差速底盘的全部运动逻辑,没有第七种动作。

⚠️ 安全

电机的供电一定要和主控(ESP32/Arduino)的供电物理分离:电机用独立电池或电源进驱动板的 VM,主控用自己的 5V/3.3V。但两者的 GND 必须共地(接到一起),否则信号电平没有共同参照,PWM 和方向控制会乱跳甚至烧端口。电机启停瞬间会拉出大电流,绝不能让它从主控的稳压输出取电——这是新手最容易烧板子的一步。

跑偏的根因:为什么你迟早要装编码器

现在回到开头的问题。你调用 forward(200),左右轮拿到的是完全相同的 PWM 占空比 200,按理该一样快。可它就是跑偏,为什么?

因为 PWM 占空比控制的是"加在电机上的平均电压",不是转速。同一个占空比下,两个电机的实际转速会因为这些差异而不同:

  • 电机本身的制造公差,同型号也有个体差异,绕组、磁钢都不可能完全一致;
  • 两侧的机械阻力不同,齿轮箱松紧、轴承摩擦、轮子安装的同轴度;
  • 车身重量分布不均,压在某侧轮子上的负载更大;
  • 电池电压在掉,左右驱动通道的压降也未必对称。

结果就是:你下达"一样快"的指令,电机收到的是"一样的电压",但它们跑出来的速度不一样,于是车就偏。你可以手动给慢的一侧多加点 PWM 来补偿(比如 forward 里左轮 200、右轮 195),但这是死参数——电池一掉电、地面一换、负载一变,补偿值就失效,车又开始偏。

这正是差速底盘逼着每个人面对的第一个真相:开环控制(只给指令、不看结果)走不直线。 想真正走直,你得知道每个轮子实际转了多少,再实时调整 PWM 让两边对齐。测量"实际转了多少"的传感器,就是编码器;用测量值反过来纠正输出的控制方法,就是闭环

这个坑我们不在本篇填,但它是后面的主线——编码器与 PID 闭环 会专门讲怎么把跑偏这件事彻底治好。现在你只要记住:开环差速能让你跑起来、能做 Demo,但凡是要"精确"的场景,编码器闭环迟早要补上。

底盘选型:套件、车架与打滑

硬件这块给你几条不绕弯的建议:

  • 直接买两驱小车套件。 某宝上"智能小车底盘 2WD"几十块一套,含 TT 减速电机×2、轮子、万向轮、车架、电池盒,孔位都对好了。新手别自己拼,省下的时间拿去调代码。
  • 车架材质:亚克力轻便、金属结实。 亚克力(透明塑料板)便宜、轻、打孔方便,做学习车足够;金属车架更刚、不易变形,适合后面加云台、机械臂这种重负载,但贵且重。学习阶段亚克力够用。
  • 轮子打滑是大敌。 塑料光轮在瓷砖、玻璃上抓地差,原地自转时容易打滑空转,导致你以为转了 90 度实际只转了 70 度。换橡胶包胶轮、或在轮子上缠一圈防滑胶带,能立竿见影。打滑还会让后面装的编码器"算的转了多少"和"车实际走了多少"对不上——这是闭环也救不了的物理误差,从轮子上解决最划算。
  • 电机选 TT 减速电机起步。 那种黄色塑料齿轮箱的 TT 电机扭矩够、便宜、配套轮子现成,是事实标准的入门款。等你嫌它转速不稳、要做精确里程时,再升级带编码器的减速电机也不迟。

你应该看到什么

接好线、烧完上面的代码,写个简单主程序逐个测试动作,你应该看到:

  • forward(200):小车向前走(可能略偏,这正常,先确认方向对);调 backward(200) 倒退。
  • turnLeft(200):小车向左画弧前进turnRight(200) 向右画弧。
  • spin(+1, 180):小车原地打转,车身中心基本不挪窝,只是绕着自己转圈。这是验证差速底盘最爽的一刻——它真的能在原地掉头。
  • stop():两轮立即停。

如果某个动作方向反了、或者一侧不动,别慌,照下面的排查表逐项对。

故障排查表

现象 大概率原因 怎么修
走不直、明显跑偏 两电机同占空比下实际转速不同(正常现象) 临时给慢侧补点 PWM;根治要上编码器闭环
某个动作整体转向反了 该侧方向引脚 IN1/IN2 接反,或电机两根线接反 软件里对调该侧 dir 极性,或硬件对调电机两线
一个轮子完全不转 该路驱动没使能、PWM 引脚没接对、或电机线松 查 STBY/使能脚、查 PWM 接线、查电机端子是否拧紧
原地自转转不动/打滑空转 轮子抓地差,或转速太低扭矩不够 换橡胶轮/缠防滑胶带;spin 的速度调高一点
一启动就猛冲、撞东西 PWM 给太大、急启停没缓冲 起步速度调小;用下面的渐变加速变体

两个值得加的变体

变体一:加速度渐变,告别急启停。 上面六个动作是"一脚油门到底",电机瞬间从 0 跳到 200,既费电又容易打滑、让车头一冲。给它加个平滑过渡:

// 把当前速度在若干步里渐变到目标速度,避免猛冲
void smoothForward(int target, int step = 10, int gap = 15) {
  for (int s = 0; s <= target; s += step) {
    forward(s);
    delay(gap);   // 每步停一小会儿,让速度爬上去
  }
  forward(target);
}

起步丝滑很多,打滑也少了。停车时同理可以从 target 渐变回 0。

变体二:遥控起步。 把六个动作接到一个数据源上——蓝牙串口收一个字符 'w'/'s'/'a'/'d'/' ' 分别映射 forward/backward/turnLeft/turnRight/stop,你就有了一台手机遥控车。这是验证底盘逻辑最直观的方式,也是后面做自动导航前的"手动挡"练手。

动手挑战:走一个正方形,回到起点

光走直线不过瘾,给你个能暴露问题的挑战:让小车走出一个边长 1 米的正方形,最后回到起点、车头朝向也回到出发时的方向。

思路很直白——重复四次"直行一条边 + 原地右转 90 度":

void drawSquare() {
  for (int i = 0; i < 4; i++) {
    forward(180); delay(2000);   // 走一条边(时间靠试,约 1 米)
    stop();       delay(300);
    spin(+1, 180); delay(700);   // 原地右转约 90 度(时间靠试)
    stop();       delay(300);
  }
}

烧进去跑一次,你大概率会发现:它走不回起点。 终点和起点差了一截,车头方向也歪了。再多跑几圈,误差越滚越大,轨迹从正方形变成歪扭的螺旋。

这就是这个挑战的全部意义——你亲手摸到了开环控制的误差累积。每条边因为跑偏多走/少走一点,每次转弯因为打滑多转/少转几度,单次误差很小,但四条边四个弯叠下来就明显了,而且没有任何机制把它纠回来。你用 delay 的时间去近似"走 1 米""转 90 度",可时间不等于距离、不等于角度,电池一掉电同样的 delay 走的距离都变了。

记住这个歪掉的正方形。它就是你需要编码器闭环最有力的理由。

小结与下一步

差速驱动底盘的全部运动逻辑,就是一句话:左右两轮各给一个方向和一个速度,靠速差走出直行、弧线和原地自转。 你把这件事封装成六个动作函数,主程序就能用人话指挥小车。但开环的差速注定走不直、回不到起点——根因是 PWM 控的是电压不是转速,而这正是把你引向编码器闭环的钩子。

下一步,在这台能动的底盘上装"眼睛":循迹小车:让它沿着黑线走 会给底盘接上红外传感器,做出第一个能自己判断、自己纠偏的闭环行为——你会发现,循迹其实就是用本篇的六个动作 + 一点点判断逻辑拼出来的。底盘是骨架,从这里开始,小车要长出感官了。

📄 来源 / 自校链接

本文为公开资料整理,非亲测。关键参数与代码请结合实物与下列官方来源验证。

内容有错、看不懂、或想看下一期?告诉我们 →

本文为公开资料的学习整理,非亲测。涉接线/花钱/合规的步骤请结合实物与官方最新资料验证,风险自负。见免责声明