Skip to content

第 3 章:控制四个轮子转动

3.1 模块原理:减速电机与 H 桥驱动

D3 小车的 4 个麦克纳姆轮分别由 4 个减速金属齿轮电机驱动。电机工作电流较大,无法由 Pico 管脚直接驱动,需经过电机驱动模块。驱动模块内部为 H 桥电路(原理见基础教具包教程第 8 章):每个电机对应两个信号管脚,两管脚之间的电势差决定电机的转向与启停。

  • 前进管脚高电平、后退管脚低电平:电机正转(轮子向前滚动)

  • 前进管脚低电平、后退管脚高电平:电机反转(轮子向后滚动)

  • 两管脚同为高电平或同为低电平:电势差为 0,电机停止

电机与 Pico 管脚的对应关系如下(详见 2.3 信号线接线方案):

轮子前进管脚后退管脚
左前轮GP2GP3
左后轮GP4GP5
右前轮GP6GP7
右后轮GP8GP9

H 桥驱动原理图

H桥原理图较复杂,看不懂不影响后续学习——硬件编程重在"编程",而非diy硬件,成百上千种电子元器的电路原理全部搞清楚,最终成为的是硬件工程师,而非软件工程师。只需记住:电源接好后,两管脚间只要有电势差,轮子即会转动,至于到底是正转还是反转,动手一试便知。

3.2 接线检查

接线出厂时已完成,编程前按以下步骤检查:

  1. 打开电源开关,电压表(⑫)应有读数,且不低于 6V;

  2. Pico 拓展板电源指示灯应点亮;

  3. 对照 2.3 表格检查 8 根电机信号线,确认颜色一致、插头无松动。

注意:本章实验应将小车架空(垫于盒子或书本上),使四个轮子悬空,这四个轮子配的是减速电机,力量特别大,防止程序调试期间小车移动跌落。

3.3 代码实现:单个轮子转动

目标:左前轮正转 3 秒 → 停止 1 秒 → 反转 3 秒 → 停止 1 秒,循环执行。

实现逻辑:GP2 置高电平、GP3 置低电平,左前轮正转,等待 3 秒;两管脚同时置低电平,停止 1 秒;GP2 置低电平、GP3 置高电平,反转 3 秒;再停止 1 秒。

左前轮正反转 Mind+ 积木

python
from machine import Pin
import time

GP2 = Pin(2, Pin.OUT)   # 左前轮 前进脚
GP3 = Pin(3, Pin.OUT)   # 左前轮 后退脚

while True:
    # 前进:GP2 高、GP3 低,电势差 = 高 - 低,电流正向流过电机
    GP2.value(1)
    GP3.value(0)
    time.sleep(3)
    # 停转:两脚同为低电平。
    # 注意:让轮子停下的是"电势差为 0",而不是"低电平"本身
    GP2.value(0)
    GP3.value(0)
    time.sleep(1)
    # 后退:电势差反向,电流反向流过电机
    GP2.value(0)
    GP3.value(1)
    time.sleep(3)
    # 停转:两脚同为高电平,电势差同样为 0
    GP2.value(1)
    GP3.value(1)
    time.sleep(1)
cpp
const int GP2 = 2;   // 左前轮 前进脚
const int GP3 = 3;   // 左前轮 后退脚

void setup() {
  pinMode(GP2, OUTPUT);
  pinMode(GP3, OUTPUT);
}

void loop() {
  // 前进:GP2 高、GP3 低,电势差 = 高 - 低
  digitalWrite(GP2, HIGH);
  digitalWrite(GP3, LOW);
  delay(3000);
  // 停转:两脚同为低电平,电势差为 0
  digitalWrite(GP2, LOW);
  digitalWrite(GP3, LOW);
  delay(1000);
  // 后退:电势差反向
  digitalWrite(GP2, LOW);
  digitalWrite(GP3, HIGH);
  delay(3000);
  // 停转:两脚同为高电平,电势差同样为 0
  digitalWrite(GP2, HIGH);
  digitalWrite(GP3, HIGH);
  delay(1000);
}

换向之间设置 1 秒停止时间,是为了先释放电机的转动动能,避免换向瞬间电流冲击,同时使动作边界清晰可观察。

3.4 养成好习惯:使用PWM替代高低电平驱动

PWM 原理已在第一册第九章详述。高低电平控制仅有"全开/全关"两种状态,过于粗暴;PWM 则可在 0%–100% 之间精细调节。尽管并非所有芯片的管脚都支持 PWM(部分品牌仅 6 个或 10 个管脚可用),但树莓派 Pico 所有编程管脚均支持 PWM。因此,对 Pico 编程时建议统一使用 PWM 替代高低电平,后期调速、调音量等需求均可灵活实现,程序可维护性与拓展性大幅提升。

下面是3.3单个轮子(左前轮)转动代码的PWM替代代码:

左前轮 PWM 驱动 Mind+ 积木

python
from machine import Pin, PWM
import time

GP2 = PWM(Pin(2))
GP3 = PWM(Pin(3))

def pwm(pin, v):
    # Mind+ 的 PWM 范围是 0~255,
    # MicroPython 的 duty_u16 范围是 0~65535。
    # 255 × 257 = 65535,所以乘 257 完成换算
    pin.duty_u16(v * 257)

while True:
    pwm(GP2, 166)   # 电势差 166,约为全速的 166/255 ≈ 65%
    pwm(GP3, 0)
    time.sleep(3)
    pwm(GP2, 0)     # 两组电势差均为 0,均表示停转
    pwm(GP3, 0)
    time.sleep(1)
    pwm(GP2, 0)
    pwm(GP3, 166)
    time.sleep(3)
    pwm(GP2, 166)
    pwm(GP3, 166)
    time.sleep(1)
cpp
const int GP2 = 2;
const int GP3 = 3;

void setup() {
  pinMode(GP2, OUTPUT);
  pinMode(GP3, OUTPUT);
}

void loop() {
  // Arduino 的 analogWrite 范围就是 0~255,与 Mind+ 积木数值一致
  analogWrite(GP2, 166);   // 电势差 166 ≈ 全速的 65%
  analogWrite(GP3, 0);
  delay(3000);
  analogWrite(GP2, 0);     // 两组电势差均为 0,均表示停转
  analogWrite(GP3, 0);
  delay(1000);
  analogWrite(GP2, 0);
  analogWrite(GP3, 166);
  delay(3000);
  analogWrite(GP2, 166);
  analogWrite(GP3, 166);
  delay(1000);
}

本教程后续所有涉及动力输出的元器件,统一采用 PWM 控制替代高低电平。后续实践中,会逐步体会到其显著优势。

3.5 代码实现:整车前进或后退

目标:整车前进 3 秒 → 停止 1 秒 → 后退 3 秒 → 停止 1 秒。

实现逻辑:将四个轮子的前进/后退分别封装为独立函数,再整合为整车运动函数。主过程调用整车运动函数,传入不同 sp 值,即可控制整车前进或后退。

四个轮子的子函数积木

python
# 四个轮子的子函数:sp > 0 前进,sp < 0 后退,sp = 0 停转
# 正转 = 前进脚出力、后退脚为 0;反转 = 两脚互换,数值取 abs(sp)
def wheel_left_1(sp):        # 左前轮 GP2/GP3
    if sp >= 0:
        pwm(GP2, sp)
        pwm(GP3, 0)
    else:
        pwm(GP2, 0)
        pwm(GP3, abs(sp))

def wheel_left_2(sp):        # 左后轮 GP4/GP5
    if sp >= 0:
        pwm(GP4, sp)
        pwm(GP5, 0)
    else:
        pwm(GP4, 0)
        pwm(GP5, abs(sp))

def wheel_right_1(sp):       # 右前轮 GP6/GP7
    if sp >= 0:
        pwm(GP6, sp)
        pwm(GP7, 0)
    else:
        pwm(GP6, 0)
        pwm(GP7, abs(sp))

def wheel_right_2(sp):       # 右后轮 GP8/GP9
    if sp >= 0:
        pwm(GP8, sp)
        pwm(GP9, 0)
    else:
        pwm(GP8, 0)
        pwm(GP9, abs(sp))
cpp
// 四个轮子的子函数:sp > 0 前进,sp < 0 后退,sp = 0 停转
// 正转 = 前进脚出力、后退脚为 0;反转 = 两脚互换,数值取 -sp
void wheel_left_1(int sp) {        // 左前轮 GP2/GP3
  if (sp >= 0) { analogWrite(2, sp); analogWrite(3, 0); }
  else         { analogWrite(2, 0);  analogWrite(3, -sp); }
}

void wheel_left_2(int sp) {        // 左后轮 GP4/GP5
  if (sp >= 0) { analogWrite(4, sp); analogWrite(5, 0); }
  else         { analogWrite(4, 0);  analogWrite(5, -sp); }
}

void wheel_right_1(int sp) {       // 右前轮 GP6/GP7
  if (sp >= 0) { analogWrite(6, sp); analogWrite(7, 0); }
  else         { analogWrite(6, 0);  analogWrite(7, -sp); }
}

void wheel_right_2(int sp) {       // 右后轮 GP8/GP9
  if (sp >= 0) { analogWrite(8, sp); analogWrite(9, 0); }
  else         { analogWrite(8, 0);  analogWrite(9, -sp); }
}

以上四个轮子的基础代码后续不再修改,下面的教程中会多次直接调用,不再重复贴出。

这四个函数能否进一步简化?经多年实践,图形化编程中已是最简;代码编程可借助数组/列表封装为通用函数,但图形化层面无法更简。

整车运动封装函数积木

python
def move(sp):
    # sp > 0 整车前进;sp < 0 整车后退;sp = 0 停止运动
    # 四个轮子给相同的速度,车就直线走
    wheel_left_1(sp)
    wheel_left_2(sp)
    wheel_right_1(sp)
    wheel_right_2(sp)
cpp
void move(int sp) {
  // sp > 0 整车前进;sp < 0 整车后退;sp = 0 停止运动
  // 四个轮子给相同的速度,车就直线走
  wheel_left_1(sp);
  wheel_left_2(sp);
  wheel_right_1(sp);
  wheel_right_2(sp);
}

整车前进后退主程序积木

python
while True:
    move(0)      # 停 1 秒
    time.sleep(1)
    move(166)    # 前进 3 秒
    time.sleep(3)
    move(0)      # 停 1 秒
    time.sleep(1)
    move(-166)   # 后退 3 秒
    time.sleep(3)
cpp
void loop() {
  move(0);      // 停 1 秒
  delay(1000);
  move(166);    // 前进 3 秒
  delay(3000);
  move(0);      // 停 1 秒
  delay(1000);
  move(-166);   // 后退 3 秒
  delay(3000);
}

说明:本章学习以 PWM 替代高低电平,并通过函数封装代码,体会 PWM 在函数调用中的便捷性。

不积跬步,无以至千里;万里之行,始于当下。