从玩具车到AGV:手把手教你用ARUCO二维码给ROS机器人做个简易‘路标’定位系统
从玩具车到AGV:手把手教你用ARUCO二维码给ROS机器人做个简易‘路标’定位系统
去年在指导大学生机器人竞赛时,有个队伍拿着他们的TurtleBot3问我:"老师,我们预算有限,能不能不用激光雷达实现室内定位?"这个问题让我想起了十年前用反光板和二维码做AGV导航的工业案例。今天,我们就用这个思路,教大家用几分钱成本的ARUCO二维码,为ROS机器人搭建一套高性价比的"虚拟路标"系统。
1. 为什么选择ARUCO定位方案
在机器人定位领域,我们常面临这样的困境:激光SLAM精度高但设备昂贵(一套LIDAR动辄上万元),轮式编码器成本低却存在累积误差,视觉SLAM对算力要求较高。而ARUCO二维码定位就像是在环境中布置"数字路标",每个标记都带有唯一ID和已知尺寸,机器人通过摄像头识别这些标记,就能快速确定自身方位。
这套方案有三大突出优势:
- 成本极低:普通USB摄像头(100-300元)+ 打印的二维码(几分钱/张)
- 部署灵活:标记可随意粘贴、移动,无需改造环境
- 教育价值:完整涵盖图像处理、坐标变换、位姿估计等机器人核心技术
提示:ARUCO是Augmented Reality University of Cordoba的缩写,这种二维码专为增强现实设计,比普通QR码具有更高的识别率和抗干扰能力。
2. 环境搭建与工具准备
2.1 硬件配置清单
| 设备类型 | 推荐型号 | 预算范围 |
|---|---|---|
| 开发平台 | Raspberry Pi 4B | 400-600元 |
| 单板计算机 | NVIDIA Jetson Nano | 800-1200元 |
| USB摄像头 | Logitech C920 | 200-300元 |
| 机器人底盘 | TurtleBot3 Burger | 3000-5000元 |
| 二维码打印材料 | 亚光铜版纸(200g) | 20元/100张 |
2.2 软件环境安装
首先确保已安装ROS Noetic(Ubuntu 20.04)或ROS Melodic(Ubuntu 18.04),然后执行以下命令安装ARUCO相关功能包:
sudo apt-get install ros-$ROS_DISTRO-aruco ros-$ROS_DISTRO-aruco-msgs ros-$ROS_DISTRO-aruco-ros cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/pal-robotics/aruco_ros catkin_make遇到CV_FILLED报错时,编辑simple_double.cpp文件,将所有CV_FILLED替换为-1即可。这个参数表示绘制实心圆,新版本OpenCV中常量定义发生了变化。
3. 创建你的虚拟路标系统
3.1 生成ARUCO标记
使用在线生成器创建不同ID的标记(推荐尺寸10cm×10cm):
import cv2 import numpy as np dictionary = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_6X6_250) markerImage = np.zeros((700, 700), dtype=np.uint8) markerImage = cv2.aruco.generateImageMarker(dictionary, 42, 700, markerImage, 1) cv2.imwrite("marker42.png", markerImage)关键参数说明:
DICT_6X6_250:表示使用6×6比特的字典,包含250个不同标记- 数字42:标记的唯一ID(0-249)
- 700:输出图像分辨率
3.2 摄像头标定实战
未标定的摄像头就像近视眼,看到的图像会有畸变。执行单目标定:
rosrun camera_calibration cameracalibrator.py \ --size 8x6 \ --square 0.024 \ image:=/usb_cam/image_raw \ camera:=/usb_cam操作要点:
- 使用棋盘格标定板(建议打印A4尺寸)
- 在摄像头前移动标定板,覆盖整个视野
- 当所有进度条变绿后点击"CALIBRATE"
- 保存生成的
ost.yaml文件到~/.ros/camera_info/
4. 实现机器人定位功能
4.1 启动识别节点
创建single.launch文件配置识别参数:
<launch> <arg name="markerId" default="42"/> <arg name="markerSize" default="0.1"/> <!-- 单位:米 --> <arg name="camera_frame" default="usb_cam"/> <arg name="marker_frame" default="aruco_marker"/> <node pkg="aruco_ros" type="single" name="aruco_single"> <remap from="/camera_info" to="/usb_cam/camera_info" /> <remap from="/image" to="/usb_cam/image_raw" /> <param name="image_is_rectified" value="True"/> <param name="marker_size" value="$(arg markerSize)"/> <param name="marker_id" value="$(arg markerId)"/> <param name="reference_frame" value="$(arg camera_frame)"/> <param name="camera_frame" value="$(arg camera_frame)"/> <param name="marker_frame" value="$(arg marker_frame)" /> </node> </launch>启动顺序:
roslaunch usb_cam usb_cam.launchroslaunch aruco_ros single.launchrostopic echo /aruco_single/pose
4.2 坐标变换与定位
获取的位姿数据是相对于摄像头的,需要转换到机器人坐标系。创建TF广播节点:
#!/usr/bin/env python import rospy import tf from geometry_msgs.msg import PoseStamped def pose_callback(msg): br = tf.TransformBroadcaster() br.sendTransform((msg.pose.position.x, msg.pose.position.y, msg.pose.position.z), (msg.pose.orientation.x, msg.pose.orientation.y, msg.pose.orientation.z, msg.pose.orientation.w), rospy.Time.now(), "base_link", "camera_link") rospy.init_node('marker_tf_broadcaster') rospy.Subscriber('/aruco_single/pose', PoseStamped, pose_callback) rospy.spin()5. 进阶应用与性能优化
5.1 多标记协同定位
当环境中布置多个标记时,可以显著提高定位可靠性。修改launch文件使用markers节点:
<node pkg="aruco_ros" type="markers" name="aruco_markers"> <remap from="/camera_info" to="/usb_cam/camera_info" /> <remap from="/image" to="/usb_cam/image_raw" /> <param name="marker_size" value="0.1"/> <param name="marker_id" value="50,51,52,53"/> <param name="reference_frame" value="map"/> </node>5.2 常见问题排查指南
| 故障现象 | 可能原因 | 解决方案 |
|---|---|---|
| 无法识别标记 | 光照条件差 | 增加补光灯或使用反光材质标记 |
| 位姿数据跳动严重 | 摄像头帧率过低 | 更换高帧率摄像头(≥30fps) |
| 识别距离突然变短 | 标记尺寸参数设置错误 | 检查launch文件中的marker_size |
| 只能识别部分标记 | 字典类型不匹配 | 确保生成和识别使用相同字典 |
在实验室测试中,我们使用10cm×10cm的标记,在2米距离内能达到±1cm的定位精度。当标记倾斜角度小于45度时,识别成功率保持在95%以上。
