在我们的生活中二维码运用广泛,比如说收款码、健康码、共享单车等等。二维码在机器人的世界中又能起到什么作用呢?

1.   二维码的由来

我们首先了解了解二维码是什么。二维码又称二维条码,常见的二维码为QR(Quick Response)Code,是一个近几年来移动设备上超流行的一种编码方式,它比传统的Bar Code条形码能存更多的信息,也能表示更多的数据类型。

二维码是用某种特定的几何图形按一定规律在平面(二维方向上)分布的、黑白相间的、记录数据符号信息的图形。在代码编制上巧妙地利用构成计算机内部逻辑基础的“0”、“1”比特流的概念,使用若干个与二进制相对应的几何形体来表示文字数值信息,通过图象输入设备或光电扫描设备自动识读以实现信息自动处理。它具有条码技术的一些共性:每种码制有其特定的字符集,每个字符占有一定的宽度,具有一定的校验功能等。同时还具有对不同行的信息自动识别功能,以及处理图形旋转变化点。常见的几种二维码如下所示:

2.   机器人识别什么样的二维码?

ROS中提供了多种二维码识别的功能包,下面我们就选用其中一个功能包(ar_track_alvar)来介绍二维码识别与跟踪。

ar_track_alvar是虚拟现实和增强现实的跨平台开源计算机视觉库( Linux、Windows和Mac OS等),由C++编写,同时提供C++的接口。

ar_track_alvar可以用于识别并跟踪各个AR标签的姿态,并且可以选择整合深度相机的深度数据(在有深度相机可用时),以实现更好的姿态估计。ar_track_alvar也可以用于识别并跟踪由多个标签组成的“捆绑包”的状态。这样可以实现更稳定的姿态估计,对遮挡的鲁棒性以及对多边物体的跟踪。

运行以下命令安装ROS的开源AR标签跟踪库ar_track_alvar。

$ sudo apt-get install ros-melodic-ar-track-alvar

ar_track_alvar功能包还提供了二维码标签的生成功能,可以使用如下命令创建相应标号的二维码标签:

$ rosrun ar_track_alvar createMarker AR_ID

其中AR_ID可以是从0到65535之间的任意数字的标号,例如:

$ rosrun ar_track_alvar cerateMarker 0

可以创建一个标号为0的二维码标签图片,命名为MarkerData_0.png,并保存在当前的路径下。保存的二维码如下图所示。

createMarker工具还有很多参数可以进行配置,使用以下命令即可查看使用帮助:

$ rosrun ar_track_alvar cerateMarker

从上图可以看出,createMarker不仅可以使用数字标号生成二维码标签,也可以使用字符串、文件名、网址等,还可以使用-s参数设置生成二维码的尺寸。

可以使用如下命令在robot_vision/config(自定义)文件夹中创建一系列二维码标签:

$ roscd robot_vision/config

$ rosrun ar_track_alvar createMarker -s 5 0

$ rosrun ar_track_alvar createMarker -s 5 1

$ rosrun ar_track_alvar createMarker -s 5 2

生成的二维码如下图所示,最好将这些二维码打印出来粘贴到硬纸板上,以备使用。

3.   机器人识别二维码

首先,复制ar-track-alvar功能包launch文件夹中的pr2_indiv.launch文件作为蓝本,针对使用的RealSense D435i相机进行修改,修改好的ar_code.launch文件如下所示:

<launch>
  <arg name="marker_size"          default="15" />
  <arg name="max_new_marker_error" default="0.08" />
  <arg name="max_track_error"      default="0.2" />
  
  <arg name="output_frame"         default="/camera_color_optical_frame" />
  <arg name="camera_image_topic"   default="/camera/color/image_raw" />
  <arg name="camera_info_topic"    default="/camera/color/camera_info" />

  <node name="ar_track_alvar" pkg="ar_track_alvar" type="individualMarkersNoKinect" respawn="false" output="screen">
    <param name="marker_size"          type="double" value="$(arg marker_size)" />
    <param name="max_new_marker_error" type="double" value="$(arg max_new_marker_error)" />
    <param name="max_track_error"      type="double" value="$(arg max_track_error)" />
    <param name="output_frame"         type="string" value="$(arg output_frame)" />

    <remap from="camera_image" to="$(arg camera_image_topic)" />
    <remap from="camera_info"  to="$(arg camera_info_topic)" />
  </node>

  <node name="rviz" pkg="rviz" type="rviz" args="-d $(find limo_visions)/rviz/ar_rviz.rviz" />
</launch>

其中"camera_image_topic"和"camera_info_topic"需要设置为实际发布的相应话题名。

运行以下命令启动相机并识别二维码:

$ roslaunch realsense2_camera rs_rgbd.launch  #启动相机

$ roslaunch limo_vision ar_code.launch        #识别二维码

二维码识别效果如下图所示:

可以看出,此launch文件可以同时识别一个或者多个二维码,图像中的二维码上会出现坐标轴,代表识别到的二维码姿态。识别到的二维码姿态通过"/ar_pose_marker"话题发布出来,如下图所示:

4.   移动机器人二维码识别与跟踪

通过前面的launch文件可以获取识别到的二维码的位姿信息,再根据位姿信息设置相应的速度,即可实现移动机器人二维码识别与跟踪。代码如下所示:

import rospy
import numpy as np
from geometry_msgs.msg import Twist
from ar_track_alvar_msgs.msg import AlvarMarkers
BEGIN_DISTANCE = 0.8
OVER_DISTANCE = 0.2
class MoveToTarget(object):
    def __init__(self):
        # ros 初始化
        rospy.init_node('move_to_target_ar', anonymous=True)
        # 发布控制机器人的消息
        self.vel_pub = rospy.Publisher('cmd_vel', Twist, queue_size=5)

        # 创建一个Subscriber,订阅/object_detect_pose
        self.pose_sub = rospy.Subscriber("/ar_pose_marker",
                                         AlvarMarkers,
                                         self.poseCallback,
                                         queue_size=10)
        # 初始化状态标志
        print("Wait for Exploring ...")

    def poseCallback(self, msg):
        for marker in msg.markers:
            qr_x = marker.pose.pose.position.x
            qr_y = marker.pose.pose.position.y
            qr_z = marker.pose.pose.position.z
            rospy.loginfo("Target{} Pose: x:{}, y:{}, z:{}".format(
                marker.id, qr_x, qr_y, qr_z))

            if marker.id is 0 and qr_z < BEGIN_DISTANCE:
                vel = Twist()
                vel.linear.x =  qr_z * 0.5  
                vel.angular.z = -5.0 * qr_x  
                self.vel_pub.publish(vel)
                rospy.loginfo(
                    "Publsh velocity command[{} m/s, {} rad/s]".format(
                        vel.linear.x, vel.angular.z))

if __name__ == '__main__':
    try:
        MoveToTarget()
        rospy.spin()
    except rospy.ROSInterruptException:
        rospy.loginfo("Exploring logistics finished.")

订阅机器人的位姿信息"/ar_pose_marker",然后根据二维码所在位置的x坐标和z坐标进行速度设置,然后通过话题"/cmd_vel"发布出来,以此实现机器人二维码识别与跟踪。

理论分析完毕,让我们在LIMO移动机器人上面试试看效果怎么样吧。将识别和跟随整合到一起(ar_control.launch),即可实现二维码跟随运动。ar_control.launch如下所示:

<launch>
    <include file="$(find limo_bringup)/launch/limo_start.launch" />
    <include file="$(find realsense2_camera)/launch/rs_rgbd.launch">
        <arg name="publish_tf" value="true" />
    </include>
    <include file="$(find limo_visions)/launch/ar_code.launch" />
    <node name="move_to_target_ar" pkg="limo_visions" type="move_to_target_ar.py" output="screen" />
</launch>

运行以下命令启动机器人底盘和相机实现二维码识别与跟踪:

$ roslaunch limo_visions ar_control.launch

LIMO移动机器人二维码识别与跟踪的效果如下:

从实现效果中可以看出,二维码识别效果很好,没有出现漏检的情况,而且二维码所携带的位姿信息比较全,可以很好地应用到需要位置标定的项目当中去。