← 返回实战项目

循迹避障小车:沿黑线自己走、遇障能停能绕

最后更新 2026-07-01
⏱ 约 18 分钟 🟡 涉接线/强电
你将学到
  • 做出一辆能沿黑线巡线、前方遇障就停/绕的两轮差速小车
  • 把电机 PWM 调速与方向真值表、循迹红外读线、超声波测距三个知识点接成一条完整链路
  • 用 TB6612 独立供电驱动双电机,学会差速转向的差速逻辑
  • 用 HC-SR04 的触发/回响时序测出前方距离,据此改变小车行为
  • 建立"电机必须独立供电"的安全底线,避开电机拉垮单片机导致 brownout 重启的坑
🛒 器材清单
器材数量参考
2WD 小车底盘(含两个 TT 减速电机、轮子、万向轮、电池盒)1 套约 20-40 元(以商城实际为准)
TB6612 电机驱动板(或 L298N)1约 5-12 元(以商城实际为准)
三路循迹红外模块(TCRT5000)1约 5-12 元(以商城实际为准)
HC-SR04 超声波测距模块1约 3-8 元(以商城实际为准)
ESP32-S3 开发板1约 25-45 元(以商城实际为准)
5 号电池盒(4 节,给电机供电)+ 杜邦线若干1 套约 5-15 元(以商城实际为准)

价格随渠道波动,以购买页实时为准。

地上贴一条弯弯曲曲的黑线,把小车放上去,一通电,它就顺着线自己跑——该拐弯拐弯,该绕圈绕圈。你往它前面一伸手,它"嗖"地停住,甚至打个方向绕过去接着走。全程没人碰,它像有了眼睛和腿。这就是这一篇要带你做出来的东西:一辆会循迹、会避障的两轮小车

这是整个实战里最有"它活了"感觉的项目,也是第一个真正的移动机器人。之前的台灯、时钟都是插在桌上不动的,这次它要在地上跑起来,多了两件之前没碰过的事:两个电机要独立供电(不然一动就把板子拉垮),以及多个传感器同时决定小车的行为(红外看脚下、超声波看前方)。这两件事正是这一篇的分量所在。

这一篇不重讲电机为什么不能裸接 GPIO、TB6612 的真值表怎么来的——那些 L2 直流电机与驱动那节讲透了,这里默认你跑通过单电机的正反转调速。我们只干一件事:把双电机 + 循迹 + 避障拼成一辆能跑的车,讲清拼的过程里那些单看一个知识点时看不到的坑。想深挖循迹的传感器原理和阈值标定,看循迹小车那篇;想搞懂避障为什么选超声波、还有哪些测距方案,看机器人避障那篇;想在 L298N / TB6612 / DRV8833 之间反复权衡,看电机驱动板怎么选那篇。这篇是把它们串成成品的那一层。


第一步:想清楚要做成什么样,再定选型

动手前先把"成品长什么样"钉死。我们的小车就三个行为,优先级从高到低:

  • 避障优先:前方一定距离内有障碍,立刻停下(进阶再让它绕)。这条压过一切,撞上去比走错线严重得多。
  • 循迹为主:前方没障碍时,顺着黑线走——线在正中就直行,偏左就往左修,偏右就往右修。
  • 丢线兜底:三路红外都没看到黑线(冲出去了),就原地转着找线,或干脆停住。

行为定了,选型的每一步就都有了理由。

底盘:直接买 2WD 套件,别自己拼

新手别自己找电机配轮子,直接买一套现成的 2WD 小车底盘——一块亚克力板、两个 TT 减速电机带轮子、一个万向轮、一个电池盒,螺丝拧一拧就成型。自己配电机和轮子,光找同轴的联轴器就能耗掉一下午,还未必装得正。等这辆车跑通了、想升级四驱或麦克纳姆轮再折腾。

驱动板:TB6612 还是 L298N?

小车这种轻负载,直接上 TB6612:它用 MOSFET,压降小、发热小、个头小,同一组电池能跑更久。L298N 是老方案,双极型晶体管压降大、发热明显,但能扛更大电流、更便宜、更好买,手头只有它也够用。两者的详细取舍见 L2 电机那节的对比表,这里不重复。下面代码以 TB6612 为主线,关键处标出换 L298N 怎么改。

循迹:三路红外够用

循迹用三路一体的红外模块(TCRT5000 那种)最省事——一个模块上排着左、中、右三个探头,每个探头正下方是黑线就输出一个电平、是白底就输出另一个电平。三路刚好够判断"线在偏左/正中/偏右",比单路强得多,又比五路简单。红外探头怎么区分黑白、离地高度怎么调、阈值怎么标,循迹那篇讲透了,这里默认你会把它调到"压黑线亮一种灯、离开灭"。

避障:HC-SR04 超声波

避障用 HC-SR04 超声波模块:便宜、量程够(几厘米到几米)、接线简单,装在车头正前方,专测"前面多远有东西"。为什么是超声波而不是红外测距、ToF、激光雷达?避障那篇横向对比了四种方案的量程、精度、价格、抗干扰——结论是入门做小车避障,HC-SR04 性价比最高。


第二步:接线——三块外设各就各位,避开雷区

这辆车要接三样东西到 ESP32-S3:TB6612 驱动板(管两个电机)、三路循迹红外、HC-SR04 超声波。加起来引脚不少,选脚前先把 ESP32-S3 的雷区记牢。

🚧 避坑

ESP32-S3 选脚雷区,接线前对照排除:

  • GPIO0 / 3 / 45 / 46:strapping 脚,上电电平决定启动模式,接了外设可能让板子刷不进、起不来;
  • GPIO26-37:绝大多数模组内部连着 SPI flash / PSRAM,动了直接死机;
  • GPIO19 / 20:默认是 USB D-/D+,用它俩会断掉 USB 串口,你连日志都看不到;
  • GPIO22 / 23 / 24 / 25:ESP32-S3 上根本不存在这几个号(号从 21 直接跳到 26),写了编译不报错、运行时行为诡异。

避开这些,安全区里随手挑够用的脚。本项目这样分配:

【TB6612 驱动板 ← 左右两个电机】
  ESP32-S3 GPIO4  ──→ AIN1   (左电机方向 1)
  ESP32-S3 GPIO5  ──→ AIN2   (左电机方向 2)
  ESP32-S3 GPIO6  ──→ PWMA   (左电机速度,走 LEDC)
  ESP32-S3 GPIO7  ──→ BIN1   (右电机方向 1)
  ESP32-S3 GPIO15 ──→ BIN2   (右电机方向 2)
  ESP32-S3 GPIO16 ──→ PWMB   (右电机速度,走 LEDC)
  ESP32-S3 GPIO17 ──→ STBY   (待机脚,必须拉高)
  AO1/AO2 ──→ 左电机两根线    BO1/BO2 ──→ 右电机两根线
  电池盒(4×1.5V≈6V) ──→ VM 和 GND      ← 电机独立电源,见安全框
  ESP32-S3 GND ──→ 驱动板 GND           ← 必须共地
  ESP32-S3 3.3V ──→ 驱动板 VCC          (给驱动芯片逻辑供电)

【三路循迹红外 ← 装在车头底部,贴近地面】
  ESP32-S3 GPIO8  ──→ 左探头 OUT
  ESP32-S3 GPIO9  ──→ 中探头 OUT
  ESP32-S3 GPIO10 ──→ 右探头 OUT
  ESP32-S3 3.3V ──→ 模块 VCC    GND ──→ 模块 GND

【HC-SR04 超声波 ← 装在车头正前方】
  ESP32-S3 GPIO11 ──→ Trig   (触发脚)
  ESP32-S3 GPIO12 ──→ Echo   (回响脚,见下方电平提示)
  ESP32-S3 5V ──→ 模块 VCC    GND ──→ 模块 GND

接线时盯死这几条,漏一条就白忙:

  • STBY 必须拉高:TB6612 的总开关,代码里 gpio_set_level(STBY, 1) 一句没有,整块芯片睡着,两个电机纹丝不动,你会以为代码错了。这是电机那节反复强调的头号隐坑。
  • 共地单片机 GND、驱动板 GND、电池盒 GND、两个传感器 GND,全都要连到一起。信号没有共同参考点,电机乱转、测距乱跳。
  • HC-SR04 的 Echo 电平:这个模块是 5V 供电、Echo 输出也是 5V 高电平,而 ESP32-S3 的 GPIO 只耐 3.3V。严格来说 Echo 要串一个分压(比如 1kΩ + 2kΩ 分压到约 3.3V)再进 GPIO,直连虽然很多人图省事这么干、短期也常能读出数,但那是在超范围硬灌、有损伤风险。要稳,就加这个分压电阻。
  • 换 L298N:没有 STBY 脚,省掉 GPIO17 那根线和拉高那句;速度脚叫 ENA/ENB(把 LEDC 绑到接 ENA/ENB 的脚),方向脚叫 IN1~IN4。照驱动板丝印对脚名,其余逻辑一模一样。
⚠️ 安全

这辆车最要命的一条:两个电机必须用独立电源(电池盒),接到驱动板的 VM,绝不能从开发板或 USB 取电。

  • 电机是感性负载,启动、换向、堵转的瞬间会拉出几百毫安到上安培的大电流,还会"憋"出反向电压尖峰(反电动势)。你要是让电机和单片机共用一路电(比如都从 USB 的 5V 取),电机一动,电压瞬间被拉垮,单片机立刻 brownout(欠压检测)复位重启——表现就是"一给电机上电板子就重启、日志从头再来",极难排查。
  • 正确做法:电机的功率电走电池盒接 VM(4 节 5 号约 6V,匹配常见 TT 电机);单片机的逻辑电走 USB 或另一路稳压;两者只在 GND 共地。驱动板的 VCC(逻辑供电)从单片机 3.3V 取。
  • 电池正负别接反:接反轻则不工作,重则烧驱动板。装电池盒时对照 VM/GND 丝印再插。
  • 反电动势:TB6612、L298N 的 H 桥内部已集成续流二极管帮你挡尖峰,不用外接,但要知道它在替你挨这一刀;电源端加个大电容进一步稳压更保险。
  • 第一次上电先架空轮子:把车垫起来让轮子悬空空转,确认左右方向、快慢正常,再放地上——接错时车不会直接窜出去撞墙。

第三步:分步把代码写出来

不一次甩一大坨,分三步长出来,每步都能单独烧进去看到效果——出问题时你才知道是哪一步坏的。

步 1:先让两个电机能前进、后退、转向

第一步只验证驱动通路:两个电机都接对了、方向和调速都正常、差速转向逻辑对。这一步就是把电机那节的单电机代码扩成双电机,再包一层"小车动作"。

#include "driver/gpio.h"
#include "driver/ledc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"

static const char *TAG = "car";

// —— 左电机 A 路 ——
#define AIN1 GPIO_NUM_4
#define AIN2 GPIO_NUM_5
#define PWMA GPIO_NUM_6
// —— 右电机 B 路 ——
#define BIN1 GPIO_NUM_7
#define BIN2 GPIO_NUM_15
#define PWMB GPIO_NUM_16
// —— 总待机脚 ——
#define STBY GPIO_NUM_17

#define PWM_MODE   LEDC_LOW_SPEED_MODE  // S3 只有低速这一组
#define PWM_TIMER  LEDC_TIMER_0
#define CH_L       LEDC_CHANNEL_0       // 左电机 PWM 通道
#define CH_R       LEDC_CHANNEL_1       // 右电机 PWM 通道

static void motor_init(void)
{
    // 四根方向脚 + STBY,都配成普通数字输出
    gpio_config_t io = {
        .pin_bit_mask = (1ULL << AIN1) | (1ULL << AIN2) |
                        (1ULL << BIN1) | (1ULL << BIN2) | (1ULL << STBY),
        .mode = GPIO_MODE_OUTPUT,
    };
    gpio_config(&io);

    // 一个定时器给两路 PWM 共用:8 位分辨率(0~255),5kHz 电机听不出啸叫
    ledc_timer_config_t timer = {
        .speed_mode      = PWM_MODE,
        .duty_resolution = LEDC_TIMER_8_BIT,
        .timer_num       = PWM_TIMER,
        .freq_hz         = 5000,
        .clk_cfg         = LEDC_AUTO_CLK,
    };
    ledc_timer_config(&timer);

    // 左、右各绑一个 PWM 通道到各自的速度脚
    ledc_channel_config_t chL = {
        .gpio_num = PWMA, .speed_mode = PWM_MODE, .channel = CH_L,
        .timer_sel = PWM_TIMER, .duty = 0, .hpoint = 0,
    };
    ledc_channel_config(&chL);
    ledc_channel_config_t chR = {
        .gpio_num = PWMB, .speed_mode = PWM_MODE, .channel = CH_R,
        .timer_sel = PWM_TIMER, .duty = 0, .hpoint = 0,
    };
    ledc_channel_config(&chR);

    gpio_set_level(STBY, 1);  // 关键:唤醒 TB6612,不拉高两个电机都不转
}

// 单个电机设速度+方向:speed 0~255,dir=1 正转 / 0 反转
static void wheel(int in1, int in2, ledc_channel_t ch, int speed, int dir)
{
    gpio_set_level(in1, dir ? 1 : 0);
    gpio_set_level(in2, dir ? 0 : 1);
    ledc_set_duty(PWM_MODE, ch, speed);
    ledc_update_duty(PWM_MODE, ch);  // set 完必须 update 才生效
}

// —— 小车动作:把左右两轮组合起来 ——
void car_forward(int sp) { wheel(AIN1,AIN2,CH_L,sp,1); wheel(BIN1,BIN2,CH_R,sp,1); }
void car_back(int sp)    { wheel(AIN1,AIN2,CH_L,sp,0); wheel(BIN1,BIN2,CH_R,sp,0); }
void car_left(int sp)    { wheel(AIN1,AIN2,CH_L,sp/3,1); wheel(BIN1,BIN2,CH_R,sp,1); } // 左轮慢=向左偏
void car_right(int sp)   { wheel(AIN1,AIN2,CH_L,sp,1); wheel(BIN1,BIN2,CH_R,sp/3,1); } // 右轮慢=向右偏
void car_stop(void)      { wheel(AIN1,AIN2,CH_L,0,1); wheel(BIN1,BIN2,CH_R,0,1); }

void app_main(void)
{
    motor_init();
    while (1) {  // 悬空测试:前进→左→右→后退→停,看四个动作对不对
        ESP_LOGI(TAG, "前进"); car_forward(180); vTaskDelay(pdMS_TO_TICKS(1200));
        ESP_LOGI(TAG, "左转"); car_left(180);    vTaskDelay(pdMS_TO_TICKS(800));
        ESP_LOGI(TAG, "右转"); car_right(180);   vTaskDelay(pdMS_TO_TICKS(800));
        ESP_LOGI(TAG, "后退"); car_back(180);    vTaskDelay(pdMS_TO_TICKS(1200));
        ESP_LOGI(TAG, "停");   car_stop();       vTaskDelay(pdMS_TO_TICKS(600));
    }
}

烧进去前先把车垫起来让轮子悬空(安全框第一条),idf.py build flash monitor你应该看到:串口滚动打印动作,两个轮子按前进→左偏→右偏→后退→停循环。

  • 差速转向的门道全在 car_left / car_right让一侧轮子比另一侧慢(这里除以 3),车就往慢的那侧偏。想原地打转就让一侧正转、一侧反转(把慢侧的 dir 改成反向、速度给满)。
  • 哪个轮子转反了,把那个电机的两根线对调,或把对应 wheel()dir 逻辑反过来——不影响安全,只是方向问题。
  • 电机纹丝不动、日志却照打?八成 STBY 没拉高,或电池盒没接 VM。回头查安全框和 gpio_set_level(STBY, 1)

步 2:接上循迹红外,让它沿黑线走

现在给小车装上"看脚下"的眼睛。三路红外读回来是三个 0/1,组合起来判断黑线偏在哪,据此调左右轮速度。

#include "driver/gpio.h"

#define IR_L GPIO_NUM_8    // 左探头
#define IR_M GPIO_NUM_9    // 中探头
#define IR_R GPIO_NUM_10   // 右探头

// 约定:探头压在黑线上读到 1(多数模块可调,以你标定的为准,见循迹那篇)
#define ON_LINE 1

static void ir_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask = (1ULL << IR_L) | (1ULL << IR_M) | (1ULL << IR_R),
        .mode = GPIO_MODE_INPUT,
    };
    gpio_config(&io);
}

// 循迹一步:根据三路读数决定怎么走
static void follow_line_step(void)
{
    int l = (gpio_get_level(IR_L) == ON_LINE);
    int m = (gpio_get_level(IR_M) == ON_LINE);
    int r = (gpio_get_level(IR_R) == ON_LINE);

    if (m && !l && !r) {          // 只有中间压线:线在正中,直行
        car_forward(160);
    } else if (l && !r) {         // 左边压线:线偏左,向左修
        car_left(160);
    } else if (r && !l) {         // 右边压线:线偏右,向右修
        car_right(160);
    } else if (!l && !m && !r) {  // 三路全丢:冲出线了,先停(进阶再做找线)
        car_stop();
    } else {                      // 其它组合(如全压线遇到路口):先直行
        car_forward(120);
    }
}

void app_main(void)
{
    motor_init();
    ir_init();
    while (1) {
        follow_line_step();
        vTaskDelay(pdMS_TO_TICKS(20));  // 20ms 一轮,够快跟得住线
    }
}

地上贴一条黑线(黑电工胶带贴白纸最好使),把车放上去。你应该看到:线在正中它直行,走着走着线偏了它就往对应方向修,画一条 S 弯它能歪歪扭扭跟下来。跟不住、抖得厉害、或认不出黑白,多半是红外阈值和离地高度没标好——这块循迹那篇专门讲了怎么调,先回去把探头调到"压黑线亮灯、离开灭灯"再来。

这种 if-else 开关式循迹最简单,但有个天生的毛病:只有"全速修"和"直行"两个挡,线一偏就猛打方向,车会像喝多了一样左右画龙。想让它跟得又快又顺,得上比例调速(P 控制)——偏得越多修得越狠、偏得越少修得越轻,这是第六步进阶的方向。

步 3:加上超声波避障,让避障压过循迹

最后装上"看前方"的眼睛。HC-SR04 的用法是一套固定时序:给 Trig 一个 10 微秒的高电平脉冲触发一次测量,然后测 Echo 脚高电平持续了多久——声音往返时间 × 声速 ÷ 2 就是距离

#include "esp_timer.h"
#include "rom/ets_sys.h"   // ets_delay_us

#define TRIG GPIO_NUM_11
#define ECHO GPIO_NUM_12
#define STOP_CM 20         // 前方近于 20cm 就当有障碍

static void sonar_init(void)
{
    gpio_config_t t = { .pin_bit_mask = 1ULL << TRIG, .mode = GPIO_MODE_OUTPUT };
    gpio_config(&t);
    gpio_config_t e = { .pin_bit_mask = 1ULL << ECHO, .mode = GPIO_MODE_INPUT };
    gpio_config(&e);
    gpio_set_level(TRIG, 0);
}

// 测一次距离,返回厘米;测量失败(超时/没回响)返回 -1
static float sonar_read_cm(void)
{
    // 1) 给 Trig 一个 10us 高脉冲,触发一次测量
    gpio_set_level(TRIG, 0); ets_delay_us(2);
    gpio_set_level(TRIG, 1); ets_delay_us(10);
    gpio_set_level(TRIG, 0);

    // 2) 等 Echo 拉高(发射完成),最多等 25ms 防止卡死
    int64_t t0 = esp_timer_get_time();
    while (gpio_get_level(ECHO) == 0) {
        if (esp_timer_get_time() - t0 > 25000) return -1;  // 没回响
    }
    // 3) 量 Echo 高电平持续多久
    int64_t start = esp_timer_get_time();
    while (gpio_get_level(ECHO) == 1) {
        if (esp_timer_get_time() - start > 25000) return -1; // 太远/超量程
    }
    int64_t us = esp_timer_get_time() - start;
    // 4) 声速约 340m/s=0.0343cm/us,往返除以 2
    return us * 0.0343f / 2.0f;
}

void app_main(void)
{
    motor_init();
    ir_init();
    sonar_init();

    while (1) {
        float dist = sonar_read_cm();

        // —— 避障优先:前方有障碍,压过一切,先停住 ——
        if (dist > 0 && dist < STOP_CM) {
            car_stop();
            ESP_LOGI(TAG, "前方 %.1fcm 有障碍,停", dist);
            // 进阶:这里可改成后退一点 + 转个方向绕开,见第六步
            vTaskDelay(pdMS_TO_TICKS(200));
            continue;               // 本轮不循迹,下一轮重新测
        }

        // —— 前方通畅:交给循迹 ——
        follow_line_step();
        vTaskDelay(pdMS_TO_TICKS(20));
    }
}

你应该看到:小车沿黑线正常走,你把手(或一本书)挡在车头前 20cm 内,它立刻停下、串口打出障碍距离;手一挪开,它接着沿线走。这就是"避障优先、循迹为主"的优先级:每一轮先看前方,有障碍就停、跳过循迹;没障碍才去循迹。

到这核心功能全齐了。回头看,你没写多少全新的东西:电机调速是电机那节的,红外读数是循迹那篇的,超声波时序是避障那篇的,你干的是把它们用一个"先避障后循迹"的主循环组织起来——这个"组织",就是 project 比 guide、article 多出来的那层功夫。


第四步:调试——对不上就查这张表

分步烧的好处是,哪一步出问题你已经缩小了范围。真出了岔子,照这张表查:

现象 最可能的原因 怎么办
一给电机上电板子就重启、日志从头 电机没独立供电,从 USB/开发板取电导致 brownout 电机务必走电池盒接 VM,逻辑电走 USB,只共地——见安全框
两个电机纹丝不动、日志正常 STBY 没拉高 / 没共地 / VM 没接电池 确认 gpio_set_level(STBY,1) 有执行且 STBY 接好;四处 GND 连一起;电池盒接 VM
只有一个轮子转 一路方向脚没接好,或 PWM 通道绑错脚 量 BIN1/BIN2/PWMB 是否到位;确认 ledc_channel_configgpio_num 是对应速度脚
某个轮子转向反了 电机两根线接反,纯方向问题 对调那个电机两根线,或反转对应 wheel()dir
车总往一边偏、走不直 左右电机转速有差异(电机个体差) 给偏快那侧的 car_forward 稍微降点速做补偿;或先按循迹靠传感器纠
循迹认不出黑白 / 乱修方向 红外阈值没标 / 离地太高或太低 / ON_LINE 极性反了 循迹那篇标阈值,调离地高度;把 ON_LINE 改成 0 试试极性
循迹左右画龙、抖得凶 if-else 开关式只有全速修,天生抖 降低巡线速度先稳住;根治靠第六步的比例调速
测距一直返回 -1 或跳变乱 Echo 没接好 / Trig 时序不对 / 5V Echo 直灌 3.3V 脚 查 Trig/Echo 接线;Echo 加分压电阻到 3.3V;确认供电是 5V
测距数值明显偏大/偏小 声速系数或往返除 2 算错 核对 0.0343f / 2.0f;量个已知距离校准
三路全丢线后车乱转 全丢线只做了 car_stop,或探头间距不匹配线宽 先确认丢线是 stop;进阶做"原地转找线";黑线宽度和探头间距要匹配
💡 提示

一次只改一处再烧。同时改三个地方、车还是不对,你根本分不清是哪个改动的锅。分步烧、单点改、先架空轮子,是移动机器人调试省时间又不撞墙的铁律。


第五步:从"能跑的 demo"做成"像样的机器人"

到这它已经是辆能循迹会避障的车了。但"能跑"和"跑得好"之间还差几步,这几步正好通向更深的阶梯,先给你指条路。

用 P 控制让循迹变顺

现在的 if-else 循迹只有"全速修"一个力度,线一偏就猛打方向,车左右画龙。真正顺滑的做法是比例调速(P 控制):把三路(甚至改用模拟量红外的连续读数)算出一个"偏差",偏差越大、左右轮的速度差就越大,偏得越轻修得越轻。这样车贴着线走得又快又稳,不再画龙。这块循迹那篇从 if-else 讲到了比例调速,顺着往下补。

让避障从"停"升级到"绕"

现在遇障只会停。进阶让它绕过去:检测到障碍后先后退一点,再原地转一个方向(car_left 给满速、持续一段时间实现小角度转向),转完测一下前方通了没,通了就继续走。想更聪明,给超声波装个舵机做云台扫描——左右各测一下,往更空的那侧绕。避障那篇给了差速底盘的避障状态机和舵机云台扫描的完整思路,照着升级。

把系统做得更稳

单主循环里"测距 + 循迹"串着跑,测距那 20 多毫秒会拖慢循迹响应。更专业的做法是把测距、循迹、决策拆成独立的 FreeRTOS 任务,用队列传递数据——这套多任务骨架台灯那篇的呼吸+按键并行已经示范过,小车上是同一个思路的放大。想系统学传感器、状态机、更复杂的机器人玩法,看机器人专题


小结 · 你做出了什么、下一步去哪

  • 你做出了一辆沿黑线自动巡线、前方遇障能停的两轮差速小车,从选型、避雷区接线、分步写码到调试,走完了一件移动机器人成品的全流程。
  • 你第一次把 TB6612 双电机 PWM 调速l2-motor)、三路红外循迹robot-line-follow)、HC-SR04 超声波测距robot-obstacle-avoid)三块,用一个"先避障后循迹"的主循环接成了一条完整链路——这个"组织零件"的功夫,就是 project 比单个知识点多出来的那层。
  • 你把最要命的一条安全底线刻进了脑子:电机必须独立供电,否则一动就把单片机拉垮 brownout 重启;连同电池别接反、共地、先架空测试,这些是所有带电机的项目都要守的规矩。

下一步:想让循迹跟得更顺,上 P 控制;想让它会绕障、会扫描选路,看避障那篇;想在几款驱动板之间反复权衡,看驱动板选型那篇;想系统玩转机器人,进机器人专题。回看全部实战见项目总览。这辆车是你从"桌面小玩意"迈进"会动的机器人"的第一步,也是最值得留着反复升级的一台。

📄 来源 / 自校链接

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

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

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