19f1cd7f2dee0.png

1. 项目速览:让机器人替人去“高压区打卡”

电力巡检机器人面向变电站、电力设备间、工业园区等场景,目标是让机器人自主完成环境建图、定位导航、设备数据采集与巡检辅助分析。它的核心方案是:利用 Gemini 2XL 获取高质量 RGB-D 数据,结合激光雷达与里程计完成 Gmapping 建图,再通过 ORB-SLAM3 重定位为 AMCL 提供初始位姿,最终由 ROS Navigation 完成路径规划与自主巡航。听起来像一串算法名排队上班,本质上是在解决一个很实在的问题:机器人被放到已知环境里,能不能尽快知道“我在哪”,然后稳定去巡检点。🤖

项目要素 内容
项目名称 电力巡检机器人
来源 第四届 3D 视觉创新应用竞赛,黄启铭,河南工业大学
相机型号 Gemini 2XL
支持设备 Jetson Nano、四轮差速小车
核心能力 Gmapping 建图、ORB-SLAM3 重定位、AMCL 初始化、ROS Navigation、自主巡检、点云/可见光/热成像融合
主要代码 fox_navigation、fox_slam、fox_base、fox_kinematics、open3d_pyside

| 源代码 | RobotV_Power-inspection|

2. 为什么电力巡检需要机器人:高压环境里,稳才是硬道理 🔌

19f1cdc877b8d.png

传统人工巡检需要人员进入设备密集、高压、高温或狭窄区域,效率和安全性都受到限制。机器人巡检的价值在于让移动平台替代人工完成重复路线巡查,并通过视觉、深度、温度等数据记录设备状态。

巡检痛点 机器人方案 预期收益
人工巡检路线重复 预设目标点与自主导航 减轻重复劳动
高压区域存在安全风险 机器人进入危险区域采集数据 降低人员暴露风险
设备状态依赖人工观察 RGB-D、点云、热成像联合采集 数据更完整,可追溯
巡检环境结构复杂 栅格地图、代价地图和局部避障 提升通行稳定性
初始定位不方便 ORB-SLAM3 重定位辅助 AMCL 减少人工设置初始位姿

项目特别关注“机器人丢进环境里能否自动找回位置”这个问题。AMCL 虽然适合在 2D 栅格地图中定位,但它通常需要初始位姿;ORB-SLAM3 则能利用视觉地图做重定位。把两者接起来,就能让导航链路更顺滑。

3. 总体架构:从 3D 视觉到 2D 导航,不是降维打击,是协同作战

19f1ce13af927.png

系统可以拆成四条主线:

主线 关键模块 输出
建图主线 激光雷达、里程计、Gmapping 2D 占用栅格地图
重定位主线 Gemini 2XL、ORB-SLAM3、视觉特征地图 机器人在 ORB 地图中的位姿
导航主线 map_server、AMCL、move_base、costmap 巡检路线与速度控制
采集主线 RGB-D、热成像、Open3D/PCL 工具 点云、可见光、温度融合数据

核心运行逻辑可以概括为:

离线 / 建图阶段:
激光雷达 + 里程计 → Gmapping → 2D 栅格地图
Gemini 2XL RGB-D → ORB-SLAM3 → ORB 视觉地图
两张地图之间标定 / 配准 → 得到坐标转换关系

在线 / 巡检阶段:
Gemini 2XL 当前图像 → ORB-SLAM3 重定位
ORB 地图位姿 → 坐标转换 → 2D 栅格地图位姿
转换后的位姿 → 发布给 AMCL 作为初始位姿
AMCL + move_base → 导航到巡检点
相机 / 热成像 / 点云 → 采集设备状态数据

这个设计的妙处在于:3D 视觉负责“快速认出自己在哪”,2D 栅格导航负责“稳稳走到目标点”。一个擅长重定位,一个擅长工程导航,组合起来就很实用。

4. 仿真先行:Isaac Sim 里把变电站场景搭起来 🧪

19f1ce2a9e05f.png

技术文档中提到,项目使用 NVIDIA Isaac Sim 进行电力巡检仿真验证。场景通过模块化几何体、材质、碰撞体和物理属性搭建,包含变压器、地上基站、高低压转换装置、开关柜、输电线、线路支架等典型设备。

仿真内容 作用
变电站场景建模 提前验证巡检路线与设备布局
机器人运动模型 检查底盘运动与 TF 树结构
激光雷达仿真 为 Gmapping / Navigation 提供 scan
ROS Bridge 将 Isaac Sim 内部数据同步到 ROS
碰撞与材质设置 提供更接近真实的运动和传感器反馈

文档也提醒了一个很工程化的经验:使用 Isaac Sim 时,优先选取结构良好的 URDF,再通过官方工具转换为 USD,通常比在场景里手工搭完再导出 URDF 更稳。说人话就是:仿真很强,但文件链路别乱,乱了 TF 树会开始闹脾气。

5. 机器人模型:URDF 把相机、雷达、底盘都挂到 TF 树上

19f1ce532c07b.png

源码中的 fox_description/urdf/fox.urdf 定义了机器人结构,包括 base_footprint、base_link、深度相机、激光雷达、控制面板和车轮等组件。导航系统依赖这些坐标系关系来理解“雷达扫到的障碍物相对机器人在哪里”。

<link name="base_footprint" />

<joint name="base_footprint_joint" type="fixed">
  <parent link="base_footprint"/>
  <child link="base_link"/>
</joint>

<link name="depth_camera_Link">
  <visual>
    <geometry>
      <mesh filename="package://fox_description/meshes/base/depth_camera_Link.STL"/>
    </geometry>
  </visual>
</link>

<joint name="depth_camera_Joint" type="fixed">
  <parent link="base_link"/>
  <child link="depth_camera_Link"/>
</joint>

<link name="laser_radar_Link">
  <visual>
    <geometry>
      <mesh filename="package://fox_description/meshes/base/laser_radar_Link.STL"/>
    </geometry>
  </visual>
</link>

在 Gmapping 和 AMCL 中,几个 TF 关系尤其关键:

TF 关系 含义 由谁提供
base_link → laser_frame 激光雷达相对机器人底盘的位置 URDF / robot_state_publisher
odom → base_footprint 机器人短时里程计运动 里程计节点
map → odom 地图坐标系到里程计坐标系修正 Gmapping 或 AMCL

如果 TF 树断掉,导航系统就像戴着眼镜却不知道镜片在哪里,传感器再好也用不上。

6. Gmapping 建图:先把巡检区域画成 2D 栅格地图

19f1ce7aad4ed.png

项目使用 Gmapping 生成 2D 占用栅格地图。它依赖三个条件:scan 激光话题、odom → base_link/base_footprint 里程计 TF,以及 base_link → scan/laser_frame 传感器 TF。

源码中的 fox_slam/launch/fox_gmapping.launch 给出了核心参数:

<node pkg="gmapping" type="slam_gmapping"
      name="fox_slam_gmapping" output="screen">
  <param name="base_frame" value="base_footprint"/>
  <param name="odom_frame" value="odom"/>
  <param name="map_frame"  value="map"/>

  <param name="map_update_interval" value="2.0"/>
  <param name="maxUrange" value="25.0"/>
  <param name="minimumScore" value="50"/>
  <param name="linearUpdate" value="1.0"/>
  <param name="angularUpdate" value="0.2"/>
  <param name="temporalUpdate" value="0.5"/>
  <param name="particles" value="100"/>
</node>

这些参数决定建图的速度、稳定性和计算压力:

参数 作用 调参方向
map_update_interval 地图刷新间隔 越小越实时,算力压力越大
minimumScore 激光匹配置信度阈值 过高易失败,过低易引入噪声
linearUpdate 机器人移动多远处理一次扫描 小值更精细,但更耗算力
angularUpdate 机器人旋转多少处理一次扫描 小值适合转弯密集场景
particles 粒子数量 越多越稳,越耗 CPU

建图完成后,可以通过 map_server 保存出 .pgm 和 .yaml,后续导航阶段由 map_server 重新发布地图。

7. ORB-SLAM3 重定位:让机器人不用手动点初始位姿

19f1ceb2fe3a6.png

AMCL 在导航中很好用,但它常常需要一个初始位置。项目文档最后总结了一个关键方案:

阶段 工作内容
1 用 ORB-SLAM3 建立视觉地图
2 用 Gmapping 建立二维激光栅格地图
3 求取 ORB 地图与激光栅格地图之间的坐标转换关系
4 导航时,ORB-SLAM3 先重定位得到机器人在 ORB 地图中的位姿
5 将该位姿转换到二维栅格地图坐标系
6 发布给 AMCL 作为初始位姿,AMCL 接管粒子定位

可以用伪代码表达为:

离线标定:
T_grid_orb = estimate_transform(orb_map_points, grid_map_points)

在线重定位:
pose_orb = ORB_SLAM3.relocalize(current_rgbd_frame)

if pose_orb is valid:
    pose_grid = T_grid_orb * pose_orb
    publish_initialpose_to_amcl(pose_grid.x, pose_grid.y, pose_grid.yaw)
    start_navigation()
else:
    request_more_observations()

这里的关键不是“让 ORB-SLAM3 替代 AMCL”,而是让它帮 AMCL 解决起步问题。AMCL 一旦拿到足够靠谱的初始位姿,就可以继续利用激光与栅格地图做粒子滤波定位。像是视觉先帮机器人找门牌号,AMCL 再带它按地图走路。

8. AMCL 与 move_base:导航的“老三样”,但调好并不简单

19f1cf318682c.png

导航启动文件 fox_navigation/launch/fox_navigtion.launch 将地图、规划、定位、底盘和雷达串起来:

<include file="$(find fox_navigation)/launch/map_server.launch"/>
<include file="$(find fox_navigation)/launch/move_base.launch"/>
<include file="$(find fox_navigation)/launch/amcl.launch"/>

<include file="$(find fox_base)/launch/fox_base.launch"/>
<include file="$(find ydlidar_ros)/launch/X2L.launch"/>

<node pkg="rviz" type="rviz" name="rviz"
      args="-d $(find fox_navigation)/rviz/NAV.rviz"/>

AMCL 配置中可以看到粒子数量、激光模型、里程计模型和初始位姿参数:

<node pkg="amcl" type="amcl" name="amcl">
  <param name="odom_model_type" value="omni"/>
  <param name="laser_max_beams" value="60"/>
  <param name="laser_max_range" value="12.0"/>
  <param name="min_particles" value="500"/>
  <param name="max_particles" value="2000"/>
  <param name="laser_model_type" value="likelihood_field"/>
  <param name="odom_frame_id" value="odom"/>
  <param name="base_frame_id" value="base_footprint"/>
  <param name="global_frame_id" value="map"/>
  <param name="initial_pose_x" value="$(arg initial_pose_x)"/>
  <param name="initial_pose_y" value="$(arg initial_pose_y)"/>
  <param name="initial_pose_a" value="$(arg initial_pose_a)"/>
</node>

move_base 负责加载代价地图和规划器参数:

<node pkg="move_base" type="move_base"
      name="move_base_node" output="screen">
  <rosparam file="$(find fox_navigation)/param/costmap_common_params.yaml"
            command="load" ns="global_costmap"/>
  <rosparam file="$(find fox_navigation)/param/costmap_common_params.yaml"
            command="load" ns="local_costmap"/>
  <rosparam file="$(find fox_navigation)/param/local_costmap_params.yaml"
            command="load"/>
  <rosparam file="$(find fox_navigation)/param/global_costmap_params.yaml"
            command="load"/>
  <rosparam file="$(find fox_navigation)/param/move_base_params.yaml"
            command="load"/>
</node>

在项目文档中,全局规划侧强调 Dijkstra/global planner,局部规划侧强调 TEB;源码中也保留了 TEB 参数文件。不过当前 move_base_params.yaml 默认启用的是 navfn/NavfnROS 和 DWAPlannerROS。这说明工程中保留了多套规划器配置,可根据仿真、实车和算力条件切换。

9. 代价地图:让机器人知道“哪里能走,哪里最好别碰”

19f1cf52da01d.png

导航不是简单地从 A 点画一条直线到 B 点。机器人需要考虑障碍物、膨胀区、局部动态环境和自身尺寸。costmap_common_params.yaml 中定义了障碍层、体素层和膨胀层:

map_type: voxel

obstacle_layer:
  obstacle_range: 3.0
  raytrace_range: 3.0
  observation_sources: scan
  scan:
    data_type: LaserScan
    topic: scan
    sensor_frame: laser_frame
    marking: true
    clearing: true
    obstacle_range: 4.0
    raytrace_range: 4.0

inflation_layer:
  enabled: true
  cost_scaling_factor: 10.0
  inflation_radius: 0.05

全局和局部代价地图分工如下:

地图 坐标系 作用
global_costmap map 基于静态地图规划全局路线
local_costmap odom 围绕机器人滚动更新,处理近处障碍
obstacle_layer scan 根据激光雷达标记/清除障碍
inflation_layer 地图单元 在障碍物周围生成安全缓冲

电力巡检场景中,设备柜、支架、电缆通道等障碍密集,代价地图调得好不好,直接决定机器人是“稳稳绕开”,还是“勇敢贴脸”。

10. 底盘与里程计:轮子转多少,位置就得算清楚

19f1cf73de460.png

fox_base 通过 Modbus RTU 与底盘控制板通信:car_cmd 下发轮速,car_data 回传速度、电压、IMU、温湿度等信息。

# fox_msgs/msg/car_cmd.msg
float64[] speed
uint16 been

# fox_msgs/msg/car_data.msg
float64[] speed
uint16[] crash
uint16[] infrared
uint16[] ultrasonic
uint16 smoke
uint16 power_voltage
float32[] mpu
float32 tempareture
float32 humidity

fox_base.cpp 的通信框架可以简化为:

// 订阅 car_cmd,将目标轮速写入控制板寄存器
ros::Subscriber car_control_sub =
    nh.subscribe("car_cmd", 10, twistCallback);

// 读取控制板反馈,并发布 car_data
if (modbus_read_input_registers(mb, 0, 35, mbbuf) == 35) {
    translate_mb_data();
    car_data_pub.publish(my_data);
}

fox_kinematics/src/odometry.cpp 则根据速度积分得到里程计,并发布 odom → base_footprint:

double delta_x = (vx * cos(th) - vy * sin(th)) * dt;
double delta_y = (vx * sin(th) + vy * cos(th)) * dt;
double delta_th = vth * dt;

x += delta_x;
y += delta_y;
th += delta_th;

geometry_msgs::TransformStamped odom_trans;
odom_trans.header.frame_id = "odom";
odom_trans.child_frame_id = "base_footprint";
odom_trans.transform.translation.x = x;
odom_trans.transform.translation.y = y;
odom_trans.transform.rotation = tf::createQuaternionMsgFromYaw(th);

odom_broadcaster.sendTransform(odom_trans);
odom_pub.publish(odom);

这部分是导航系统的底层心跳:如果里程计漂得太离谱,Gmapping 和 AMCL 都会很辛苦;如果 TF 发布不稳定,move_base 也会跟着迷路。

11. Gemini 2XL 与点云采集:巡检不只看路线,还要看设备状态

19f1cf83642c1.png

项目的采集系统不仅面向导航,还面向设备状态记录。技术文档中提到采集内容包括高分辨率 RGB 图像、RGB-D 深度图、热成像图像、无色点云、彩色点云和参数文件等。

open3d_pyside/Orbbec_Camera.py 提供了深度图查看与时域滤波:

class TemporalFilter:
    def __init__(self, alpha):
        self.alpha = alpha
        self.previous_frame = None

    def process(self, frame):
        if self.previous_frame is None:
            result = frame
        else:
            result = cv2.addWeighted(
                frame, self.alpha,
                self.previous_frame, 1 - self.alpha, 0
            )
        self.previous_frame = result
        return result

深度流处理流程如下:

depth_data = np.frombuffer(depth_frame.get_data(), dtype=np.uint16)
depth_data = depth_data.reshape((height, width))
depth_data = depth_data.astype(np.float32) * scale
depth_data = np.where(
    (depth_data > MIN_DEPTH) & (depth_data < MAX_DEPTH),
    depth_data,
    0
)
depth_data = temporal_filter.process(depth_data)
depth_image = cv2.normalize(depth_data, None, 0, 255, cv2.NORM_MINMAX)
depth_image = cv2.applyColorMap(depth_image, cv2.COLORMAP_JET)

这类处理能让深度数据更稳定,也方便巡检人员通过界面直观看到设备表面距离、轮廓和点云形态。

12. 点云处理与热成像融合:让“看得见”和“测得出”合到一起

19f1cf98baec9.png

open3d_pyside/Algorithm.py 中集成了多种点云处理函数,适合做巡检数据预处理和展示:

功能 对应函数 用途
统计滤波 filter() 去除离群噪声点
法线估计 normal_estimation() 分析设备表面几何结构
KDTree 搜索 KDtree() 邻域查询与局部分析
Octree 构建 Octree() 空间层次组织
体素下采样 Voxel_subsampling() 降低点云规模
半径滤波 Radius_filtering() 删除孤立点
DBSCAN 聚类 DBSCAN_cluster() 分离不同设备或部件
RANSAC 平面分割 RANSAC_segmentation() 分割柜面、墙面等平面结构

例如,RANSAC 平面分割可以抽象为:

pcd = o3d.io.read_point_cloud(file_name)

plane_model, inliers = pcd.segment_plane(
    distance_threshold=0.2,
    ransac_n=3,
    num_iterations=1000
)

inlier_cloud = pcd.select_by_index(inliers)
outlier_cloud = pcd.select_by_index(inliers, invert=True)

技术文档还提到热成像与可见光图像配准流程:边缘检测、特征点提取、最佳匹配、距离排序、仿射矩阵计算、重复点剔除,最终把温度信息映射到点云上。这样一来,巡检结果不仅有“设备长什么样”,还可以包含“设备哪里热”。

13. 多点巡检与任务执行:目标点发给 move_base,小车就开工

配图建议|巡检任务图

> Image prompt:

19f1cfde82e64.png

源码中 multipoint_navigation/src/nav_2d.cpp 封装了一个服务,把外部传入的二维目标点转换为 move_base 目标:

goal.target_pose.header.frame_id = "map";
goal.target_pose.header.stamp = ros::Time::now();

goal.target_pose.pose.position.x = req.pose.x;
goal.target_pose.pose.position.y = req.pose.y;

geometry_msgs::Quaternion orientation =
    tf::createQuaternionMsgFromYaw(req.pose.theta);

goal.target_pose.pose.orientation = orientation;
navclient->sendGoal(goal);
navclient->waitForResult();

这使得巡检任务可以按“点位列表”组织:

任务阶段 动作
设定巡检点 在 map 坐标系下定义目标点
发送导航目标 通过服务或 action 调用 move_base
到达目标点 触发 RGB-D / 热成像 / 点云采集
数据存档 保存图片、点云和设备状态
前往下一点 继续巡检路线

文件中还包含 auto_charging 相关代码,说明系统具备向自动回充方向扩展的基础:先导航到充电桩附近,再通过相对运动和标志追踪完成末端对接。

14. 工程亮点与可优化方向

19f1cfeec4122.png
技术亮点 具体体现 工程价值
视觉重定位辅助导航 ORB-SLAM3 位姿转换后初始化 AMCL 降低手动设初始位姿的负担
2D 与 3D 协同 Gmapping 负责栅格导航,Gemini 2XL 负责深度/点云 兼顾导航稳定性和巡检数据质量
完整 ROS 导航栈 map_server、AMCL、move_base、costmap、RViz 工程链路清晰,可复用性强
底盘闭环控制 Modbus RTU、轮速消息、里程计 TF 支撑实车运动与定位
点云处理工具链 Open3D/PCL、滤波、聚类、平面分割 支撑设备结构分析
多传感器融合探索 可见光、深度、热成像融合 面向设备温度异常检测

后续优化可以围绕这些方向展开:

优化方向 建议做法 预期收益
坐标转换自动化 用成对地标或特征点自动估计 T_grid_orb 减少人工标定误差
规划器配置统一 明确 DWA、TEB、Navfn、GlobalPlanner 的实车/仿真配置 降低部署混乱
巡检语义识别 增加仪表、开关状态、异常发热点检测 从“会走”升级到“会看懂设备”
数据报告生成 自动关联点位、温度图、点云和时间戳 提升巡检结果可追溯性
动态障碍处理 引入动态 costmap 或语义障碍过滤 增强现场安全性

15. 总结:它的厉害之处,是把“我在哪”和“我要去哪”接上了

电力巡检机器人项目的核心价值,不只是把 Gemini 2XL 装到小车上,也不只是能跑 Gmapping 或 AMCL。它真正有意思的地方在于:用 ORB-SLAM3 解决导航初始定位不便的问题,再把视觉地图位姿转换到二维栅格地图中,让 AMCL 和 move_base 接着完成可靠导航。与此同时,RGB-D、点云和热成像采集又为设备状态巡检提供了更丰富的数据来源。

用一句活泼但不夸张的话收尾:这台机器人不只是会在变电站里“转悠”,它是在认真地建图、找路、看设备,还顺便把温度和点云都记进小本本里。 📍

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注