2025年第27届中国机器人及人工智能大赛自主巡航实战经验分享

作为连续两届参加中国机器人及人工智能大赛并拿下国一的"老兵",我想跟大家分享一些在自主巡航项目中的实战经验。这个项目看起来简单,但真正做起来才发现里面有太多坑需要踩,希望我的一些经验能让你少走弯路。

一、项目实战理解

刚开始接触这个项目时,我和团队都以为主要难点在于算法的精巧设计。结果第一年比赛只拿了个国二,回来复盘才发现,比赛成败的关键不在于算法多高级,而在于系统的鲁棒性和稳定性

场地中那些任务信息图像看似简单,但在不同光照、不同角度下识别难度差异很大。记得去年决赛时,有支985高校的队伍用了很牛的深度学习算法,结果在现场因为光照问题,识别率直接掉到40%以下,连基本的任务点都没完成。

核心任务拆解:

  • 语音识别与播报(10分)
  • 三次任务点识别与到达(60分)
  • 终点到达(10分)
  • 技术文档(10分)

首先要确保60分的基础分稳稳拿到,才有机会冲击更高分数。

二、软件架构实战经验

ROS框架设计

第一年我们用了单体架构,所有功能都堆在一个节点里,结果调试和找bug特别痛苦。第二年重构为多节点设计:

这种模块化设计好处太多了:

  1. 团队可以并行开发
  2. 单元测试变得简单
  3. 找bug和调试效率提高10倍不止

实战代码技巧

1. 激光数据预处理

比赛中经常会遇到激光数据异常的情况,这段代码帮我们解决了很多问题:

// 激光雷达数据异常处理函数 sensor_msgs::LaserScan filterScan(const sensor_msgs::LaserScan& scan) { sensor_msgs::LaserScan filtered = scan; // 1. 剔除无效值 for (size_t i = 0; i < scan.ranges.size(); i++) { if (scan.ranges[i] < scan.range_min || scan.ranges[i] > scan.range_max || !std::isfinite(scan.ranges[i])) { filtered.ranges[i] = scan.range_max; // 将无效值设为最大值 } } // 2. 中值滤波 (三点滑动窗口) for (size_t i = 1; i < filtered.ranges.size() - 1; i++) { std::vector<float> window = { filtered.ranges[i-1], filtered.ranges[i], filtered.ranges[i+1] }; std::sort(window.begin(), window.end()); filtered.ranges[i] = window[1]; // 取中值 } // 3. 处理反光区域数据跳变 for (size_t i = 2; i < filtered.ranges.size(); i++) { float diff = std::abs(filtered.ranges[i] - filtered.ranges[i-1]); if (diff > 0.5 && filtered.ranges[i] > 5.0) { filtered.ranges[i] = filtered.ranges[i-1]; } } return filtered; }
2. 视觉自适应增强

不同场地光照差异很大,这段代码可以自动调整图像处理参数

def adaptive_image_processing(image): """根据图像特性自动调整处理参数""" # 计算图像亮度直方图 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) hist = cv2.calcHist([gray], [0], None, [256], [0, 256]) # 计算亮度均值和标准差 mean_brightness = np.mean(gray) std_brightness = np.std(gray) # 根据亮度特性调整参数 if mean_brightness < 80: # 低光环境 alpha = 1.5 # 增加对比度 beta = 25 # 增加亮度 elif mean_brightness > 180: # 高光环境 alpha = 0.7 # 降低对比度 beta = -20 # 降低亮度 else: # 正常光照 alpha = 1.0 beta = 0 # 应用亮度调整 adjusted = cv2.convertScaleAbs(image, alpha=alpha, beta=beta) # 光照均衡化处理 if std_brightness > 60: # 光照不均匀 # 转到LAB色彩空间进行亮度均衡化 lab = cv2.cvtColor(adjusted, cv2.COLOR_BGR2LAB) l, a, b = cv2.split(lab) clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8)) cl = clahe.apply(l) merged = cv2.merge((cl, a, b)) return cv2.cvtColor(merged, cv2.COLOR_LAB2BGR) else: return adjusted

这个函数在我们决赛中立了大功,解决了场馆顶部射灯照射导致的图像过曝问题。

三、核心算法实战选择

SLAM定位算法

我们测试过三种主流SLAM算法的性能表现

实战经验: 正式比赛我们用Cartographer,虽然占用资源多,但闭环检测能力强,精度高。关键参数调优是:

# cartographer.lua中的关键参数 TRAJECTORY_BUILDER_2D.submaps.num_range_data = 80 # 减小以降低延迟 TRAJECTORY_BUILDER_2D.min_range = 0.15 # 设置为激光雷达最小值 TRAJECTORY_BUILDER_2D.max_range = 12.0 # 设置为激光雷达最大值 TRAJECTORY_BUILDER_2D.missing_data_ray_length = 5.0 # 处理遮挡 POSE_GRAPH.optimization_problem.huber_scale = 1e2 # 提高优化稳定性 POSE_GRAPH.constraint_builder.min_score = 0.55 # 提高约束阈值

视觉识别方案

不要迷信单一的深度学习模型,我们的最佳方案是多模型融合

def ensemble_prediction(image): """多模型融合预测""" # 使用不同模型进行预测 yolo_results = yolo_model.predict(image) resnet_results = resnet_model.predict(image) # 目标检测结果融合 all_boxes = [] # 添加YOLO检测框 for det in yolo_results: x1, y1, x2, y2 = det['bbox'] confidence = det['confidence'] * 0.6 # YOLO权重 label = det['class'] all_boxes.append([x1, y1, x2, y2, confidence, label]) # 添加ResNet检测框 for det in resnet_results: x1, y1, x2, y2 = det['bbox'] confidence = det['confidence'] * 0.4 # ResNet权重 label = det['class'] all_boxes.append([x1, y1, x2, y2, confidence, label]) # 非极大值抑制 final_boxes = non_maximum_suppression(all_boxes, 0.5) # 标签投票 final_results = [] for box_group in final_boxes: # 计算平均边界框 avg_box = calculate_average_box(box_group) # 标签投票 labels = [b[5] for b in box_group] label = most_common(labels) # 计算置信度 confidence = sum([b[4] for b in box_group]) final_results.append({ 'bbox': avg_box, 'class': label, 'confidence': confidence }) return final_results

这种多模型融合方法在不稳定光照条件下识别率要高15%左右,虽然计算开销大了点,但值得。

 四、导航平滑性优化

速度平滑滤波器

导航卡顿的核心问题是速度命令变化过于剧烈。我们实现了一种基于双指数平滑的速度命令过滤器:

class VelocityFilter { public: VelocityFilter(double alpha = 0.3, double beta = 0.1) : alpha_(alpha), beta_(beta), s_x_(0), s_y_(0), s_theta_(0), b_x_(0), b_y_(0), b_theta_(0), initialized_(false) {} geometry_msgs::Twist filter(const geometry_msgs::Twist& raw_cmd) { if (!initialized_) { // 初始化 s_x_ = raw_cmd.linear.x; s_y_ = raw_cmd.linear.y; s_theta_ = raw_cmd.angular.z; b_x_ = 0; b_y_ = 0; b_theta_ = 0; initialized_ = true; return raw_cmd; } // 双指数平滑滤波器 // 更新级数项 double s_x_prev = s_x_; double s_y_prev = s_y_; double s_theta_prev = s_theta_; s_x_ = alpha_ * raw_cmd.linear.x + (1 - alpha_) * (s_x_prev + b_x_); s_y_ = alpha_ * raw_cmd.linear.y + (1 - alpha_) * (s_y_prev + b_y_); s_theta_ = alpha_ * raw_cmd.angular.z + (1 - alpha_) * (s_theta_prev + b_theta_); // 更新趋势项 b_x_ = beta_ * (s_x_ - s_x_prev) + (1 - beta_) * b_x_; b_y_ = beta_ * (s_y_ - s_y_prev) + (1 - beta_) * b_y_; b_theta_ = beta_ * (s_theta_ - s_theta_prev) + (1 - beta_) * b_theta_; // 构造平滑后的速度命令 geometry_msgs::Twist filtered_cmd; filtered_cmd.linear.x = s_x_ + b_x_; filtered_cmd.linear.y = s_y_ + b_y_; filtered_cmd.angular.z = s_theta_ + b_theta_; return filtered_cmd; } private: double alpha_; // 数据项权重 double beta_; // 趋势项权重 // 平滑值 double s_x_, s_y_, s_theta_; // 趋势值 double b_x_, b_y_, b_theta_; bool initialized_; };

 TEB参数优化

通过对比测试,我们总结出一套最优的TEB局部规划器参数:

 

TebLocalPlannerROS: # 机器人配置 max_vel_x: 0.35 max_vel_x_backwards: 0.1 max_vel_y: 0.35 max_vel_theta: 0.8 acc_lim_x: 0.2 acc_lim_y: 0.2 acc_lim_theta: 0.3 min_turning_radius: 0.0 # 轨迹配置 teb_autosize: True dt_ref: 0.4 dt_hysteresis: 0.1 global_plan_overwrite_orientation: True max_global_plan_lookahead_dist: 2.0 feasibility_check_no_poses: 5 # 优化配置 no_inner_iterations: 5 no_outer_iterations: 4 penalty_epsilon: 0.05 weight_max_vel_x: 1.0 weight_max_vel_y: 1.0 weight_max_vel_theta: 1.0 weight_acc_lim_x: 2.0 weight_acc_lim_y: 2.0 weight_acc_lim_theta: 2.0 weight_kinematics_nh: 1000.0 weight_kinematics_forward_drive: 100.0 weight_optimaltime: 1.0 weight_obstacle: 50.0 weight_inflation: 0.1 # 平滑参数(关键部分) weight_adapt_factor: 2.0 enable_homotopy_class_planning: False simple_exploration: False

在比赛间隙调整这些参数时,我习惯按照这个顺序调整:先调速度限制,再调加速度限制,然后是权重参数。最关键的三个参数是weight_kinematics_forward_driveweight_obstacleacc_lim_theta

五、实战踩坑与应对

1. 机械结构问题

第一年比赛,我们的摄像头固定方式太简单,用的3D打印支架。结果比赛中底盘急停导致摄像头大幅晃动,视觉识别全乱了。

解决方案: 第二年改用铝合金框架 + 减震垫,效果好很多。记住一点:不要低估机械振动对传感器的影响

2. 光照变化

比赛场地光照往往是最大变数。记得去年西安的比赛,场馆靠窗一侧阳光直射,另一侧则很暗。

解决方案:

  • 视觉算法做好自适应处理
  • 提前20分钟进场调试
  • 准备多套参数配置,快速切换

3. 定位丢失

导航过程中定位丢失是常见问题。一个队友不小心走进场地或者场地有高反光材料,都可能导致定位失败。

def emergency_relocation(): """定位丢失应急处理""" # 1. 停止当前导航 stop_navigation() # 2. 切换为原地旋转模式采集数据 cmd_vel = rospy.Publisher('/cmd_vel', Twist, queue_size=1) twist = Twist() twist.angular.z = 0.5 # 缓慢旋转 # 发送旋转命令5秒 start_time = rospy.Time.now() rate = rospy.Rate(10) while (rospy.Time.now() - start_time).to_sec() < 5.0: cmd_vel.publish(twist) rate.sleep() # 3. 停止旋转 twist.angular.z = 0.0 cmd_vel.publish(twist) # 4. 尝试使用特征点匹配重定位 success = feature_based_relocalization() if success: rospy.loginfo("重定位成功,继续导航") resume_navigation() else: rospy.logwarn("重定位失败,切换到紧急模式") switch_to_emergency_mode()

 

六、总结与建议

如果让我给参加自主巡航项目的同学们一些建议,那就是:

  1. 基础分最重要:确保导航稳定可靠,拿到60分基础分,再追求更高分数
  2. 系统鲁棒性大于算法先进性:算法再先进,如果不够稳定,在比赛中也会翻车
  3. 充分测试各种极端情况:刻意制造干扰和异常,测试系统恢复能力
  4. 做好知识积累和经验传承:记录所有问题和解决方案,避免后来者重复踩坑

技术上,我的几点关键建议:

  • 多传感器融合是解决单一传感器不稳定的最佳方案
  • 参数自适应比固定参数在实际比赛中可靠得多
  • 故障容错机制是区分一般队伍和优秀队伍的关键

最后,希望大家都能享受这个比赛带来的技术挑战!我当年就是在比赛中学到了很多东西,今年我依旧会来参加今年的比赛,如果需要去年的工作空间或者今年的指导私聊博主,非常感谢!!!

Read more

从「AI改变世界」到「AI帮我改Bug」:一个小厂架构师的Agent落地实战

从「AI改变世界」到「AI帮我改Bug」:一个小厂架构师的Agent落地实战

凌晨两点的顿悟:AI不是魔法,是工具 上周三凌晨两点,我坐在书房里揉着发涨的太阳穴——创业团队的产品刚上2.0版本,客户反馈的Bug堆了满满一屏幕。女儿的乐高积木还散在客厅地板上,老父亲的呼噜声从隔壁房间传来,而我面前的电脑屏幕上,一个红色的错误提示正在闪烁。 「要是有个AI能帮我自动定位Bug就好了。」我对着空气吐槽,顺手又灌了一口冰咖啡。 三个月前,我也是这么想的。那时候AI Agent的概念正火,我在各种技术大会上听了无数次「Agent将颠覆软件开发」的演讲。回到公司后,我拍着胸脯跟团队说:「咱们也搞个AI Agent,让它帮我们写代码、测Bug、甚至做需求分析!」 现在想来,当时的自己简直像个刚毕业的愣头青——热情有余,务实不足。 从「大而全」到「小而美」:我的Agent落地三步走 落地流程可视化 遇到问题 遇到问题 遇到问题 接入错误日志系统 懂代码库结构 全能Agent幻想 系统启动慢 代码质量差 功能臆想 反思与调整 找到最小可用场景

Coze扣子「百套AI工作流」模板合集

Coze扣子「百套AI工作流」模板合集

💰 价值5899元的市面热卖模板全公开! 📦 142MB收录100+款扣子工作流,覆盖多领域爆款逻辑! 🎯 免费用顶级模板,省下高价学费,快速切入AI短视频赛道! 🔥 扣子教程-爆款历史讲解 * 文件大小: 126MB * 内容特色: 用AI解锁历史流量密码!精华教程,手把手教你将枯燥历史变成爆款视频 * 适用人群: 知识区UP主和内容创作者 * 核心价值: 让历史故事也能狂揽点赞! * 下载链接: 夸克网盘分享 🎨 AI工作流一键生成:简笔画心理学 * 文件大小: 492MB * 内容特色: 保姆级教程!条条爆款+百分百原创,小白5分钟上手心理学内容创作 * 适用人群: 心理学内容创作者 * 核心价值: 轻松月入过万!融合简笔画与心理学知识,视频模板可直接套用 * 下载链接: 夸克网盘分享 ⭐ 扣子小人国一键生成工作流 * 文件大小: 15.5MB * 内容特色: 轻量但强悍!热门短视频"小人国"特效独家源码,一键生成奇幻视觉大片 * 适用人群:

AI 办公成职场标配,别再用错拖后腿!7 套书教你精准用 AI 提效

AI 办公成职场标配,别再用错拖后腿!7 套书教你精准用 AI 提效

2026三掌柜赠书活动第十八期 AI 办公成职场标配,别再用错拖后腿!7 套书教你精准用 AI 提效 目录 Part.0 前言 Part.1 开会汇报没重点?AI当“嘴替” Part.2 不想加班,还不知道搭个智能体帮你干? Part.3 主业涨薪难,想抓AI风口做副业? Part.4 DeepSeek总get不到你的点? Part.5 Office内置AI不会用? Part.6 不想被“职场体力活”耗空? Part.7 对抗工具墒增,实现职场进阶! Part.8 彩蛋:赠书! Part.9 结束语 Part.0 前言