☰
竞速机器人48.47秒成绩背后的运动控制与调试全链路解析
2026/10/14 12:22:38 网站建设 项目流程

当看到“荣耀机器人元气仔以 48.47 秒的成绩夺得亚军”这样的赛报时,很多人的第一反应是“这个机器人好快”。但如果你自己动手做过竞速类机器人,就会明白,48.47 秒这个数字背后,并不是电机转速的简单堆叠,而是一整套运动控制、传感融合、路径规划和调试方法的协同结果。

计时类机器人赛项是对工程能力非常综合的考核:直线能不能跑直,弯道能不能按最优轨迹切过,停车能不能停准,重复运行时成绩是否稳定。任何一个环节出现 10% 的误差,总成绩就可能从 48 秒掉到 55 秒以上。本文不评价具体赛队,而是把这个 48.47 秒当作一个典型性能目标,拆解竞速机器人从底盘选型到路径控制、再到实际调试的完整链路。读完你可以回答三个问题:这类机器人到底在比什么?50 秒以内的成绩是怎么被拆出来的?如果自己搭一台比赛机器人,应该优先解决哪些环节?

1. 计时类机器人赛项到底在比什么

很多人以为竞速机器人赛项就是“谁跑得快”,这是最常见的误解。计时类赛项(包括巡线竞速、工程任务赛、轨迹赛)有两个指标同时起作用:一是完成任务需要的时间,二是任务完成的规范性。跑得快但撞到赛道边界、漏掉任务点、冲过停车区,都会被罚时甚至直接取消成绩。

一个 48.47 秒的成绩,我们可以从时间维度做一个粗略拆解。假设赛道长度为 30 到 40 米,中间包含直道、大弯、S 弯、十字路口和停车区,那么机器人平均速度大约在 0.7 到 0.9 米/秒。这个速度对高性能四驱模型车来说并不算高,难点在于:

  • 弯道速度不能太慢,否则时间全耗在转向里;
  • 直道速度不能持续太猛,否则入弯时容易冲出赛道;
  • 停车时必须停在指定区域,位置偏差不能超过几厘米;
  • 整个过程中传感器数据、电机调速、控制决策要实时同步,延迟超过 20ms 就可能造成明显的过冲。

所以赛项本质上考的是“在保证任务完成率的前提下,把整条赛道的速度曲线优化到极限”。它不是单点技术比拼,而是系统工程:机械底盘决定速度上限,传感器决定感知精度,控制算法决定动态响应,代码结构决定调试效率。任何一个短板都会变成时间成本。

这篇文章讨论的“元气仔”属于这类竞赛机器人中的一个典型形态:中小尺寸、轮式驱动、由嵌入式主控板控制、通过传感器感知路径。下面所有技术拆解都以这种形态为例,泛化到其他底盘结构也同样适用。

2. 竞速机器人的运动模型与底盘选型

优化任何一台竞速机器人之前,必须建立运动模型。运动模型决定了你能用什么样的控制策略,也决定了代码里速度指令应该怎么下发。

2.1 差速底盘:竞速项目最常用的模型

竞速机器人最常用的底盘是“两轮驱动 + 万向轮”或“四轮驱动”的差速结构。差速模型的核心是:左右两侧轮子的速度不同,机器人就会转向。用公式表示:

  • v 是机器人中心线速度;
  • ω 是机器人旋转角速度;
  • vL 和 vR 分别是左右轮线速度。

当 vL = vR,直行;当 vL < vR,机器人向右偏转;反之向左。差速模型的控制量可以抽象成两个:目标线速度和目标角速度。上层算法只需要关心“现在该走多快、该以多大弧度转弯”,底层负责把目标换算成左右电机的实际 PWM 占空比。

2.2 底盘对比:不是越复杂的底盘越快

底盘类型机动性直线稳定性传动效率控制复杂度适合场景
二轮差速中中高低简单轨迹、短赛道
四轮差速中高高中长直道、重型任务车
三轮全向高低中高全向移动任务,不适合高速竞速
四轮麦克纳姆高低低高全向平移任务,速度劣势明显

这里的关键判断是:很多新手觉得“全向轮能横移,肯定更先进”,但高速竞速场景恰恰是差速底盘的主场。全向轮依靠辊子接触地面,直线行驶时能量损耗更大,而且每个辊子的接触状态会引入高频抖动,对巡线传感器和陀螺仪的稳定性都不友好。差速底盘结构简单、可靠、反馈线性度好,更适合把时间投入在控制算法优化上。

2.3 底盘参数对时间的影响

底盘参数直接决定了控制带宽。需要关注三个参数:

  • 轮径:轮径越大,单位转速下的线速度越高,但加速力矩要求也越大。轮径 65mm 到 80mm 是比较常见的比赛区间。
  • 轴距:轴距越长,直线稳定性越好,但转弯响应越迟钝。竞赛车为了灵活性,轴距通常控制在 120mm 到 180mm。
  • 减速比:电机减速比决定最大速度与扭矩的平衡。比赛车常用的 N20 电机,减速比 30:1 到 60:1 都有,具体选型要看赛道平均速度需求。

如果你手上已经有一台成品车,先测量这些参数,再把它们写进代码配置里。后续所有速度规划都会依赖这些物理常数。

3. 控制闭环:为什么 50 秒以内的成绩离不开 PID

竞速机器人的核心控制问题是:给定目标速度,机器人实际速度能不能快速而准确地跟上。如果你只是写死 PWM 占空比,会发现同一个 PWM 在不同电池电压下速度差很多,左轮和右轮即使在相同 PWM 下转速也不一致。没有闭环控制,直线会越跑越偏,弯道会忽快忽慢,成绩自然不稳定。

PID 是最常用的闭环控制方法。它根据“目标值与当前值的误差”计算输出:

  • P(比例)根据当前误差输出,误差越大,输出越大;
  • I(积分)消除长期稳态误差;
  • D(微分)根据误差变化率提供阻尼,抑制超调。

在实际比赛中,有两种 PID 是必不可少的:

  1. 速度环 PID:让左右轮的实际线速度分别稳定在目标值;
  2. 转向环 PID:根据传感器偏差实时调整机器人方向,让车体尽量贴合赛道中心线。

这两种 PID 属于串级结构:外层转向环输出期望角速度,内层速度环输出期望 PWM。不过对于入门到中级的竞速机器人,很多队伍会把转向环直接映射到左右轮的速度差,也能跑出不错成绩。下面优先介绍最实用的实现方式。

4. 环境准备与开发板选型

比赛机器人主控的选择通常围绕生态成熟度和实时性展开。单片机能直接操作 GPIO、定时器、PWM 和中断,相比树莓派等高系统平台,实时性更好,启动更快,更适合高速运动控制。

常用组合有:

主控平台语言优点注意事项
STM32 系列C/C++定时器资源丰富,实时性强开发环境配置相对复杂
Arduino MEGA / DueC++上手最快,资料多单片机性能有限,编码器计数请加中断
Raspberry Pi PicoMicroPython / C性价比高,MicroPython 调试方便高级定时器需要查阅 Datasheet
ESP32 系列Arduino / ESP-IDF带 WiFi,方便调参ADC 精度一般

如果目标是比赛实战,更推荐采用“单片机主控 + 电调/电机驱动板”方案。以本文示例为例,我会使用 Raspberry Pi Pico + MicroPython 来实现核心控制,因为它的代码可读性高、串口交互方便,便于读者快速复现。工程上要迁移到 STM32,控制思路完全一致。

需要准备的材料:

  • 一台差速底盘(两个带编码器的直流减速电机);
  • 一个双 H 桥电机驱动模块(如 TB6612 或 DRV8833);
  • 主控板一块(Pico 或其他单片机);
  • 一个 4 到 8 路灰度传感器阵列,或一个能输出 8 位灰度值的巡线模块;
  • 锂电池组(7.4V 2S 是常见选择);
  • USB-TTL 串口模块,用于调试输出;
  • 杜邦线、面包板、万用表。

版本信息以你实际拿到的硬件为准。本文重点演示通用思路,不绑定某个特定驱动库。

5. 核心实现:编码器测速与电机调速代码

很多队伍在代码上容易犯的错误是:先写一大段逻辑,然后发现电机根本不动,也不知道是接线问题还是代码问题。正确的顺序是“最底层先跑通”:先让电机能转,再让编码器能量到,最后才上 PID 闭环。

5.1 电机 PWM 驱动代码

以 MicroPython 为例,先写一个最基本的电机驱动函数。

# 文件路径:main.py(片段,仅演示电机驱动) from machine import Pin, PWM import time # 假设左边两个引脚是方向和控制 # 这里使用 TB6612 驱动模块 LEFT_AIN1 = Pin(10, Pin.OUT) LEFT_AIN2 = Pin(11, Pin.OUT) LEFT_PWM = PWM(Pin(12), freq=20000) def left_motor(speed): # speed 范围 -100 到 100 if speed > 0: LEFT_AIN1.value(1) LEFT_AIN2.value(0) elif speed < 0: LEFT_AIN1.value(0) LEFT_AIN2.value(1) else: LEFT_AIN1.value(0) LEFT_AIN2.value(0) LEFT_PWM.duty_u16(int(abs(speed) * 65535 / 100)) # 测试左电机正转 50 left_motor(50) time.sleep(2) left_motor(0)

这段代码的核心是把速度值抽象成 -100 到 100 的归一化量,后期做 PID 时不用每次都换算 PWM 范围。需要注意的是,PWM 频率不要设得太低,一般 15kHz 到 25kHz 可以避免电机发出尖锐噪音。

5.2 编码器读取与测速

编码器的作用是测量电机实际转速。多数直流减速电机搭配霍尔编码器,输出 A、B 两路脉冲。通过 A 相和 B 相的相位关系,可以判断旋转方向。下面代码演示用中断方式简单计数。

# 文件路径:encoder.py from machine import Pin class Encoder: def __init__(self, pin_a, pin_b, ppc=20): self.ppc = ppc # 每圈脉冲数,根据具体编码器修改 self.pin_a = Pin(pin_a, Pin.IN, Pin.PULL_UP) self.pin_b = Pin(pin_b, Pin.IN) self.count = 0 self.pin_a.irq(handler=self._update, trigger=Pin.IRQ_RISING) def _update(self, pin): # A 相上升沿时,检查 B 相电平判断方向 if self.pin_b.value(): self.count -= 1 else: self.count += 1 def reset(self): self.count = 0

这个实现策略是:只在 A 相上升沿进入中断,再读 B 相电平判断方向。相比 4 倍频解码,它的中断频率低,适合 MicroPython 这种解释执行环境。高速场景下如果发现漏脉冲,可以改用 C 语言硬件定时器解码。

5.3 速度 PID 闭环

测速得到的是一个累积脉冲数,要转成速度需要记录单位时间内的增量。下面实现一个周期性速度 PID。

# 文件路径:speed_controller.py class SpeedPID: def __init__(self, kp, ki, kd, sample_time=0.02): self.kp = kp self.ki = ki self.kd = kd self.sample_time = sample_time self.target = 0 self.integral = 0 self.last_error = 0 def set_target(self, speed): self.target = speed def update(self, current_speed): error = self.target - current_speed self.integral += error * self.sample_time # 积分限幅,防止 windup self.integral = max(-50, min(50, self.integral)) derivative = (error - self.last_error) / self.sample_time output = self.kp * error + self.ki * self.integral + self.kd * derivative self.last_error = error # 输出限幅 return max(-100, min(100, output))

在主循环里,每 20ms 读取一次左右编码器增量,计算实际速度,再用两个 SpeedPID 分别输出左右电机 PWM。这样就能保证左右轮速度尽量一致,直道跑得直,弯道跑得稳。

6. 基于灰度传感器的路径识别与转向控制

有了速度闭环,机器人已经能跑直线,但比赛赛道在不停变化方向,所以还需要路径识别。最常用的传感器是红外灰度阵列,它通过地面反射率判断当前传感器下方是白色赛道还是黑色引导线。

6.1 传感器偏差计算

灰度阵列通常返回一组二值数据,例如 8 位数字,每一位代表一个传感器是否压线。好的处理方式是把“压线位置”映射为一个偏差值 error,例如:

  • error = 0 表示车在线的正中心;
  • error = 正数表示机器人偏向线的左侧;
  • error = 负数表示机器人偏向线的右侧。

一个简单的加权平均实现:

# 文件路径:line_sensor.py class LineSensor: def __init__(self, values): # values 是一个 0/1 列表,0 为未检测到线 self.values = values def get_error(self): weight = [-3, -2, -1, 0, 1, 2, 3] # 这里假设 7 路传感器,中心传感器权重为 0 total = 0 count = 0 for i, v in enumerate(self.values): total += weight[i] * v count += v if count == 0: # 丢线:返回一个较大偏差,让转向逻辑加大纠偏 return self.last_error * 2 if abs(self.last_error) > 1 else 8 self.last_error = total / count return self.last_error

丢线情况非常关键。在高速过弯时,传感器有可能全部离开黑线。如果此时直接把偏差置 0,车就会直线冲出赛道。更稳妥的策略是记住上一次有效偏差,并让输出继续沿原方向加大纠偏,直到重新检测到线。

6.2 转向 PID 与速度联动

转向 PID 的输出可以理解为左右轮的差速分配。简单做法是:

base_speed = 45 # 直道基础速度 turn_gain = 8 # 转向增益,需实测调整 error = sensor.get_error() correction = turn_gain * error left_speed = base_speed + correction right_speed = base_speed - correction

这样做在慢速巡线时有效,但高速时容易出现两个问题:一是入弯时速度没有降低,转弯半径太大;二是出弯时速度恢复太慢,白白浪费时间。更合理的方式是把 base_speed 也做成传感器偏差的函数,偏差越大,速度越低,从而自动实现入弯减速、出弯加速。

def compute_speed(error): # 偏差越大,基础速度越低 speed = 55 - abs(error) * 6 return max(25, min(55, speed))

这样一来,机器人可以做到“直道加速、弯道减速”的自然匹配,不需要人工去设置每个弯道的位置。

7. 点位任务、停车与精度验证

计时赛往往不止“跑一圈”这么简单。很多赛题会在赛道中设置任务点,要求机器人停在指定区域、完成特定动作,或者精准停车。停车精度直接影响罚时,是成绩不稳定的重要来源。

停车控制的一个核心思想是:不要等到传感器已经看到停车标志才刹车。因为机器人有惯性,从发出停车指令到完全停下还需要滑行一小段。正确做法是提前在代码中设定一个“预停车距离”或用编码器累计位移判断。

# 文件路径:stop_controller.py # 假设已经知道目标停车位置对应的编码器累计数 stop_count def check_stop(encoder_left, encoder_right, stop_count, allow_error=20): avg_count = (encoder_left.count + encoder_right.count) // 2 if abs(avg_count - stop_count) <= allow_error: left_motor(0) right_motor(0) return True return False

如果要更精确地控制停车位置,可以采用位置 PID。位置 PID 的目标不是速度实时相等,而是“位置逐渐逼近目标”。当编码器累计数接近目标时,速度输出自动减小,让车缓慢停稳,避免高速急停带来的滑行误差。

建议在赛前把所有关键位置都标定成编码器累计数:起点、每个任务点、停车区。比赛时读取编码器数据,就能判断当前位置离目标还有多少距离。

8. 运行结果与效果验证

到这一节为止,代码已经把“电机驱动—编码器测速—速度闭环—巡线转向—停车控制”串起来了。但写完代码不等于跑得好,必须用数据验证三个指标。

8.1 用串口观察速度曲线

启动机器人,在直道上给定目标速度 50,通过串口打印实际速度,正常曲线应该迅速接近 50 且没有明显振荡。如果实际速度围绕目标值大幅波动,说明 PID 参数 P 过大或 D 过小。

# 串口调试终端 minicom -D /dev/ttyUSB0 -b 115200

预期输出示例:

target: 50.00, current: 49.82, pwm: 48.10 target: 50.00, current: 50.11, pwm: 49.80 target: 50.00, current: 49.95, pwm: 50.02

相邻周期差值在 2 以内,基本合格。

8.2 用计时器验证整圈用时

在起点放置一个光电门,或者用程序在按下启动按钮后开始计时,完成停车后停止计时。多次测量取平均值和方差。如果方差超过 3 秒,说明机器人轨迹重复性差,优先检查左右轮参数是否一致、传感器安装是否松动、电池电量是否充足。

8.3 如果成绩不稳定,第一排查顺序

  1. 看左右轮编码器读数是否同步;
  2. 看弯道丢线是否频繁;
  3. 看停车滑行距离是否每次不同;
  4. 看电池电压,赛前 7.4V 和赛后 7.2V 对电机速度影响很大。

每轮测试都记录串口日志和圈时,数据化分析才能定位问题。

9. 常见问题与排查思路

问题现象可能原因排查方式解决方案
电机不转PWM 引脚或方向引脚接反用万用表检查引脚电平对照 PCB 原理图重新接线
直线跑偏左右轮机械阻力不一致旋转车轮感受阻力差异检查轴承、齿轮啮合,必要时换轮
速度 PID 振荡P 过大或积分限幅太高串口观察速度曲线降低 P,检查积分限幅
弯道冲线入弯速度过快或 D 过小慢速回放轨迹录像降低 base_speed 的弯道最小值
丢线后乱转丢线处理逻辑错误打印丢线时的 error 值采用“保留上次偏差并增益放大”策略
停车过冲刹车太晚记录刹车点编码器值提前刹车距离或改位置 PID
同一套程序两次成绩差 5 秒电池电量或传感器被遮挡测量电池电压、清洁传感器赛前充电,固定传感器支架

这里特别强调一点:传感器安装高度对巡线影响巨大。灰度传感器离地面太高,反射值边界模糊;太低,过粗糙赛道时容易刮擦。一般建议安装高度在 8mm 到 15mm 之间,并且要保证所有传感器离地高度一致。

10. 竞速机器人调优的最佳实践

跑进 50 秒以内不能靠“运气好”,而是靠一套可复现的调试流程。下面这些建议来自大量竞赛队伍的共同经验,适合直接落到工程里。

10.1 参数不要散落在代码里

把 PID 参数、基础速度、转向增益、停车点位置都集中到一个配置文件中。比赛现场调参时会大幅减少改代码的时间。

# 文件路径:config.py BASE_SPEED = 55 MIN_SPEED = 25 TURN_GAIN = 8 SPEED_ERROR_GAIN = 6 LEFT_KP = 18 LEFT_KI = 2 LEFT_KD = 0.5 RIGHT_KP = 18 RIGHT_KI = 2 RIGHT_KD = 0.5 STOP_COUNT = 2400

现场调试时只需调整这一组常量即可。

10.2 建立“测试—记录—调整”循环

不要一口气把所有参数调到位。先固定直线速度,再调弯道减速,最后调停车。每次修改只动一个参数,记录修改前后的圈时和现象。用表格管理调试记录,比凭感觉试要有效得多。

10.3 提前做好电池管理和温度保护

电池电压下降会导致同样的 PWM 下电机转速下降。如果比赛分多轮,建议每轮之间测量电压,并在代码里做电压补偿:电压低时自动提高 PWM 上限。另外,长时间堵转会让电机驱动板过热,可以在驱动芯片上贴散热片。

10.4 机械结构要固定,电气线路要防抖

比赛过程中机器人会高频振动,杜邦线接口很容易松动。建议所有信号线用扎带固定,电源线采用焊点连接。传感器支架使用金属或硬质塑料,不能用热熔胶粘一下就完事。

10.5 留出断点调试手段

在代码里增加调试模式开关。比赛时可以把调试输出关掉,节省串口带宽;平时测试时打开,方便实时观察每个传感器状态、编码器计数和 PID 输出。一个典型的调试指令可以是:

# 文件路径:main.py DEBUG = False # 比赛时改为 False

这行配置看似简单,实际能帮你省下大量现场排查时间。

11. 回到 48.47 秒:一个合格的竞速系统应该具备什么

回到“元气仔”夺得亚军的 48.47 秒。这个成绩不一定是全场最快,但从获奖角度看,它至少说明这台机器人在几个关键维度上没有明显短板:

  • 机械和驱动系统有足够的响应速度和稳定性,不会因为电机差异导致轨迹发散;
  • 传感器数据处理得当,弯道丢线概率低,停车定位比较可靠;
  • 控制算法兼顾了直道速度与弯道通过性,没有因为过度保守而浪费大量时间;
  • 调试流程到位,能够在赛前把参数收敛到合理区间。

也就是说,当你看到 48.47 秒时,不应该只把它理解为“电机转速很快”,而要把它理解为“电机控制、路径感知、逻辑决策、机械可靠性”四个层面的综合结果。

如果你想自己复现类似的成绩,建议不要从赛前两周才开始搭建。正确路径是:先用最简单的 2 到 3 米折返赛道跑通整套代码,确认底层可靠;再逐步加入弯道、S 弯、停车任务;最后才针对完整赛道优化参数。底层不稳时调上层参数,只会越调越乱。

下一步可以深入的方向包括:使用傅里叶变换分析曲线轨迹的振动频率、引入陀螺仪辅助姿态估计、用离线路径规划预先设定每个区段的目标速度。这些都建立在本文这套基础闭环之上。先把基础闭环跑稳,再考虑更高级的优化,是竞速机器人项目最稳妥的推进方式。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询