ESP32智能小车三合一:循迹、避障与跟随功能整合实战
最近在做一个智能小车项目,需要它既能沿着黑线跑,又能避开路上的障碍物,还能跟着一个移动的物体走。网上找了一圈资料,发现要么只讲循迹,要么只讲避障,想找一个把循迹、避障、跟随三个功能整合到一辆基于ESP32的小车上的完整教程,还真不容易。自己摸索着做了一遍,踩了不少坑,也总结了一套比较可靠的方案。
本文将手把手带你从零搭建一辆“三合一”智能小车。我们会使用性价比极高的ESP32作为主控,配合常见的红外传感器和电机驱动模块,实现循迹、红外避障和超声波跟随功能。文章会涵盖完整的硬件选型、接线图、Arduino代码编写、逻辑调试以及常见问题的解决方案。无论你是学生正在准备电赛或课程设计,还是嵌入式爱好者想做个有趣的玩具,都能从这篇教程中找到可以直接复用的代码和清晰的思路。
1. 项目核心功能与硬件选型
在开始动手之前,我们先明确这辆智能小车要实现的三个核心功能,以及每个功能对应的硬件原理。
1.1 功能定义与实现思路
- 循迹:让小车沿着地面上画好的黑色轨迹线自动行驶。这是通过车底朝下的红外循迹传感器实现的。传感器发射红外光,黑色轨迹线会吸收大部分红外光,而白色地面则会反射。通过检测反射光的强度,传感器就能判断下方是黑线还是白地,从而输出不同的电平信号给ESP32,ESP32再控制左右轮差速,实现转向。
- 避障:让小车在行驶过程中,自动探测前方的障碍物并绕开或停止。我们采用红外避障模块。它同样利用红外反射原理,当模块前方一定距离内有物体时,反射的红外光被接收,模块输出信号。ESP32检测到这个信号后,会触发避障策略(如后退、转向)。
- 跟随:让小车跟随一个移动的物体(比如人)前进。这里我们使用超声波模块来测量小车与前方物体之间的距离。通过持续测量距离,ESP32可以动态调整车速:距离太近就减速或后退,距离太远就加速追赶,保持在一个设定的“安全跟随距离”区间内。
逻辑优先级:在实际运行时,这三个功能需要有一个明确的优先级。通常,避障的优先级最高,因为安全第一。任何时候检测到障碍物,都应立即中断当前行为(循迹或跟随)执行避障。其次是循迹,当没有障碍物且处于循迹模式时,小车专心沿黑线走。最后是跟随模式,在没有黑线且没有紧急障碍物时,小车尝试跟随前方的物体。
1.2 硬件清单与作用
以下是完成本项目所需的核心硬件清单,所有模块都非常常见且价格低廉。
| 组件 | 型号/规格 | 数量 | 主要作用 |
|---|---|---|---|
| 主控制器 | ESP32开发板 (如ESP32 DevKitC V4) | 1 | 项目的大脑,负责读取传感器数据、执行控制逻辑、驱动电机。 |
| 电机驱动 | L298N或TB6612FNG电机驱动模块 | 1 | 接收ESP32的弱电控制信号,驱动直流电机的大电流。TB6612FNG效率更高、发热更小,更推荐。 |
| 直流减速电机 | TT马达(带减速箱) | 2 | 提供动力,通常需要配合车轮使用。 |
| 循迹传感器 | TCRT5000红外反射传感器 | 3-5个 | 检测地面黑线。五路传感器控制更精准,三路足以应对简单路线。 |
| 避障传感器 | E18-D80NK 或类似红外避障开关 | 1-2个 | 检测前方障碍物。通常安装在车头。 |
| 测距传感器 | HC-SR04超声波模块 | 1 | 测量与前方物体的距离,用于跟随功能。 |
| 电源 | 18650锂电池两节及电池盒 | 1套 | 为整个系统供电。电机驱动模块和ESP32最好分开供电。 |
| 车体 | 智能小车底盘套件(含轮子、万向轮) | 1套 | 承载所有电子元件。 |
| 连接线 | 杜邦线(公对公、公对母) | 若干 | 连接各模块。 |
为什么选择ESP32?ESP32集成了Wi-Fi和蓝牙,虽然本项目暂未使用无线功能,但它为后续扩展(如手机APP遥控、OTA升级)留下了巨大空间。其双核处理器也能轻松应对多传感器数据读取和电机控制任务,性能远超传统的Arduino UNO。
2. 硬件连接与电路搭建
正确的硬件连接是项目成功的第一步。请务必在断电状态下进行接线。
2.1 电机与驱动模块连接
我们以TB6612FNG驱动模块为例,因为它控制更精细,且有待机功能。
- 电机连接:将左、右两个TT电机的线分别接到驱动模块的
A+ A-和B+ B-输出端。 - 电源连接:
- 电机电源 (VM):接锂电池正极(如7.4V)。GND接锂电池负极。
- 逻辑电源 (VCC):接ESP32的
3.3V或5V引脚(根据模块说明,TB6612FNG逻辑电压可接3.3V)。GND接ESP32的GND。 - 注意:务必将锂电池的GND、驱动模块的GND和ESP32的GND连接在一起,即共地,这是电路正常工作的基础。
- 控制信号连接:将驱动模块的控制引脚连接到ESP32的GPIO口。
AIN1,AIN2-> 控制电机A(左轮)正反转。接ESP32的任意两个IO口,如GPIO13,GPIO12。PWMA-> 电机A的PWM调速引脚。接ESP32的任意支持PWM的IO口,如GPIO14。BIN1,BIN2,PWMB-> 同理,控制电机B(右轮)。接GPIO27,GPIO26,GPIO25。STBY(待机引脚) -> 接高电平(如3.3V)模块才工作,也可以接一个IO口进行软件控制。
2.2 传感器与ESP32连接
- 五路循迹传感器模块:
- 模块的
VCC和GND分别接ESP32的5V(或3.3V,看模块规格)和GND。 - 传感器的五个输出引脚(通常标为
OUT1-OUT5)分别接ESP32的五个数字输入引脚,例如GPIO15,GPIO2,GPIO4,GPIO5,GPIO18。当检测到黑线时,对应引脚输出低电平(0),白线为高电平(1)。
- 模块的
- 红外避障模块 (E18-D80NK):
棕色线(VCC)-> ESP325V。蓝色线(GND)-> ESP32GND。黑色线(OUT)-> ESP32 数字输入引脚,如GPIO19。有障碍物时输出低电平。
- 超声波模块 (HC-SR04):
VCC-> ESP325V。GND-> ESP32GND。Trig(触发) -> ESP32 数字输出引脚,如GPIO23。Echo(回声) -> ESP32 数字输入引脚,如GPIO22。
接线核对提示:接完线后,强烈建议画一张简单的接线图,或用表格记录每个ESP32引脚的功能,方便后续编程和排查故障。
3. 软件开发环境搭建
我们将使用Arduino IDE来为ESP32编写程序,这是最快速上手的方式。
3.1 安装Arduino IDE与ESP32开发板支持
- 从Arduino官网下载并安装最新版Arduino IDE。
- 打开IDE,点击
文件->首选项,在“附加开发板管理器网址”中输入:
可以点击输入框右侧的图标添加多个URL,如果有其他URL,用逗号隔开即可。https://espressif.github.io/arduino-esp32/package_esp32_index.json - 点击
工具->开发板->开发板管理器,在搜索框中输入“esp32”,找到“ESP32 by Espressif Systems”,点击安装。 - 安装完成后,在
工具->开发板中选择你的ESP32型号,如“ESP32 Dev Module”。 - 选择正确的端口(连接ESP32后会出现)。
3.2 核心代码结构与函数封装
为了让代码清晰易维护,我们将功能模块化。首先,定义所有用到的引脚。
// 引脚定义 // 电机驱动引脚 (以TB6612FNG为例) #define MOTOR_AIN1 13 #define MOTOR_AIN2 12 #define MOTOR_PWMA 14 #define MOTOR_BIN1 27 #define MOTOR_BIN2 26 #define MOTOR_PWMB 25 #define MOTOR_STBY 33 // 如果使用待机控制 // 五路循迹传感器引脚 (从左到右) #define TRACK_SENSOR_1 15 #define TRACK_SENSOR_2 2 #define TRACK_SENSOR_3 4 #define TRACK_SENSOR_4 5 #define TRACK_SENSOR_5 18 // 红外避障传感器引脚 #define OBSTACLE_SENSOR 19 // 超声波传感器引脚 #define ULTRASONIC_TRIG 23 #define ULTRASONIC_ECHO 22 // 工作模式定义 #define MODE_TRACKING 1 #define MODE_FOLLOWING 2 int currentMode = MODE_TRACKING; // 默认循迹模式接下来,封装电机控制函数。这是小车运动的基础。
// 电机控制函数 void motorInit() { pinMode(MOTOR_AIN1, OUTPUT); pinMode(MOTOR_AIN2, OUTPUT); pinMode(MOTOR_PWMA, OUTPUT); pinMode(MOTOR_BIN1, OUTPUT); pinMode(MOTOR_BIN2, OUTPUT); pinMode(MOTOR_PWMB, OUTPUT); pinMode(MOTOR_STBY, OUTPUT); digitalWrite(MOTOR_STBY, HIGH); // 解除待机 } // 控制单个电机:speed范围-255~255,负值为反转 void setMotor(int motor, int speed) { bool inPin1, inPin2; if (speed > 0) { inPin1 = HIGH; inPin2 = LOW; } else if (speed < 0) { inPin1 = LOW; inPin2 = HIGH; speed = -speed; // 取绝对值 } else { inPin1 = LOW; inPin2 = LOW; } if (motor == 0) { // 左轮电机A digitalWrite(MOTOR_AIN1, inPin1); digitalWrite(MOTOR_AIN2, inPin2); analogWrite(MOTOR_PWMA, speed); } else if (motor == 1) { // 右轮电机B digitalWrite(MOTOR_BIN1, inPin1); digitalWrite(MOTOR_BIN2, inPin2); analogWrite(MOTOR_PWMB, speed); } } // 小车运动封装:前进、后退、左转、右转、停止 void carForward(int speed) { setMotor(0, speed); setMotor(1, speed); } void carBackward(int speed) { setMotor(0, -speed); setMotor(1, -speed); } void carTurnLeft(int speed) { setMotor(0, -speed); setMotor(1, speed); } void carTurnRight(int speed) { setMotor(0, speed); setMotor(1, -speed); } void carStop() { setMotor(0, 0); setMotor(1, 0); }4. 核心功能实现与代码详解
有了基础的电机控制,我们现在来实现三个核心功能。
4.1 循迹功能实现
循迹算法的核心是根据五个传感器的状态,决定小车的转向策略。我们采用经典的“PID思想”(比例-微分-积分)的简化版——状态机法。
// 循迹传感器初始化 void trackSensorInit() { pinMode(TRACK_SENSOR_1, INPUT); pinMode(TRACK_SENSOR_2, INPUT); pinMode(TRACK_SENSOR_3, INPUT); pinMode(TRACK_SENSOR_4, INPUT); pinMode(TRACK_SENSOR_5, INPUT); } // 读取五路传感器状态,返回一个5位的二进制数 // 例如:0b00100 表示只有中间传感器检测到黑线 int readTrackSensors() { int sensorState = 0; sensorState |= (!digitalRead(TRACK_SENSOR_1)) << 4; // 最左 sensorState |= (!digitalRead(TRACK_SENSOR_2)) << 3; sensorState |= (!digitalRead(TRACK_SENSOR_3)) << 2; // 中间 sensorState |= (!digitalRead(TRACK_SENSOR_4)) << 1; sensorState |= (!digitalRead(TRACK_SENSOR_5)) << 0; // 最右 // 注意:很多传感器模块检测到黑线输出 LOW(0),所以用 ! 取反 // 这样 sensorState 中,1 代表检测到黑线,更直观。 return sensorState; } // 循迹控制主函数 void trackLine() { int state = readTrackSensors(); int baseSpeed = 150; // 基础速度 switch (state) { case 0b00100: // 000 中间传感器检测到线 case 0b01100: case 0b00110: carForward(baseSpeed); // 直行 break; case 0b00010: case 0b00011: case 0b00001: // 线偏右 carTurnLeft(baseSpeed); // 向左转以校正 break; case 0b01000: case 0b11000: case 0b10000: // 线偏左 carTurnRight(baseSpeed); // 向右转以校正 break; case 0b11111: // 所有传感器都检测到黑线,可能是十字路口或终点 case 0b00000: // 所有传感器都看不到线,可能脱线了 carStop(); // 这里可以添加更复杂的逻辑,比如路口转向或原地旋转寻线 break; default: carForward(baseSpeed); // 其他状态默认前进 } }代码逻辑解释:程序不断读取五个传感器的状态。如果只有中间传感器看到黑线,小车直行。如果黑线偏右(右侧传感器检测到),说明小车向左偏了,需要向左转来校正,反之亦然。这是一种非常直观且有效的控制方式。
4.2 避障功能实现
避障功能的优先级最高。我们使用一个简单的状态机:检测到障碍物就后退并转向,然后继续前进。
// 避障传感器初始化 void obstacleSensorInit() { pinMode(OBSTACLE_SENSOR, INPUT); } // 检测障碍物 bool checkObstacle() { // E18-D80NK有障碍物时输出 LOW return (digitalRead(OBSTACLE_SENSOR) == LOW); } // 避障反应函数 void avoidObstacle() { if (checkObstacle()) { Serial.println("障碍物!执行避障。"); carStop(); delay(200); carBackward(180); // 后退 delay(500); carStop(); delay(200); carTurnRight(200); // 向右转(你可以改为随机左转或右转) delay(300); carStop(); delay(200); // 避障动作完成后,跳出当前循环,让主循环重新判断模式 } }在主循环中,checkObstacle()的检测应该放在最前面,一旦为真,立即调用avoidObstacle(),并中断当前的循迹或跟随逻辑。
4.3 跟随功能实现
跟随功能依赖于超声波模块持续测距,并通过PID控制器来平滑地调整小车速度,使其保持设定距离。
首先,实现超声波测距函数。
// 超声波传感器初始化 void ultrasonicInit() { pinMode(ULTRASONIC_TRIG, OUTPUT); pinMode(ULTRASONIC_ECHO, INPUT); } // 获取距离(厘米) float getDistanceCM() { digitalWrite(ULTRASONIC_TRIG, LOW); delayMicroseconds(2); digitalWrite(ULTRASONIC_TRIG, HIGH); delayMicroseconds(10); digitalWrite(ULTRASONIC_TRIG, LOW); long duration = pulseIn(ULTRASONIC_ECHO, HIGH, 30000); // 超时30ms,约5米 // 声音速度 340 m/s = 0.034 cm/μs, 距离 = (时间 * 0.034) / 2 float distance = duration * 0.034 / 2.0; if (distance == 0 || distance > 500) { // 无效值处理 return -1.0; } return distance; }然后,实现一个简单的跟随控制器。
// 跟随控制参数 float targetDistance = 20.0; // 目标跟随距离 20cm float currentDistance = 0; float Kp = 3.0; // 比例系数,需要根据实际调试 // 跟随模式主函数 void followObject() { currentDistance = getDistanceCM(); if (currentDistance < 0) { // 测距无效,可能是超出范围或没有物体 carStop(); return; } float error = currentDistance - targetDistance; int speedAdjust = (int)(Kp * error); // 简单的P控制 // 限制速度范围 int baseSpeed = 150; int leftSpeed = baseSpeed + speedAdjust; int rightSpeed = baseSpeed + speedAdjust; // 速度限幅 leftSpeed = constrain(leftSpeed, -255, 255); rightSpeed = constrain(rightSpeed, -255, 255); setMotor(0, leftSpeed); setMotor(1, rightSpeed); // 如果距离太近,可以设置一个急停阈值 if (currentDistance < 10.0) { carStop(); delay(100); } }这个跟随逻辑非常基础。当测量距离大于目标距离时,error为正,speedAdjust为正,小车加速前进;反之则减速甚至后退。Kp系数需要在实际测试中调整,太大容易震荡,太小则反应迟钝。
5. 系统整合与主程序逻辑
现在,我们将所有功能整合到一个完整的程序中,并设计主循环的状态逻辑。
// 模式切换引脚(例如用一个按键或蓝牙指令,这里用宏定义模拟) #define MODE_SWITCH_PIN 0 // 假设用GPIO0接按键,低电平触发 void setup() { Serial.begin(115200); motorInit(); trackSensorInit(); obstacleSensorInit(); ultrasonicInit(); pinMode(MODE_SWITCH_PIN, INPUT_PULLUP); // 内部上拉 Serial.println("智能小车初始化完成!"); Serial.println("当前模式:循迹模式"); } void loop() { // 第一步:最高优先级,检查障碍物 if (checkObstacle()) { avoidObstacle(); // 避障后,短暂延迟并重新开始循环,避免模式混乱 delay(100); return; } // 第二步:检查模式切换(这里用按键模拟,实际可用蓝牙指令) if (digitalRead(MODE_SWITCH_PIN) == LOW) { delay(50); // 简单消抖 if (digitalRead(MODE_SWITCH_PIN) == LOW) { currentMode = (currentMode == MODE_TRACKING) ? MODE_FOLLOWING : MODE_TRACKING; Serial.print("切换到模式:"); Serial.println(currentMode == MODE_TRACKING ? "循迹" : "跟随"); carStop(); delay(500); // 模式切换停顿 while (digitalRead(MODE_SWITCH_PIN) == LOW); // 等待按键释放 } } // 第三步:根据当前模式执行相应功能 switch (currentMode) { case MODE_TRACKING: trackLine(); break; case MODE_FOLLOWING: followObject(); break; default: carStop(); } // 添加一个小延迟,稳定循环周期 delay(20); }主循环逻辑解读:
- 安全第一:每次循环最先检查障碍物,有则立即处理,处理完后
return跳出本次循环,确保避障动作不被其他逻辑打断。 - 模式管理:检查是否有切换模式的指令(示例中是按键)。切换模式时让小车暂停一下,避免状态突变导致失控。
- 功能执行:根据
currentMode变量,执行循迹或跟随函数。 - 循环延迟:一个固定的短延迟有助于稳定程序节奏,防止ESP32全速运行导致传感器读取不稳定。
6. 常见问题与调试技巧
在制作过程中,你几乎一定会遇到下面这些问题。这里提供排查思路。
6.1 电机不转或转动异常
| 问题现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 电机完全不转 | 1. 电源未接通或电压不足。 2. 电机驱动模块的STBY引脚未置高。 3. 控制引脚接线错误或接触不良。 4. 代码中电机控制引脚定义错误。 | 1. 用万用表测量电机驱动模块的VM和GND之间电压是否正常(7-12V)。 2. 检查STBY引脚是否接高电平或代码中是否设置为HIGH。 3. 逐一检查AIN1/AIN2/PWMA到ESP32的连线。 4. 在 setup()中先让电机以一个方向简单转动测试。 |
| 只有一个电机转 | 1. 不转的电机接线松动或损坏。 2. 对应的驱动芯片通道损坏。 3. 代码中只给了一个电机信号。 | 1. 交换两个电机的接线,如果问题跟随电机走,则是电机问题;如果问题跟随驱动通道走,则是驱动模块问题。 2. 使用 analogWrite()测试PWM引脚是否有输出。 |
| 电机抖动或转速慢 | 1. 电源功率不足(电池电量低)。 2. PWM频率不合适。 3. 机械结构卡顿。 | 1. 更换新电池或使用外接电源测试。 2. ESP32的 analogWrite()频率默认是1kHz,一般没问题。可以尝试更换引脚。3. 检查车轮是否安装过紧,齿轮箱是否有异物。 |
6.2 循迹传感器反应不灵敏或错误
- 问题:小车总是跑偏,或者对黑线没反应。
- 调试:
- 校准传感器:在
setup()中,将小车放在白纸和黑线上,用Serial.print()分别打印五个传感器的原始读数(digitalRead的值),确认检测到黑线和白纸时,输出是否稳定且相反。很多模块需要调节上面的电位器来调整检测灵敏度。 - 检查安装高度:传感器离地面太远或太近都会影响检测效果,一般距离地面1-2厘米为宜。
- 环境光干扰:强烈的环境光(特别是日光)会影响红外传感器。可以尝试在传感器上方加遮光罩,或者使用数字传感器(如灰度传感器)替代。
- 逻辑反了:确认代码中的逻辑。
!digitalRead()是因为我的模块检测到黑线输出LOW。如果你的模块相反,需要调整逻辑。
- 校准传感器:在
6.3 避障或跟随功能不稳定
- 超声波测距不准:
- 原因:HC-SR04对角度和物体表面材质敏感。绒布、斜面等会导致回波信号弱。
- 解决:确保被测物体表面平整;在
pulseIn函数中增加超时时间;对多次测量的距离取中值或平均值滤波。
// 示例:中值滤波函数 float getFilteredDistanceCM(int samples) { float distances[samples]; for (int i = 0; i < samples; i++) { distances[i] = getDistanceCM(); delay(30); // 两次测量间稍作延迟 } // 简单排序取中值(这里省略排序代码,可用`std::sort`) // ... 排序逻辑 ... return distances[samples / 2]; } - 避障模块误触发:
- 原因:E18-D80NK探测距离可调,可能被地面或车体自身部件触发。
- 解决:调节模块上的电位器,缩短有效探测距离;调整安装角度,使其略微朝上,避免检测到地面。
6.4 程序运行混乱或ESP32重启
- 电源问题:电机启动瞬间电流很大,可能导致ESP32电压被拉低而重启。务必为ESP32和电机驱动使用两套独立的电源(或一个电池通过两个稳压模块),并在电源输入端并联一个大电容(如1000μF)缓冲电流冲击。
- 代码阻塞:避免在
loop()中使用长延时delay(),这会导致传感器无法及时检测。对于需要延时的动作(如避障时的后退),可以考虑使用非阻塞的定时方式(millis())。 - 堆栈溢出:如果添加了太多功能或复杂的算法,注意检查串口监视器是否出现“Guru Meditation Error”等错误,这可能需要优化代码或调整FreeRTOS任务设置。
7. 优化与扩展方向
当你的基础功能都能稳定运行后,可以考虑以下优化和扩展,让小车更智能、更强大。
7.1 算法优化
- PID循迹:将上面简单的状态机换成真正的PID控制。通过计算位置偏差(例如,将五个传感器的状态映射为一个连续的位置值),用PID算法计算出更平滑的转向速度,使小车运行更稳定,过弯更流畅。
- 避障策略优化:当前的避障策略是固定的“后退-右转”。可以升级为:
- 随机转向:每次随机选择左转或右转,避免陷入死胡同。
- 测距扫描:配合舵机转动超声波模块,扫描左右两侧距离,选择更空旷的一侧转向。
- 跟随模式优化:引入完整的PID(比例-积分-微分)控制,并加入死区和输出限幅,让跟随过程更加平稳,减少在目标距离附近的来回震荡。
7.2 功能扩展
- 无线控制与监控:利用ESP32自带的Wi-Fi或蓝牙。
- 手机APP遥控:开发一个简单的APP或使用现成的蓝牙串口助手,切换模式、手动控制小车。
- Web服务器:让ESP32作为一个Web服务器,通过浏览器可以实时查看传感器数据、摄像头画面(需额外模块)并控制小车。
- 数据上传:将小车的状态、传感器数据上传到物联网平台(如阿里云、ThingsBoard),实现远程监控。
- 增加视觉功能:使用ESP32-CAM模块,实现颜色识别、人脸跟踪、二维码导航等更高级的AI功能。
- 多传感器融合:增加MPU6050陀螺仪和加速度计,实现更精确的直线行走和角度控制。结合编码器电机,可以实现精确的里程计计算。
7.3 工程化建议
- 电源管理:这是项目稳定的基石。强烈建议使用带有稳压功能的电源模块(如LM2596)单独为ESP32提供稳定的5V或3.3V。电机电源则直接接电池。
- 结构加固:使用尼龙柱、螺丝将各模块牢固地固定在底盘上,避免因震动导致线材松动。
- 代码模块化:将不同功能的代码进一步封装成独立的
.h和.cpp文件,例如MotorDriver.h、SensorHub.h、PIDController.h等,使主程序非常简洁,便于维护和移植。 - 参数可配置:将PID参数、速度、目标距离等变量放在程序开头,或者通过串口命令动态调整,方便调试。
从零开始整合ESP32、多种传感器和电机驱动,完成一个具备循迹、避障、跟随功能的智能小车,是一个非常好的嵌入式系统入门项目。它不仅涵盖了GPIO控制、PWM调速、传感器数据采集、中断处理等基础知识点,还涉及到多任务调度、控制算法等进阶概念。
调试过程中,耐心和系统性排查是关键。务必遵循“电源先行,分步测试”的原则:先确保电机能动,再调循迹,然后加入避障,最后整合跟随。每增加一个功能,就充分测试其独立性和与原有功能的兼容性。
希望这份详细的教程和代码能为你提供一个坚实的起点。你可以在此基础上自由发挥,添加更多传感器、更优的算法或酷炫的无线功能,打造出属于你自己的独一无二的智能小车平台。