
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. 为什么电力巡检需要机器人:高压环境里,稳才是硬道理 🔌

传统人工巡检需要人员进入设备密集、高压、高温或狭窄区域,效率和安全性都受到限制。机器人巡检的价值在于让移动平台替代人工完成重复路线巡查,并通过视觉、深度、温度等数据记录设备状态。
| 巡检痛点 | 机器人方案 | 预期收益 |
|---|---|---|
| 人工巡检路线重复 | 预设目标点与自主导航 | 减轻重复劳动 |
| 高压区域存在安全风险 | 机器人进入危险区域采集数据 | 降低人员暴露风险 |
| 设备状态依赖人工观察 | RGB-D、点云、热成像联合采集 | 数据更完整,可追溯 |
| 巡检环境结构复杂 | 栅格地图、代价地图和局部避障 | 提升通行稳定性 |
| 初始定位不方便 | ORB-SLAM3 重定位辅助 AMCL | 减少人工设置初始位姿 |
项目特别关注“机器人丢进环境里能否自动找回位置”这个问题。AMCL 虽然适合在 2D 栅格地图中定位,但它通常需要初始位姿;ORB-SLAM3 则能利用视觉地图做重定位。把两者接起来,就能让导航链路更顺滑。
3. 总体架构:从 3D 视觉到 2D 导航,不是降维打击,是协同作战

系统可以拆成四条主线:
| 主线 | 关键模块 | 输出 |
|---|---|---|
| 建图主线 | 激光雷达、里程计、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 里把变电站场景搭起来 🧪

技术文档中提到,项目使用 NVIDIA Isaac Sim 进行电力巡检仿真验证。场景通过模块化几何体、材质、碰撞体和物理属性搭建,包含变压器、地上基站、高低压转换装置、开关柜、输电线、线路支架等典型设备。
| 仿真内容 | 作用 |
|---|---|
| 变电站场景建模 | 提前验证巡检路线与设备布局 |
| 机器人运动模型 | 检查底盘运动与 TF 树结构 |
| 激光雷达仿真 | 为 Gmapping / Navigation 提供 scan |
| ROS Bridge | 将 Isaac Sim 内部数据同步到 ROS |
| 碰撞与材质设置 | 提供更接近真实的运动和传感器反馈 |
文档也提醒了一个很工程化的经验:使用 Isaac Sim 时,优先选取结构良好的 URDF,再通过官方工具转换为 USD,通常比在场景里手工搭完再导出 URDF 更稳。说人话就是:仿真很强,但文件链路别乱,乱了 TF 树会开始闹脾气。
5. 机器人模型:URDF 把相机、雷达、底盘都挂到 TF 树上

源码中的 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 栅格地图

项目使用 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 重定位:让机器人不用手动点初始位姿

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:导航的“老三样”,但调好并不简单

导航启动文件 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. 代价地图:让机器人知道“哪里能走,哪里最好别碰”

导航不是简单地从 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. 底盘与里程计:轮子转多少,位置就得算清楚

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 与点云采集:巡检不只看路线,还要看设备状态

项目的采集系统不仅面向导航,还面向设备状态记录。技术文档中提到采集内容包括高分辨率 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. 点云处理与热成像融合:让“看得见”和“测得出”合到一起

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:

源码中 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. 工程亮点与可优化方向

| 技术亮点 | 具体体现 | 工程价值 |
|---|---|---|
| 视觉重定位辅助导航 | 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、点云和热成像采集又为设备状态巡检提供了更丰富的数据来源。
用一句活泼但不夸张的话收尾:这台机器人不只是会在变电站里“转悠”,它是在认真地建图、找路、看设备,还顺便把温度和点云都记进小本本里。 📍