2018年5月26日于Carnegie Mellon University
本文的pdf文件可从这里获取。
Ubuntu 16.04 LTS, Python 2.7.12, ROS Lunar
本文中“>>> ”表示在Linux终端中输入命令,某些需要sudo权限的命令可能没有写出sudo。
本文使用的双目相机硬件是LenaCV的产品,该产品可以从中国大陆的淘宝网上采购到。
https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-17461658044.5.6c782004hVg4HU&id=562303637855
本文由Google Docs在线生成,可能出现某些无法调整的格式问题。
相机通过USB连接系统后,在Linux中识别该设备
>>> lsusb
显示结果如图 1所示,其中Device 008即为当前调试的设备。
安装GTK UVC video viewer. 在接上相机后,运行UVC video viewer,所得画面如图 2所示。通过画面上几个控制滑块控制相机参数以进行调试和测试。LenaCV相机返回的实时画面是一张图,相机内部应当已经完成了同步,并将两个相机的图像进行了拼接。经过实测发现拼接图像的右侧实际上为左摄像头的画面。
图2 使用GTK UVC video viewer直接调试设备
主要调试过程参考了libuvc_camera的官方wiki
http://wiki.ros.org/libuvc_camera
首先需要确保系统正常安装了ROS,并且ROS处于可以使用状态。
创建一个catkin workspace或者使用已经存在的catkin workspace。切换到catkin workspace的src文件夹,将libuvc_camera的git仓库clone到本地。
>>> git clone https://github.com/ros-drivers/libuvc_ros.git
返回到src文件夹上一级,启动catkin_make进行编译,若报缺少某些库,则直接利用apt-get进行安装即可。
根据libuvc_camera官方wiki的描述,使用uvc设备需要拥有一定权限,推荐的做法是针对需要使用的硬件设备添加udev rule。具体做法如下,在/etc/udev/rules.d文件夹下新建文件99-uvc.rules(需要root权限)。这个文件将描述相机的所有者,将所有者设置为当前用户即可。该文件的文件名一般都是以数字开头,其目的是控制文件之间的排序。数字越小,排序越靠前。这样做的道理是Linux系统将在加载硬件驱动的过程中有时会有一些次序要求,用文件名的次序可以控制这些rule加载的先后。99-uvc.rules的内容如table 1所示。
表1 99-uvc.rules
# UVC cameras
SUBSYSTEMS=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1e4e", ATTRS{idProduct}=="0568", OWNER="<用户名>"
其中OWNER即为需要设置的用户名,这里将其设置为当前用户,idVendor和idProduct直接复制lsusb返回结果中的数值。保存该文件,此后需要将相机重新插拔一次。此后libuvc_camera若不能正常launch,ROS报权限不够错误,处理方法参考3.3节。
libuvc_camera定义了一个ros node,名为camera_node,启动这个node一般通过一个launch文件。本测试使用的launch文件内容如table 2所示。
表2 launch file
如table 2所示,需要定义几个参数来控制相机,其中width、height、video_mode和frame_rate需要通过v4l2-ctl命令参看,v4l2-ctl需要通过apt-get安装。安装好v4l2-ctl后,执行
>>> v4l2-ctl --list-formats-ext
执行结果如图 3所示。从结果上看相机支持的video_mode包括MJPG,在配置launch file时,需要指定video_mode为mjpeg。图像大小和帧率也需根据图 3中的结果设置。
图3 v4l2-ctl执行结果
启动launch file。
>>> roslaunch
首次启动可能由于权限问题而失败,出现如图 4所示画面。此时通过如下命令进行修正
>>> sudo chmod o+w /dev/bus/usb/003/004
其中 003/004 是中报错信息中的部分,请用户根据自己的报错信息进行修改。
图4 权限问题导致启动失败
正确启动时,终端中显示的内容如table 3所示。
表3 libuvc_camera启动消息
... logging to /home/yyhu/.ros/log/2183dccc-5ee1-11e8-8cb9-5800e3fc52bd/roslaunch-airlab-14474.log |
正确启动了libuvc_camera后,可以通过ROS的rqt_image_view查看图像,所用到的topic为/camera/image_raw。rqt_image_view的查看结果如图 5所示。
图5 rqt_image_view的查看结果
在线双目标定将利用ROS提供的camera_calibration包实现。
为了能够使用ROS的camera_calibration包,需要将相机的画面从一幅图像拆分为两幅图像,分别对应双目摄像机的两个相机,并且各自发布一个topic。我们需要一个node,订阅libuvc_camera的topic,实时将画面一分为二,并发布两个新的topic。这里将创建一个新的专用publisher完成以上工作。
首先进入catkin workspace的src目录,创建一个新的package,本文中使用的package名称为“lenacv”
>>> catkin_create_pkg lenacv std_msgs rospy roscpp
之后返回到src上一级,使用catkin_make进行初步编译,生成必要的文件。重新执行devel/setup.bash。
>>> source devel/setup.bash
重新回到lenacv的目录,创建scripts目录并进入。编写一个新的ROS node的python文件,内容如table 4所示。这个node名为listen_uvc,并将publish两个新的topic,分别为lenacv_left和lenacv_right。该文件命名为separator.py。
表4 ROS node
请参考Github仓库的最新版本 https://github.com/huyaoyu/catkins/blob/master/lenacv/scripts/separator.py |
修改ROS node源码文件的执行权限。
>>> chmod +x separator.py
在外层目录重新执行catkin_make。启动libuvc_camera,之后通过
>>> rosrun lenacv separator.py
来启动刚刚创建的listen_uvc node。启动ROS rqt,添加两个image view的plugin,并各自显示来自lenacv_left和lenacv_right的数据,效果如图 6所示。
图6 拆分后的双目图像
本节主要参考
http://wiki.ros.org/camera_calibration/Tutorials/StereoCalibration
双目标定使用ROS提供的camera_calibration包。在进行双目标定前,先打印棋盘格标定板。将打印好的标定板平整地固定在某一平面物体表面,利用直尺测量标定板上棋盘格的边长。标定时启动libuvc_camera,启动lenacv_camera的separator.py,最后通过下述命令启动camera_calibration。
>>> rosrun camera_calibration cameracalibrator.py --size 8x6 --square 0.0345 right:=/lenacv_camera/right/image_raw left:=/lenacv_camera/left/image_raw right_camera:=/lenacv_camera/right left_camera:=/lenacv_camera/left --no-service-check
此处--size 参数为所用棋盘格的交叉点数量和排布,如图 7所示,圆点所在位置为交叉点。--size参数的第一个数字为交叉点的列数。请确保棋盘格的两个边长方向上的交叉点的数量是不同的,并且保持长边处于水平。--square 参数为棋盘格的边长,单位为m。请确保使用正四边形的棋盘格。
图7 棋盘格
启动后将看到双目的实时灰度图像。通过鼠标调整程序窗口的大小以获得比较清晰的视角。将棋盘格至于双目相机的视野内,确保两个相机都能同时捕捉到清晰完整的棋盘格图像。cameracalibrator.py将自动识别棋盘格,并在识别到第一个棋盘格后,出现“X”、“Y”、“size”和”skew”字样。这些字样下方均有一个类似进度条的标志。移动棋盘格,cameracalibrator.py将自动辨识棋盘格,并在灰度画面上叠加识别到的棋盘格交叉点的彩色图像,如图 8所示。
图8 标定过程中实时识别到的棋盘格
当棋盘格的识别和当前棋盘格的位置符合要求时,cameracalibrator.py有可能将其记录进最终标定数据集。一个棋盘格的输入是否进入最终标定数据集,也取决于棋盘格与相机相对位置在标定数据集中是否已经有类似记录。cameracalibrator.py会试图使记录的数据尽可能的适合用于标定“X”、“Y”、“size”和”skew”并得到更好的效果,它会主动控制数据集数量和范围。每收集到一组棋盘格的有效数据后,终端上会出现提示,如图 9所示,并且上述“X”、“Y”、“size”和”skew”所对应的进度条也会相应增长。
图9 收集棋盘格数据
如图 10所示,当数据集收集到了足够的数据,界面上的“Calibrate”按钮将进入使能状态,此时用鼠标点击该按钮开始标定。
图10 使能状态的calibrate按钮
标定可能持续一定时间,此时软件界面可能失去相应,需耐心等待。当标定结束后,终端中将显示标定结果。点击软件界面上的“save”按钮,将标定结果(以及标定数据集)记录在文件系统上。此后可手工复制上述保存好的文件到其他指定位置。注意,保存的数据仅包含两个相机各自的intrinsics,extrinsics仅在屏幕上做出显示,他们所在的位置如图 11所示。手工复制extrinsics,并记录在文件上以留后期使用。
图11 标定得到的extrinsics