ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

轮腿机器人竞赛实战复盘:从机械结构到PID与视觉识别的工程优化

轮腿机器人竞赛实战复盘:从机械结构到PID与视觉识别的工程优化 趁着比赛刚结束记忆还在热乎劲儿我把这次浙江轮腿赛从备赛、调试到上场的完整过程写下来。拿第四名止步省二说不遗憾是假的但复盘之后发现成绩背后暴露出来的技术问题才是真正值得记录的。这篇文章不打算写成情绪宣泄而是作为一名开发者的视角把轮腿机器人从机械结构、运动控制、视觉识别到整机联调的实战经验完整拆开。如果你也准备参加机器人竞赛或者正在做轮腿相关的项目这篇文章应该能帮你少踩不少坑。从拿到第四名离场到回学校重新整理代码和调试记录我意识到一个事实第四名和省一等奖之间的距离不是运气而是从稳定性、容错性到临场决策力的一整套工程差距。下面这篇文章就是这套差距的完整复盘。1. 轮腿机器人竞赛到底在比什么1.1 轮腿机器人的技术定位轮腿机器人简单理解就是“轮子加腿”的复合结构。它结合了轮式移动的高效性和腿式结构的越障能力。从结构类型上看常见的方案有几类结构方案特点适用场景四轮 前后摇臂结构简单稳定性最高平地竞速、轻度越障两轮自平衡体型小控制难度高狭窄通道、姿态展示四轮 主动腿关节可以主动迈步、抬腿越障高障碍、台阶、复杂地形轮毂电机 悬挂机械效率高响应快高速巡航、赛道类任务我们这次采用的是“四轮 前后摇臂 后轮独立驱动”的方案属于偏保守但可靠度较高的设计。从最终得分来看机械结构的可靠性是整个比赛的基础但它不是决定排名的唯一因素。1.2 竞赛评分维度拆解很多第一次参加轮腿赛的队伍会把精力全部放在“跑得够不够快”上。但实际评分维度要复杂得多。根据我们赛前拿到的评分细则大致可以分为几个方向任务完成度是否在限定时间内完成所有规定动作这是权重最高的一项。稳定性机器人在运行过程中是否出现摔倒、卡死、冲出赛道等情况。识别准确率对场地中的标识、颜色、数字或物体进行识别的正确率。速度与完成时间在保证完成度和稳定性的前提下用时越短分数越高。现场应变如果赛场环境与训练环境不一致机器人能否通过参数调整或决策逻辑快速适应。换句话说轮腿竞赛比拼的是一个系统工程能力。单项突出不够必须全面稳健。1.3 为什么我们拿到了第四名我们队最终的成绩是第四名拿到省级二等奖。复盘整个比赛过程我们的速度和越障能力其实都在前三名的水平线上真正拉开差距的是两个地方稳定性不够排名前三的战队在连续两轮比赛中几乎没有出现机器人摔倒和识别失误而我们在第二轮出现了一次过障碍时重心偏移导致的卡壳耽误了关键时间。环境适应性不足赛场的光线强度和地面摩擦系数与训练场地存在差异我们的视觉识别参数和运动控制参数没有来得及快速调整导致部分动作出现迟滞。这些问题的根源不是某一个模块的缺陷而是赛前测试没有按照“比赛环境”的标准来执行。这一点我会在后面用一整个章节详细展开。2. 赛前准备环境搭建与关键参数约定2.1 实验平台与系统说明先说明我们队伍使用的软硬件环境这里写出来供大家参考具体版本需要根据你手头的设备灵活调整。硬件部分主控板STM32F407 开发板运动控制协处理器树莓派 4B视觉识别与上层决策电机直流减速电机 × 4带霍尔编码器姿态传感器MPU6050六轴陀螺仪 加速度计摄像头USB 免驱摄像头720P60FPS电源11.1V 3S 锂电池软件部分嵌入式开发STM32CubeIDE HAL 库视觉处理Python 3.8 OpenCV 4.5通信方式串口UART进行数据透传调试工具Serial Studio串口数据可视化、VNC Viewer远程桌面需要说明的是这套组合并不是什么稀缺硬件STM32 加树莓派是竞赛圈非常经典的主从架构。主控负责实时性要求高的运动控制协处理器负责算力需求大的视觉任务两者通过串口通信协作。2.2 软件工具链配置如果你的环境和我类似建议按下面顺序配置# 树莓派端视觉处理 sudo apt update sudo apt install python3-pip pip3 install opencv-python numpy pyserial # Windows 端串口调试辅助 # 安装串口调试助手或使用 Python pyserial 编写调试脚本STM32 端建议直接用 STM32CubeMX 生成工程骨架然后集成 MPU6050 驱动和 PID 控制代码。这里有一个非常实用的建议在正式写控制逻辑之前先把串口通信协议定好否则后期联调会非常痛苦。2.3 赛前必须维护的参数文档这是我认为本次比赛中最应该早做的一件事建一个参数配置表。轮腿机器人的参数数量远超普通小车。我们最后统计了一下机械尺寸参数、PID 参数、视觉 HSV 阈值、速度上限、障碍判断阈值加起来超过 60 个。如果没有一份清晰的参数文档到了赛场根本不知道改了哪个参数会导致什么结果。我建议的参数文档格式如下参数名当前值作用范围最后修改日期备注pid_balance_kp22.5平衡环 P2025-03-10负载增加后需要上调pid_balance_ki0.15平衡环 I2025-03-10过大容易振荡hsv_red_low(0, 120, 70)红色标识识别2025-03-12依赖场地光线max_speed750最大轮速2025-03-13单位 encoder 值这份表不仅帮助我们在联调时快速定位问题也在赛场上帮助我们快速恢复参数。比赛间隙只有几十分钟靠脑子记 60 个参数根本不可能。2.4 时间规划与任务拆解按照我们三个月的备赛周期时间分配大致如下第 1 个月机械结构搭建 电机驱动调试第 2 个月运动控制闭环平衡、转向、速度控制第 2.5 个月视觉识别模块开发并与主控联调最后两周场地模拟测试 参数调优 应急预案这个节奏整体来说是合理的但我们在最后两周犯了一个错误过度追求新功能而没有把已经实现的功能做回归测试。结果就是我们在赛前三天修改了视觉 HSV 阈值导致原先稳定的识别逻辑出现波动而这个问题直到比赛前一天晚上才发现。3. 核心模块拆解从机械到运动控制3.1 机械结构设计中的重心控制轮腿机器人的机械结构设计核心不是“结实”而是“重心”。我们这次采用的方案把电池放置在下底盘中央主控板和树莓派分层安装在电池上方摄像头安装在前支架顶部。整体重心控制在底盘平面投影的中心区域这是保证平衡控制有效的前提。如果你自己设计轮腿结构需要重点注意以下三个原则重心越低越好重心越低机器人抗倾覆能力越强平衡控制越容易。左右严格对称左右质量差会导致转向偏航控制上需要额外补偿。轮距和轴距的比例要适中轮距太窄容易侧翻轴距太长影响转向灵活性。3.2 姿态解算MPU6050 数据融合姿态解算是轮腿机器人平衡控制的第一环。通过 MPU6050 获取三轴加速度和三轴角速度然后通过合适的融合算法得到机器人的俯仰角。我们使用的是互补滤波算法。相比卡尔曼滤波互补滤波计算量小、调参简单在 STM32 上运行非常合适。核心思路是高频段信任陀螺仪的角速度积分低频段信任加速度计的姿态解算通过一个系数 α 进行融合。// 文件路径Src/attitude.c // 互补滤波姿态解算核心代码 #define ALPHA 0.96f // 互补滤波系数需要根据实际传感器调整 #define RAD_TO_DEG 57.29578f float dt 0.005f; // 采样周期 5ms float angle_gyro 0.0f; // 陀螺仪积分角度 float accel_angle 0.0f; // 加速度计解算角度 float angle_output 0.0f; // 最终姿态角 void Attitude_Update(float gx, float gy, float gz, float ax, float ay, float az) { // 1. 通过加速度计解算俯仰角注意传感器安装方向 accel_angle atan2f(-ax, az) * RAD_TO_DEG; // 2. 陀螺仪积分gx 是绕 X 轴的角速度即俯仰角速度 angle_gyro gx * dt; // 3. 互补滤波融合 angle_output ALPHA * (angle_output gx * dt) (1.0f - ALPHA) * accel_angle; }这里有一个非常重要的细节加速度计解算的角度在运动剧烈时噪声很大陀螺仪积分长期运行会产生漂移。因此互补滤波系数的选择需要权衡响应速度和噪声抑制。我们最终把 ALPHA 设置为 0.96也就是 96% 信任陀螺仪、4% 信任加速度计在平衡车上表现比较稳定。3.3 串级 PID 平衡控制轮腿机器人的运动控制采用的是经典的串级 PID 结构外环为角度环内环为角速度环或速度环。串级 PID 的优势在于外环输出作为内环的目标值内环可以更快地抑制扰动。比如机器人受到外部冲击时角速度会瞬间变化内环可以快速响应不需要等待外环计算。// 文件路径Src/motion_control.c // 串级PID控制核心代码角度环 角速度环 typedef struct { float target; float actual; float kp; float ki; float kd; float integral; float previous_error; float output; } PID_t; // 位置式 PID 计算 float PID_Calculate(PID_t *pid, float target, float actual) { float error target - actual; pid-integral error; if (pid-integral 1000.0f) pid-integral 1000.0f; if (pid-integral -1000.0f) pid-integral -1000.0f; float derivative error - pid-previous_error; pid-previous_error error; pid-output pid-kp * error pid-ki * pid-integral pid-kd * derivative; return pid-output; } // 串级控制入口 float target_angle 0.0f; // 目标角度0 为直立 float current_angle 0.0f; // 姿态解算得到的当前角度 float current_gyro 0.0f; // 当前角速度 PID_t angle_pid {0.0f, 0.0f, 18.0f, 0.05f, 0.5f, 0.0f, 0.0f, 0.0f}; PID_t gyro_pid {0.0f, 0.0f, 2.5f, 0.0f, 0.05f, 0.0f, 0.0f, 0.0f}; float target_gyro, motor_output; void MotionControl_Loop(void) { // 外环角度环输出为角速度目标 target_gyro PID_Calculate(angle_pid, target_angle, current_angle); // 内环角速度环输出为电机 PWM motor_output PID_Calculate(gyro_pid, target_gyro, current_gyro); // 输出到电机驱动注意左右电机方向相反 Motor_SetPWM(motor_output); }在调参过程中我建议按这个顺序只调角度环 P让机器人能“硬扛”住不倒即使会振荡。加入角速度环抑制振荡的核心让动作变得平顺。再逐项加入 I 和 D消除静差提升动态响应。最后联调转向和速度在直立稳定基础上叠加运动控制。3.4 电机驱动与编码器反馈轮腿机器人对电机响应速度要求很高。我们使用的是带霍尔编码器的直流减速电机通过正交解码获取轮子转速和位置信息用于速度闭环。电机驱动我们采用常见的 H 桥驱动方案通过 PWM 控制电机的速度和方向。// 文件路径Src/motor.c // 电机 PWM 输出核心代码简化示意 void Motor_Init(void) { HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_1); // 左电机 HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_2); // 右电机 HAL_TIM_Encoder_Start(htim3, TIM_CHANNEL_ALL); // 编码器 } void Motor_SetPWM(int16_t pwm_value) { if (pwm_value 1000) pwm_value 1000; if (pwm_value -1000) pwm_value -1000; if (pwm_value 0) { __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_1, pwm_value); __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_2, 0); } else { __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_1, 0); __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_2, -pwm_value); } }需要注意的是电机 PWM 如果设置过大会导致电流急剧上升主控板电压跌落甚至直接引起单片机复位。我们就在联调时遇到了这个问题后来通过在电源端加装大电容并限制最大 PWM 值解决了。4. 视觉识别与决策逻辑4.1 视觉方案的整体架构视觉部分运行在树莓派上使用 OpenCV 进行图像处理识别结果通过串口发送给 STM32。整体流程如下摄像头采集 → 图像预处理 → 颜色/目标识别 → 坐标计算 → 串口发送 → STM32 决策竞赛中需要识别的目标通常包括红色标识、绿色区域、数字标签等颜色识别是最基础也是最可靠的方案。4.2 基于 HSV 的颜色识别颜色识别最常用的方法是把图像从 BGR 转换到 HSV 颜色空间然后通过设定阈值提取目标颜色区域。HSV 相比 BGR 对光照变化更鲁棒但也不是完全免疫。这一点在比赛中给我们造成过麻烦后面会专门讲。# 文件路径vision/color_detect.py # 颜色识别核心代码 import cv2 import numpy as np def detect_red_area(image): 检测图像中的红色目标区域返回目标中心坐标和面积 # BGR 转 HSV hsv cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 红色的 HSV 范围需要根据场地实际情况调整 lower_red1 np.array([0, 120, 70]) upper_red1 np.array([10, 255, 255]) lower_red2 np.array([170, 120, 70]) upper_red2 np.array([180, 255, 255]) # 红色在 HSV 中分布在 0° 和 180° 两端需要两次掩膜 mask1 cv2.inRange(hsv, lower_red1, upper_red1) mask2 cv2.inRange(hsv, lower_red2, upper_red2) mask cv2.bitwise_or(mask1, mask2) # 形态学操作去除噪声 kernel np.ones((5, 5), np.uint8) mask cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 寻找轮廓 contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if len(contours) 0: return None, 0 # 取最大轮廓 max_contour max(contours, keycv2.contourArea) area cv2.contourArea(max_contour) if area 500: # 过滤小面积噪声 return None, 0 # 计算中心坐标 M cv2.moments(max_contour) if M[m00] 0: return None, 0 cx int(M[m10] / M[m00]) cy int(M[m01] / M[m00]) return (cx, cy), area # 测试代码 if __name__ __main__: cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) while True: ret, frame cap.read() if not ret: break center, area detect_red_area(frame) if center is not None: cv2.circle(frame, center, 5, (0, 255, 0), -1) cv2.putText(frame, fArea: {area}, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2) cv2.imshow(Frame, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这个代码的核心是两点红色的 HSV 范围需要分两段因为 HSV 色相环中红色跨越了 0° 分界线。必须做形态学操作否则二值图像中的孤立噪点会严重影响识别结果。4.3 串口通信协议视觉识别结果需要传给主控 STM32 做决策。我们使用了固定长度、带帧头帧尾的协议格式保证通信的可靠性。协议格式如下帧头(0xAA) 数据长度(1字节) 数据区 校验和(1字节)数据区定义了我们可能需要的识别信息字节索引含义说明0识别类型0-红色/1-绿色/2-数字/3-无目标1-2目标中心 X0-640高字节在前3-4目标中心 Y0-480高字节在前5目标面积百分比0-100Python 发送端代码# 文件路径vision/serial_send.py # 串口发送识别结果 import serial import struct def send_detect_result(ser, target_type, center_x, center_y, area_percent): 向 STM32 发送识别结果 data bytearray() data.append(0xAA) # 帧头 data.append(7) # 数据长度类型1 X坐标2 Y坐标2 面积1 校验1 data.append(target_type) data.extend(struct.pack(H, center_x)) data.extend(struct.pack(H, center_y)) data.append(area_percent) # 校验和除帧头外所有字节累加 checksum sum(data[1:]) 0xFF data.append(checksum) ser.write(data) # 用法示例 ser serial.Serial(/dev/ttyUSB0, 115200, timeout0.1) send_detect_result(ser, 0, 320, 240, 35)STM32 端接收时需要对校验和进行同样的计算不一致就丢弃这一帧数据。这样能避免噪声带来的误触发。4.4 基于状态机的任务决策识别到目标之后机器人需要决定下一步动作。我们用了一个简单的状态机来管理任务流程。状态定义如下SEARCH搜索目标原地旋转或沿指定路径运动。APPROACH发现目标调整方向并靠近。OVERCOME执行越障或指定动作。FINISH所有任务完成停车。// 文件路径Src/task_state.c // 任务状态机核心代码 typedef enum { TASK_SEARCH 0, TASK_APPROACH, TASK_OVERCOME, TASK_FINISH } TaskState; TaskState current_state TASK_SEARCH; void Task_StateMachine(int target_type, int center_x, int center_y, int area_percent) { switch (current_state) { case TASK_SEARCH: // 慢速旋转搜索目标 Motor_SetPWM(200); Motor_SetPWM(-200); // 如果检测到目标面积足够大进入靠近状态 if (area_percent 10) { current_state TASK_APPROACH; } break; case TASK_APPROACH: // 根据目标中心坐标调整方向 int error center_x - 320; // 图像中心 320 int turn_speed error * 0.3f; Motor_SetPWM(400 turn_speed); Motor_SetPWM(400 - turn_speed); // 如果目标足够大说明已经靠近执行指定动作 if (area_percent 50) { current_state TASK_OVERCOME; } break; case TASK_OVERCOME: // 执行越障或避障动作具体逻辑根据任务定制 Motor_SetPWM(800); Motor_SetPWM(800); // 延时或检测到完成标志后结束 if (动作完成) { current_state TASK_FINISH; } break; case TASK_FINISH: Motor_SetPWM(0); Motor_SetPWM(0); break; } }状态机的优势在于逻辑清晰、易于调试。每一轮比赛我们都可以通过串口日志打印当前状态快速定位问题出在哪一个环节。5. 整机联调与赛道验证5.1 联调顺序模块单独调好后最怕的就是合并在一起时“互相打架”。我们总结了一套联调顺序可以避免大部分低级问题先调通信确认树莓派和 STM32 串口收发正常数据帧解析正确。再调视觉识别在静止状态下确认 Python 端的识别结果准确、稳定。然后调运动控制在无视觉输入的情况下验证平衡、前进、转向的基本指令。最后做整机闭环把视觉输出接入状态机观察完整任务流程是否通顺。每一步都要记录日志。我们使用了串口日志 SD 卡存储的方式每轮测试跑完就可以回放机器人内部的状态变化找出异常点。5.2 赛道测试记录每次赛道测试至少跑三遍完整流程。记录表大概长这样测试轮次任务完成情况是否摔倒/卡住总用时视觉识别成功次数问题描述第 1 轮全部完成否63s6/6转向时有轻微摆尾第 2 轮全部完成是1次越障失败71s5/6过障碍时重心偏移第 3 轮部分完成是冲出赛道88s4/6光线变化导致识别失败通过这张表我们能够快速判断问题是机械、控制还是视觉。5.3 稳定性优化的三个关键点整个联调阶段我们主要优化了三个方面1. 降低重心初期摄像头安装过高导致高速转向时离心力明显机器人有翻车趋势。后来将摄像头支架降低了 3 厘米并将电池从最上层下移到底盘上整个机器人的过弯稳定性有了质的提升。2. 增大脚轮减震轮腿机器人在穿过减速带时冲击力会直接影响姿态传感器的读数。我们在每个轮轴上增加了橡胶减震垫并在代码里对姿态数据做了中值滤波有效减少了过障碍时的瞬间漂移。3. 动态调整 PID 增益简单固定 PID 在平地跑得好但在上坡、下坡或撞击后响应不佳。我们后来加入了一个简单的模糊逻辑根据机器人的倾斜角度动态调整角度环的 P 值角度偏差越大P 值越大让机器人能在更强的外力下恢复平衡。// Src/motion_control.c // 动态调 P 值的简化思路 float angle_error fabs(target_angle - current_angle); if (angle_error 15.0f) { angle_pid.kp 25.0f; // 大偏差时增大刚度 } else if (angle_error 5.0f) { angle_pid.kp 20.0f; // 中等偏差 } else { angle_pid.kp 17.0f; // 小偏差时保持柔顺 }6. 比赛现场最可惜的几个失误以下是本次比赛真实出现的失误也是我们复盘后最想分享给后来者的经验。6.1 光线变化导致视觉阈值失效这是最致命的一个问题。训练场地使用的是室内日光灯光线均匀且偏白。而比赛场地靠近窗边下午时段有太阳光斜射部分地面区域产生了强烈的反光和高光区域。我们的 HSV 阈值是在训练场地下标定的。到了比赛现场第一次测试红色识别率就下降到了 70% 左右部分区域甚至完全识别不到。解决方案当时没有完美的补救方法只能临时调整 HSV 上下限。但因为参数改得太急又导致绿色目标误识别成红色。赛后我们想到的正解是赛前做一次“光照鲁棒性标定”即在不同光照条件下采集多组 HSV 范围做并集处理。6.2 状态机缺少超时保护我们的状态机在正常情况下工作正常但比赛现场出现了一个训练时没有遇到过的情况机器人到达目标附近后因为视觉识别出现一次帧丢失导致状态机认为“目标还没找到”重新回到了 SEARCH 状态。这一退直接让机器人转了一圈白白浪费了 8 秒。如果状态机里加一个超时强制转移机制比如“在 APPROACH 状态下连续 3 秒检测不到目标默认执行 OVERCOME”就不会出现这个问题。6.3 负载变化导致的 PID 参数失效比赛要求机器人携带一个指定的负载物模拟运输任务。我们训练阶段用的负载物约为 200g但比赛现场的负载物偏重接近 350g。负载增加后机器人整体的转动惯量变大原来的 PID 参数出现明显的过冲和振荡。在近距离转弯时甚至出现了一次推头现象。这个问题本质上还是参数鲁棒性不足。赛前应该做“负载范围测试”覆盖可能出现的最重和最轻负载并制定对应的参数列表。6.4 排故时间不足比赛当天的排故时间非常有限。我们因为临时调整视觉参数和 PID 参数花费了大量时间在复测上导致第二轮比赛时机器人电量不足个别动作出现了供电跌落引起的重启。这里最值得反思的是比赛现场不该再去做大范围调参应该只做“参数切换”。也就是说赛前准备多套完整参数现场根据环境选择最接近的一套最多微调。6.5 常见问题排查清单问题现象常见原因解决思路开机后无法直立姿态角度方向反了检查 MPU6050 安装方向和代码中的符号机器人高频振荡角度环 P 过大或角速度环 P 过小减小角度环 P增大角速度环 P视觉识别频繁丢失HSV 阈值过窄扩大 HSV 范围多次采样标定串口数据乱码波特率不一致或共地问题统一波特率确保两个设备共地电机突然停转电源供电不足加装大电容降低最大 PWM 限幅状态机卡死没有超时保护增加超时强制跳转逻辑7. 如果重来一次工程建议清单这次比赛虽然没有拿到最理想的名次但回头看很多问题其实是可以在备赛阶段就避免的。下面是我们在赛后会优先执行的改进方案也推荐给准备参赛的队伍。7.1 提前进行“比赛模式”演练所谓“比赛模式”就是模拟比赛的真实流程限定 10 分钟进场调试时间、使用比赛现场的光照条件、跑完整的三轮任务、中间只允许调整参数不能改代码。这个演练应该在赛前两周至少执行三次。7.2 参数模板化与快速恢复把所有参数按照不同场地、不同光照、不同负载条件编写成多套配置模板。比赛现场通过一个 switch 语句或配置文件快速切换。// Src/param_config.h // 参数模板切换 typedef struct { float balance_kp; float balance_ki; float balance_kd; float gyro_kp; float gyro_kd; int hsv_red_low[3]; int hsv_red_high[3]; } RobotParam; const RobotParam PARAM_INDOOR { 18.0f, 0.05f, 0.5f, 2.5f, 0.05f, {0, 120, 70}, {10, 255, 255} }; const RobotParam PARAM_OUTDOOR { 20.0f, 0.05f, 0.6f, 3.0f, 0.08f, {0, 100, 60}, {12, 255, 255} }; const RobotParam PARAM_HEAVY_LOAD { 24.0f, 0.06f, 0.4f, 2.8f, 0.04f, {0, 120, 70}, {10, 255, 255} };7.3 硬件冗余与防呆设计比赛中最怕硬件出问题但硬件问题恰恰最容易通过冗余设计来规避。建议至少做到准备两套电机驱动板。准备两组编码器备件。电源接口做防反接保护。所有连接器接口打胶固定防止震动松脱。7.4 串口日志是排错第一手资料比赛现场无法像实验室那样反复观看机器人行为。唯一能还原现场的就是日志。建议所有关键事件都打日志每次状态切换。每次视觉识别结果。PID 输出超限。电压过低警告。8. 总结从省二的遗憾里收获了什么第四名这个成绩让我们止步省二确实遗憾。但说实话比赛结束后的复盘让我意识到这个结果并不冤枉。排名前三的队伍未必在某个单项上比我们强多少。他们的优势在于“系统性”和“鲁棒性”所有的模块都能在变化的环境下稳定工作而我们的系统在实验室条件下表现优秀一旦环境变化就暴露出诸多脆弱点。轮腿机器人竞赛表面上比的是机器人谁跑得快、谁越障能力强本质上比的是工程能力——能不能设计出一套在非理想环境下仍然可靠运行的完整系统。这次比赛给我最大的收获是建立了一套从备赛到临场的工程方法论参数文档化、状态机设计、环境适应性测试、比赛模式演练。这些方法不只是用于竞赛放在任何嵌入式或机器人项目中都适用。如果你正在准备类似比赛我建议你从第一天开始就养成为每项参数做记录的习惯从第一轮测试开始就模拟比赛环境从第一个功能完成就开始做回归测试。不要等到比赛前一周才考虑稳定性。希望这篇复盘能对你有帮助。如果后续有时间我会继续分享更多轮腿机器人的控制和视觉细节也可以聊聊如何把竞赛代码改造成更通用的工程代码。比赛虽然结束了但技术上还有太多可以折腾的地方。一起加油。
返回列表