跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
编程语言AI算法

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

分享了参加中国机器人及人工智能大赛自主巡航项目的实战经验。核心观点是系统鲁棒性和稳定性优于算法先进性。文章涵盖软件架构(ROS 多节点设计)、激光数据预处理、视觉自适应增强、SLAM 定位(Cartographer)选择、多模型融合识别方案、导航平滑性优化(速度滤波器与 TEB 参数)以及常见故障应对(机械振动、光照变化、定位丢失)。建议确保基础分,重视多传感器融合与参数自适应,做好极端情况测试。

Pythonist发布于 2026/4/5更新于 2026/10/25135 浏览

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

一、项目实战理解

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

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

核心任务拆解:

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

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

二、软件架构实战经验

ROS 框架设计

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

[图示:ROS 框架设计]

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

  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]; // 取中值
    }
    
     ( i = ; i < filtered.ranges.(); i++) {
         diff = std::(filtered.ranges[i] - filtered.ranges[i]);
         (diff >  && filtered.ranges[i] > ) {
            filtered.ranges[i] = filtered.ranges[i];
        }
    }
     filtered;
}
// 3. 处理反光区域数据跳变
for
size_t
2
size
float
abs
-1
if
0.5
5.0
-1
return
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 算法的性能表现

[图示: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_drive、weight_obstacle 和 acc_lim_theta。

五、实战踩坑与应对

1. 机械结构问题

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

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

2. 光照变化

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

解决方案:

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

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

def emergency_relocation():
    """定位丢失应急处理"""
    # 1. 停止当前导航
    stop_navigation()
    # 2. 切换为原地旋转模式采集数据
    cmd_vel = rospy.Publisher('/cmd_vel', Twist, queue_size=10)
    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. 做好知识积累和经验传承:记录所有问题和解决方案,避免后来者重复踩坑

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

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

最后,希望大家都能享受这个比赛带来的技术挑战!我当年就是在比赛中学到了很多东西,今年我依旧会来参加今年的比赛。

目录

  1. 一、项目实战理解
  2. 二、软件架构实战经验
  3. ROS 框架设计
  4. 实战代码技巧
  5. 1. 激光数据预处理
  6. 2. 视觉自适应增强
  7. 三、核心算法实战选择
  8. SLAM 定位算法
  9. cartographer.lua 中的关键参数
  10. 视觉识别方案
  11. 四、导航平滑性优化
  12. 速度平滑滤波器
  13. TEB 参数优化
  14. 五、实战踩坑与应对
  15. 1. 机械结构问题
  16. 2. 光照变化
  17. 3. 定位丢失
  18. 六、总结与建议

更多推荐文章

查看全部
  • Python 编写简易 Web 应用框架实战指南
  • 动态规划经典模型:0-1 背包与最长公共子序列
  • C++ 内存管理:从裸指针到智能指针的进化
  • C++ 基础核心概念:命名空间、引用与内联函数
  • 基于低代码引擎快速构建企业级审批系统实战
  • 旋转排序数组二分查找解法:LeetCode 33 题实战
  • Java JUnit NoSuchMethodError 错误排查与 Spring Boot 版本兼容修复
  • Elasticsearch 核心概念与常见面试问题解析
  • C++ 算法实战:排序子序列划分与 LIS 优化
  • OpenHarmony 环境下 AngularDart 使用 angular_bloc 状态管理指南
  • C#初级开发者应对 AI 预测重构的策略与实战技巧
  • 本地离线部署 Whisper 模型实现语音转写指南
  • Ubuntu 24.04 部署 OpenClaw 本地 AI 助手指南
  • AI 时代国产数据库发展趋势与金仓数据库技术实践
  • Flutter 鸿蒙适配:mediapipe_core 端侧 AI 推理与手势识别实战
  • C++ 笔试刷题 Day 9: 添加逗号、跳台阶与扑克牌顺子
  • 清华等机构推出 DreamBench++:基于 GPT-4o 的图像生成评估新基准
  • Java 助力:充电桩物联网与新能源深度融合
  • Python 鸭子类型:动态类型的核心概念与实践
  • DeepSeek 时代,前端开发的变革与实战路径

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online