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

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

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

Pythonist发布于 2026/4/5更新于 2026/9/10103 浏览

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

一、项目实战理解

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

场地中那些任务信息图像看似简单,但在不同光照、不同角度下识别难度差异很大。记得去年决赛时,有支 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]; // 取中值
    }
    // 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 算法的性能表现

[图示: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. 六、总结与建议

更多推荐文章

查看全部
  • FPGA 入门:基于 LED 的 2 选 1 多路选择器实现
  • Z-Image-Turbo 孙珍妮模型使用指南
  • Linux 系统权限全面解析
  • 前端骨架屏实现详解:Vue、React、Angular、jQuery 及小程序实践
  • Python 进阶与高级语法详解
  • JavaScript 金额计算精度丢失与分摊方案
  • Neo4j 安装与配置教程(Windows/MacOS/Linux)
  • C++11 条件变量:notify_one 与 notify_all 的唤醒机制
  • 线性回归算法原理及 Python 代码实现
  • Python 月相可视化项目实战:从计算到 Web 渲染
  • YOLOv8 旋转框角度回归优化:CSL 与 DCL 编码实战
  • OpenClaw 多端交互实测指南:Web、TUI 与钉钉集成配置
  • C++ string 类全面解析
  • BFS 解决边权相同的最短路问题
  • Vue3 组件方法调用无效或提示不存在的排查与修复
  • Spring Boot 与 Leaflet 实现省域迂回可视化实战
  • 短波发射台共址 DRM 监测:射频前端的挑战与应对
  • VS Code 远程连接服务器后 GitHub Copilot 无法使用问题排查
  • OpenClaw:AI 直接操控电脑的开源工具
  • 低代码搭建高企年报自动化系统实践

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如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