最近在机器人导航领域,基于视觉的SLAM技术越来越受到关注。我尝试将ROS2 Humble、Astra深度相机和ORB-SLAM3这三个技术栈整合起来,搭建一个完整的视觉SLAM系统。这个组合特别适合中小型机器人项目,既能获得不错的定位精度,又不会对硬件提出过高要求。
硬件准备清单:
注意:Astra相机有多个版本,建议使用Astra Pro,它的深度图像质量更好。我在测试中发现老款Astra在弱光环境下噪点明显增多。
软件环境方面,需要先安装ROS2 Humble基础环境。这里有个小技巧:如果之前安装过其他ROS版本,建议新建一个工作空间,避免依赖冲突。我使用的是以下命令:
bash复制sudo apt install ros-humble-desktop
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws
colcon build
安装完成后,建议先单独测试相机驱动。Astra相机在ROS2中的驱动是ros2_astra_camera,可以通过以下命令安装:
bash复制sudo apt install ros-humble-astra-camera
ORB-SLAM3是当前最先进的视觉SLAM方案之一,相比前代有几个关键改进:
不过官方代码默认只支持ROS1,我们需要进行ROS2适配。这里我推荐使用orbslam3-ros2这个第三方移植版本,实测稳定性不错:
bash复制cd ~/ros2_ws/src
git clone https://github.com/thien94/orbslam3-ros2.git
编译时需要特别注意依赖项:
深度相机的标定质量直接影响SLAM效果。我总结了一套高效的标定流程:
bash复制ros2 run camera_calibration cameracalibrator \
--size 8x6 \
--square 0.024 \
image:=/camera/color/image_raw
小技巧:标定板要尽量充满画面不同区域,每个位置保持2-3秒静止
bash复制ros2 run astra_camera align_checker
这个自定义工具可以检查彩色图与深度图的对齐质量,我建议误差控制在1-2像素内。
kalibr工具,不过配置较复杂,初学者可以先跳过。创建自定义launch文件orbslam3_astra.launch.py,关键配置如下:
python复制Node(
package='orbslam3_ros2',
executable='mono',
name='orbslam3',
parameters=[{
'voc_file': voc_path,
'settings_file': settings_path,
'map_frame_id': 'orbslam3_map',
'pose_frame_id': 'orbslam3_pose'
}],
remappings=[
('/camera/image_raw', '/camera/color/image_raw')
]
)
参数调优经验:
ORBextractor.nFeatures:建议设为2000-3000(Astra分辨率较低)ThDepth:深度验证阈值,默认35,室内可降到25Camera.fps:必须与实际帧率一致(Astra通常30fps)在Jetson等嵌入式设备上运行时,我发现了几个有效的优化手段:
python复制image_sub = self.create_subscription(
Image,
'/camera/color/image_raw',
self.image_callback,
QoSProfile(depth=1, reliability=2)
)
设置QoS策略为Best Effort可以降低延迟
ORB_SLAM3/Examples/ROS2/ORB_SLAM3/src/ros_mono.cc中的关键帧插入条件:cpp复制if(mpTracker->mLastFrame.mnId%5==0) // 原为3
System::Reset()清空地图,避免长时间运行内存泄漏| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 初始化失败 | 特征点不足 | 调整ORBextractor.nFeatures参数 |
| 跟踪频繁丢失 | 运动过快/光照变化 | 降低相机帧率或增加曝光补偿 |
| 地图漂移严重 | 闭环检测失效 | 检查词汇表文件路径是否正确 |
Astra相机偶尔会出现深度数据异常,我编写了一个简单的滤波节点:
python复制depth_img = bridge.imgmsg_to_cv2(msg)
depth_img[depth_img > 4000] = 0 # 去除过远噪点
depth_img = cv2.medianBlur(depth_img, 3) # 中值滤波
ORB-SLAM3输出的坐标系与ROS标准不同,需要转换:
python复制tf_buffer = tf2_ros.Buffer()
listener = tf2_ros.TransformListener(tf_buffer)
transform = tf_buffer.lookup_transform(
'map', 'orbslam3_pose', rclpy.time.Time()
)
结合IMU数据可以显著提升动态场景下的稳定性。我修改了ros_stereo_inertial.cc使其支持Astra:
cpp复制// 在图像回调中同步IMU数据
vector<ORB_SLAM3::IMU::Point> vImuMeas;
mpImuGb->getMeasurements(img_msg->header.stamp, vImuMeas);
在Jetson Xavier上部署时,建议:
sudo systemctl set-default multi-user.targetjetson_clocks锁定最高频率cpp复制mpORBextractorLeft = new ORBextractor(
nFeatures,fScaleFactor,nLevels,fIniThFAST,fMinThFAST,2); // 原为4
扩展地图保存功能:
python复制def save_map_service_cb(request, response):
slam.SaveMap(request.map_path)
return response
self.save_srv = self.create_service(
SaveMap, 'save_map', self.save_map_service_cb)
这个项目最让我惊喜的是ORB-SLAM3在低算力设备上的表现。经过适当优化后,即使在Jetson Nano上也能实现10fps的稳定跟踪。不过要注意的是,Astra相机的深度噪声在强光环境下会明显增加,建议在室内使用时拉上窗帘。另外发现一个有趣的现象:在纹理丰富的环境中,关闭深度数据反而能得到更稳定的跟踪结果,这可能是因为ORB特征本身对几何信息依赖较强。