0 写在前面

在本博客系列中将主要介绍:

  1. 使用ROS系统中URDF模型建立语言设计一个两轮移动机器人
  2. 使用XACRO——这一衍生自URDF的更加高效的模型建立语言对URDF构建的机器人进行优化,并进行机器人的传感器功能实现
  3. 利用Rviz实现机器人感知世界的显示
  4. 这是笔者的第一篇博客,希望获得大家的喜欢,如有问题,不胜赐教,期待大家的赞与评论~

1 URDF与Rviz集成

目标

利用 URDF创建一个具备两个主动轮,一个雷达传感器以及一个摄像头的移动机器人模型,并在 Rviz中显示

实现手段

利用URDF搭建了一个具有box形状的base_link,并将其作为kinect深度相机传感器;具有cylinder形状的wheel;具有cylinder形状的用于支撑激光雷达的hold_laser_link(这是为了防止相机遮盖住激光雷达的视野);具有box形状的camera_link,并将其作为移动机器人的相机传感器;具有cylinder形状的laser_link,并将其作为移动机器人的激光传感器;具有sphere球体形状的base_footprint,设置该link具体原因请见注意事项;具有sphere球体形状的front、back_wheel,用于实现机器人的全向旋转

代码

URDF文件

其中需要强调的是文件目录,此URDF文件储存在如下路径:
airobot_ws/src/myCar_move/urdf/urdf/hw_car_final.urdf
其中代码见下:

<robot name="mycar">

    <link name="base_footprint">
        <visual>
            <geometry>
                <sphere radius="0.001" />
            </geometry>
        </visual>
    </link>


    <link name="base_link">
        <visual>
            <geometry>
                <box size ="0.2 0.2 0.08"/>
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="blue">
                <color rgba="0 0 0.8 1" />
            </material>
        </visual>
    </link>

    <joint name="base_link2base_footprint" type="fixed">
        <parent link="base_footprint" />
        <child link="base_link"/>
        <origin xyz="0 0 0.055" />
    </joint>


    <link name="left_wheel">
        <visual>
            <geometry>
                <cylinder radius="0.0325" length="0.015" />
            </geometry>
            <origin xyz="0 0 0" rpy="1.5705 0 0" />
            <material name="black">
                <color rgba="0.0 0.0 0.0 1.0" />
            </material>
        </visual>

    </link>

    <joint name="left_wheel2base_link" type="continuous">
        <parent link="base_link" />
        <child link="left_wheel" />
        <origin xyz="0 0.1 -0.0225" />
        <axis xyz="0 1 0" />
    </joint>


    <link name="right_wheel">
        <visual>
            <geometry>
                <cylinder radius="0.0325" length="0.015" />
            </geometry>
            <origin xyz="0 0 0" rpy="1.5705 0 0" />
            <material name="black">
                <color rgba="0.0 0.0 0.0 1.0" />
            </material>
        </visual>

    </link>

    <joint name="right_wheel2base_link" type="continuous">
        <parent link="base_link" />
        <child link="right_wheel" />
        <origin xyz="0 -0.1 -0.0225" />
        <axis xyz="0 1 0" />
    </joint>

    <link name="front_wheel">
        <visual>
            <geometry>
                <sphere radius="0.0075" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="black">
                <color rgba="0.0 0.0 0.0 1.0" />
            </material>
        </visual>
    </link>

    <joint name="front_wheel2base_link" type="continuous">
        <parent link="base_link" />
        <child link="front_wheel" />
        <origin xyz="0.0925 0 -0.0475" />
        <axis xyz="1 1 1" />
    </joint>

    <link name="back_wheel">
        <visual>
            <geometry>
                <sphere radius="0.0075" />
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0" />
            <material name="black">
                <color rgba="0.0 0.0 0.0 1.0" />
            </material>
        </visual>
    </link>

    <joint name="back_wheel2base_link" type="continuous">
        <parent link="base_link" />
        <child link="back_wheel" />
        <origin xyz="-0.0925 0 -0.0475" />
        <axis xyz="1 1 1" />
    </joint>

    <link name="hold_laser_link">
        <visual>
            <origin xyz=" 0 0 0 " rpy="0 0 0" />
            <geometry>
                <cylinder length="0.06" radius="0.02"/>
            </geometry>
            <material name="yellow">
                <color rgba="0.8 0.3 0.1 0.5" />
            </material>
        </visual>
    </link>
    <joint name="hold_laser_joint" type="fixed">
        <origin xyz="0 0 0.07" rpy="0 0 0"/>
        <parent link="base_link"/>
        <child link="hold_laser_link"/>
    </joint>    

    <link name="laser_link">
        <visual>
            <origin xyz=" 0 0 0 " rpy="0 0 0" />
            <geometry>
                <cylinder length="0.04" radius="0.04"/>
            </geometry>
            <material name="black"/>
        </visual>
    </link>
    <joint name="laser_joint" type="fixed">
        <origin xyz="0 0 0.05" rpy="0 0 0"/>
        <parent link="hold_laser_link"/>
        <child link="laser_link"/>
    </joint>

    <link name="central_camera_link">
        <visual>
            <origin xyz=" 0 0 0 " rpy="0 0 0" />
            <geometry>
                <box size="0.012 0.022 0.022" />
            </geometry>
            <material name="black">
                <color rgba="0 0 0 0.95"/>
            </material>
        </visual>
    </link>
    <joint name="central_camera_joint" type="fixed">
        <origin xyz="0.089 0 0.046" rpy="0 0 0"/>
        <parent link="base_link"/>
        <child link="central_camera_link"/>
    </joint>

</robot>

launch文件

为了使用Rviz,就需要将我们编写的URDF与启动Rviz的节点一同包含在launch文件中,同样的,首先需要关注的是我们的文件路径:
airobot_ws/src/myCar_move/launch/hw_car_move_urdf.launch
同时,为了显示,需要将Rviz中的Fixed Frame改为机器人本体坐标系(base_link等均可),其中代码见下:

<launch>

    <!-- 设置参数 -->
    <param name="robot_description" textfile="$(find myCar_move)/urdf/urdf/hw_car_final.urdf" />

    <!-- 启动 rviz -->
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find my_car)/config/test01.rviz" />

    <!-- 添加关节状态发布节点 -->
    <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" />
    <!-- 添加机器人状态发布节点 -->
    <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" />
    <!-- 可选:用于控制关节运动的节点 -->
    <!--安装 sudo apt install ros-《ROS版本》-joint-state-publisher-gui-->
    <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" />
    <!--集成arbotix运动控制节点-->
    <node name="arbotix" pkg="arbotix_python" type="arbotix_driver" output="screen">
        <!--加载配置文件-->>
        <rosparam file="$(find myCar_move)/config/control.yaml" command="load" />
        <!--设置为仿真-->
        <param name="sim" value="true" />
    </node>

</launch>

效果展示

urdf与rviz集成

2 Xacro与Rviz集成

目标

利用xacro ,将编写的 urdf文件进行优化,同样实现在 Rviz中显示

实现手段

相对于URDF语法,xacro主要在以下方面进行了优化:

  1. 首先对机器人进行模块化处理,分成了若干个.xacro文件,分别构造不同的模块,例如my_head负责构建不同形状的惯性矩阵,car负责引用各个模块,进而组件小车;
  2. 其次是对变量值的处理,区别于URDF,xacro支持将变量用宏的形式来显示,并支持运算后赋值;
  3. 最后是对机器人传感器以及gazebo的支持,可以通过ros_gzplugins网站下载各个传感器的具体.xacro文件,并且只需修改些些许语句,便可实现对传感器各个参数的设置,实现对gazebourdf的集成

文件结构

将小车模块化之后的xacro文件夹,有如下的目录结构:

└───xacro
        camera.xacro
        car.xacro
        kinect.xacro
        laser.xacro
        move.xacro
        my_base.xacro
        my_camera.xacro
        my_head.xacro
        my_laser.xacro

代码

xacro代码

首先仍然是关注文件夹路径:
airobot_ws/src/my_car/urdf/xacro
接着需要说明的是,笔者并不会介绍xacro的具体语法,请需要了解xacro代码用法的同学自行上网搜索。对于此机器人,xacro代码并没有很复杂,主要工作在于定义宏,定义关节形状,定义惯性矩阵,定义传感器参数等工作,文件可点此下载,文件提取码llys

launch文件代码

启动xacroRviz集成指令launch文件目录为:
airobot_ws/src/myCar_move/launch/hw_car_move_xacro.launch'
同样为了显示,需要将Fixed Frame改为机器人本体坐标系(base_link等均可)

<launch>

    <!-- 设置参数 -->
    <param name="robot_description" command="$(find xacro)/xacro $(find my_car)/urdf/xacro/car.xacro" />

    <!-- 启动 rviz -->
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find my_car)/config/test01.rviz" />

    <!-- 添加关节状态发布节点 -->
    <node pkg="joint_state_publisher" type="joint_state_publisher" name="joint_state_publisher" />
    <!-- 添加机器人状态发布节点 -->
    <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher" />
    <!-- 可选:用于控制关节运动的节点 -->
    <!--安装 sudo apt install ros-《ROS版本》-joint-state-publisher-gui-->
    <node pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" name="joint_state_publisher_gui" />
    <!--集成arbotix运动控制节点-->
    <node name="arbotix" pkg="arbotix_python" type="arbotix_driver" output="screen">
        <!--加载配置文件-->>
        <rosparam file="$(find myCar_move)/config/control.yaml" command="load" />
        <!--设置为仿真-->
        <param name="sim" value="true" />
    </node>

</launch>

效果展示

xacro与rviz
各个传感器数据在Rviz中的显示如下:
传感器数据
tips:左下角的camera传感器数据显示,Rviz中的Laser传感器显示
奇怪的彩色点云
tips:利用kinect获得的rviz中的深度彩色点云,注意彩色点云位置十分奇怪
具体原因、解决方案请见注意事项

3 注意事项

关于kinect中深度点云坐标系的问题

观察上节中的效果展示,机器人的深度彩色点云显示的很奇怪,其原因主要在于在kinect中图像数据与点云数据使用了两套坐标系统,且两套坐标系统位姿并不一致,其解决方案

  • kinect.xacro中设置坐标系,修改配置文件的<frameName>标签内容:
<frameName>support_depth</frameName>
  • 发布新设置的坐标系到kinect连杆的坐标变换关系,在启动rviz的launch中,添加:
<node pkg="tf2_ros" type="static_transform_publisher" name="static_transform_publisher" args="0 0 0 -1.57 0 -1.57 /support /support_depth" />
  • 启动rviz,重新显示如下图:
    正常的彩色点云

关于base_footprint的建立

base_footprint显示如下:
base_footprint
通过查阅相关资料,base_footprint坐标系直译理解为在地面上机器人位置的投影,下面是关于设立此坐标系最关键的几个原因:

  1. 当机器人为特殊构型,例如人形,四足时,作为基坐标系的base_link会上下摇摆,不利于上层例如导航、建图等功能的设计,更深层的原因是他会是得里程计坐标系/odom严重漂移,而建立base_footprint即投影坐标系后,能够为里程计的设计提供一个稳定的参考

  2. 用于显示,将机器人抬高至水平面以上,同步现实设计

  3. 用于各个外部工具包的使用,大多导航,建图等工具包均是建立/base_footprint以及/odom/tf变换关系

关于xacro的参数服务器传参

在launch代码中需要注意xacro文件中为了设置参数,传参机器人文件需要利用<command>指令(URDF中为<textfile>)

4 写在最后

以上是环境搭建三部曲的第一节,接下来还会更新第二和三节,还希望大家喜欢~,在这挖个坑,或许将来还有移动机器人导航三部曲^_^