基于ros-neotic系统的多个差速小车仿真实现(从入门到入土教程)

目录

1、前言

2、创建工作空间

3、创建单个小车的底盘

4、添加小车的驱动轮和万向轮

5、添加小车控制运动的文件

6、增加多个小车


1、前言

        本人是JUN自动化专业大三的学生,自学ROS(robot operation system--机器人操作系统)已经有半年的时间,在学习ros之前对于ros系统属于一问三不知的学习情况,只是对于python基本的语法(例如基本的数组结构和书写格式)但当涉略。也是一路摸爬滚打学习ros过来的,再次也非常感谢我的导师给我这个机会和平台学习ROS系统。

        写下这篇文章的初衷是为了记录我的ROS学习路程,也是为了温习之前ROS知识操作体系,如果有错误的地方请读者多多包涵。

2、创建工作空间

2.1、mkdir -p test01_ws/src创建文件夹

# 注意是在根目录下创建工作空间
mkdir -p test01_ws/src

2.2、进入工作空间中,cd test01_ws/

# cd指令是linux常用指令,cd+刚创立的文件夹即可进入工作空间
cd test01_ws/

2.3、使用catkin_make,会多出build和devel文件夹

# 输入指令之前要注意当前的目录是否为刚刚创建的test01_ws/目录
catkin_make

2.4、在test01_ws目录下输入code .启动vs code

# 在test01_ws/目录下输入此指令会自动弹出vs code编译界面并且自动跳转到工作空间
code .

2.5、快捷键Crtl+Shift+B调用编译,选择catkin_make:build,点击后面的小齿轮配置文件,然后修改.vscode/tasks.json文件(注意保存修改后的json文件!!!),修改内容如下:

{
// 有关 tasks.json 格式的文档,请参见
    // https://go.microsoft.com/fwlink/?LinkId=733558
    "version": "2.0.0",
    "tasks": [
        {
            "label": "catkin_make:debug", //代表提示的描述性信息
            "type": "shell",  //可以选择shell或者process,如果是shell代码是在shell里面运行一个命令,如果是process代表作为一个进程来运行
            "command": "catkin_make",//这个是我们需要运行的命令
            "args": [],//如果需要在命令后面加一些后缀,可以写在这里,比如-DCATKIN_WHITELIST_PACKAGES=“pac1;pac2”
            "group": {"kind":"build","isDefault":true},
            "presentation": {
                "reveal": "always"//可选always或者silence,代表是否输出信息
            },
            "problemMatcher": "$msCompile"
        }
    ]
}

2.6、选择src右键,选择create catkin package添加依赖项,先输入src下工作空间的名字urdf01_multi并且按回车开始输入依赖项,这里的依赖项包括gazebo_plugins gazebo_ros gazebo_ros_control urdf xacro(每个依赖项之间使用空格隔开)。

2.7(选做)、如果担心输入依赖项错误,可以打开src下的子文件下的package.xml文件使用快捷键Crtl+Shift+B进行编译,不报错就是正确的。

2.8、在我们刚刚创建的src目录下创建几个文件夹,分别是config、launch、urdf、worlds,同时在urdf文件夹下再创建一个子文件夹gazebo。下面介绍一下创建这些文件夹的意义。

config文件夹:存放我们在rviz中的小车及地图配置文件。

launch文件夹:顾名思义launch是启动的意思,我们需要在此文件夹中存放启动小车模型的文件。

urdf文件夹:存放小车模型配置文件。

worlds文件夹:存放gazebo的地图模型文件。

gazebo文件:存放后期用于控制小车运动、摄像头和雷达传感器配置的文件。

3、创建单个小车的底盘

3.1、在刚刚创建的urdf文件夹下创建名为demo01_car_base.urdf.xacrohead.xacro的文件,下面介绍一下各个文件夹的功能。

demo01_car_base:包含了单个小车的配置代码(包括底盘,驱动轮和万向轮)

car.urdf.xacro:用于集成小车配置文件和控制运动的文件

head.xacro:存放惯性矩阵的代码

3.2、在head.xacro文件中复制粘贴标准的球体、圆柱与立方体的惯性矩阵公式代码(已经封装为了xacro文件)。

<robot name="base" xmlns:xacro="http://wiki.ros.org/xacro">
    <!-- Macro for inertia matrix -->
    <xacro:macro name="sphere_inertial_matrix" params="m r">
        <inertial>
            <mass value="${m}" />
            <inertia ixx="${2*m*r*r/5}" ixy="0" ixz="0"
                iyy="${2*m*r*r/5}" iyz="0" 
                izz="${2*m*r*r/5}" />
        </inertial>
    </xacro:macro>

    <xacro:macro name="cylinder_inertial_matrix" params="m r h">
        <inertial>
            <mass value="${m}" />
            <inertia ixx="${m*(3*r*r+h*h)/12}" ixy = "0" ixz = "0"
                iyy="${m*(3*r*r+h*h)/12}" iyz = "0"
                izz="${m*r*r/2}" /> 
        </inertial>
    </xacro:macro>

    <xacro:macro name="Box_inertial_matrix" params="m l w h">
       <inertial>
               <mass value="${m}" />
               <inertia ixx="${m*(h*h + l*l)/12}" ixy = "0" ixz = "0"
                   iyy="${m*(w*w + l*l)/12}" iyz= "0"
                   izz="${m*(w*w + h*h)/12}" />
       </inertial>
   </xacro:macro>
</robot>

3.3、在demo01_car_base.urdf.xacro文件中输入小车底盘中心点和小车底盘的代码,同时还要输入两者之间通过关节连接的配置代码。

<!-- 根标签,必须声明 xmlns:xacro -->
<robot name="my_base" xmlns:xacro="http://www.ros.org/wiki/xacro">
    <!-- 封装变量、常量 -->
    <xacro:property name="PI" value="3.141"/>
    <!-- 封装宏属性——黑色和黄色 -->
    <material name="black">
        <color rgba="0.0 0.0 0.0 1.0"/>
    </material>
    <material name="yellow">
        <color rgba="0.5 0.3 0.0 0.5"/>
    </material>
    <!-- 底盘属性 -->
    <!-- 小车底盘中心点半径 -->
    <xacro:property name="base_footprint_radius" value="0.001"/>
     <!--小车底盘半径  -->
    <xacro:property name="base_link_radius" value="0.1"/>
    <!-- 小车底盘高度 -->
    <xacro:property name="base_link_length" value="0.08"/>
    <!-- 小车底盘质量 -->
    <xacro:property name="base_mass" value="2"/>
    <!-- 小车底盘离地高度 -->
    <xacro:property name="map_space" value="0.015"/>

    <!-- 小车底盘中心点 -->
    <link name="base_footprint">
        <visual>
            <geometry>
                <sphere radius="${base_footprint_radius}"/>
            </geometry>
        </visual>
    </link>

    <!-- 小车底盘 -->
    <link name="base_link">
        <visual>
            <geometry>
                <cylinder radius="${base_link_radius}" length="${base_link_length}"/>
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0"/>
            <material name="yellow"/>
        </visual>
        <collision>
            <geometry>
                <cylinder radius="${base_link_radius}" length="${base_link_length}"/>
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0"/>       
        </collision>
        <xacro:cylinder_inertial_matrix m="${base_mass}" r="${base_link_radius}" h="${base_link_length}"/>
    </link>
    <gazebo reference="base_link">
        <material>Gazebo/Yellow</material>
    </gazebo>

    <!-- 小车底盘和底盘中心的关节连接 -->
    <joint name="base_link_to_base_footprint" type="fixed">
        <parent link="base_footprint"/>
        <child link="base_link"/>
        <!-- 关节的重心应该位于小车离地间距+一半的小车底盘高度 -->
        <origin xyz="0 0 ${map_space + base_link_length / 2}"/>
    </joint>
</robot>

3.4、在car.urdf.xacro文件中输入集成了demo01_car_base.urdf.xacrohead.xacro文件的代码。

<robot name="my_laser" xmlns:xacro="http://wiki.ros.org/xacro">
    <!-- 包含惯性矩阵 -->
    <xacro:include filename="head.xacro"/>
    <!-- 包含小车配置的xacro文件 -->
    <xacro:include filename="demo01_car_base.urdf.xacro"/>
</robot>

3.5、在demo01_car_base.launch文件中输入启动小车配置Gazebo仿真环境和rviz仿真环境的启动代码。

<launch>
    <!-- 将xacro小车文件加载到参数服务器 -->
    <param name="robot_description" command ="$(find xacro)/xacro $(find urdf01_multi)/urdf/car.urdf.xacro"/>
    <!-- 启动gazebo -->
    <include file="$(find gazebo_ros)/launch/empty_world.launch"/>
    <!-- 在gazebo中显示机器人模型 -->
    <node pkg="gazebo_ros" type="spawn_model" name="car" args="-urdf -model mycar -param robot_description"/>
    <!-- 发布机器人关节和状态节点 -->
    <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"/> 
    <!-- 启动rviz -->
    <node pkg="rviz" type="rviz" name="rviz"/>
</launch>

3.6、在vs code中使用快捷键Crtl+`启用终端,并且回到test01_ws/的路径下,输入source ./devel/setup.bash将当前目录作为工作空间,这样就可以使用roslaunch的指令

#在需求目录下输入指令,将该目录作为工作空间
source ./devel/setup.bash

       在工作空间输入该指令后,就可以使用指令roslaunch urdf01_multi demo01_car_base.launch启动我们的小车了,使用roslaunch指令后,程序就会自动启动gazebo和rviz的仿真环境

        在Gazebo仿真环境下,可以看到我们创建的小车底盘和一个基坐标系

        我们第一次启动rviz环境时,会发现有报错的存在,而且rviz中也没有出现小车模型,这是因为我们打开的是一个空白的rviz仿真环境,需要我们自己加入小车模型并且保存rviz的配置,这样也可以方便下次使用rviz插件。

        此时,我们需要将Fixed Frame(默认值为map)改成我们刚才命名的小车底盘中心(博主这里命名的是base_footprint),然后点击右下角的Add,添加RobotModel,这样就可以正确显示小车底盘了(当然也可以再添加一个TF,用于观察小车每个节点之间的坐标系变换)。

3.7、在rviz仿真界面使用快捷键Crtl+Shift+S保存我们的rviz配置,将该文件命名为XXX.rviz,并且将该配置文件保存到我们之前创建的config目录(在2.8节创建的config文件)下面

3.8、保存好了之后,回到vs code里的终端,在终端使用快捷键Crtl+C就可以停止程序的运行

3.9、随后我们再对launch文件中的启动rviz处代码进行修改,在原有代码的基础上加入新代码args="-d $(find urdf01_multi)/config/mycar.rviz",这新添加的代码目的是将我们刚刚在config下保存的rviz配置文件集成进启动rviz的环节,我们下次运行launch文件后,rviz中就会复现我们上次保存过的配置了(即再次打开修改后的launch文件,可以在rviz仿真环境下看到小车,无需手动添加小车模型)。

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

附加修改之后的launch文件代码如下:

<launch>
    <!-- 将xacro小车文件加载到参数服务器 -->
    <param name="robot_description" command ="$(find xacro)/xacro $(find urdf01_multi)/urdf/car.urdf.xacro"/>
    <!-- 启动gazebo -->
    <include file="$(find gazebo_ros)/launch/empty_world.launch"/>
    <!-- 在gazebo中显示机器人模型 -->
    <node pkg="gazebo_ros" type="spawn_model" name="car" args="-urdf -model mycar -param robot_description"/>
    <!-- 发布机器人关节和状态节点 -->
    <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"/> 
    <!-- 启动rviz -->
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdf01_multi)/config/mycar.rviz"/>
</launch>

4、添加小车的驱动轮和万向轮

4.1、添加驱动轮(小车左右轮子)代码如下,需注意的是,这部分代码需要包含在<robot>...</robot>代码块之中。

    <!-- 驱动轮属性封装 -->
    <!-- 驱动轮半径 -->
    <xacro:property name="wheel_radius" value="0.0325"/>
    <!-- 驱动轮宽度 -->
    <xacro:property name="wheel_length" value="0.015"/>
    <!-- 驱动轮质量 -->
    <xacro:property name="wheel_mass" value="0.05"/>

    <!-- 驱动轮宏代码实现 -->
    <xacro:macro name="driving_wheels" params="name flag">
        <!-- 小车驱动轮连杆代码 -->
        <link name="base_${name}">
            <visual>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_length}"/>
                </geometry>
                <origin xyz="0 0 0" rpy="${PI/2} 0 0"/>
                <material name="black"/>
            </visual>
            <collision>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_length}"/>
                </geometry>
                <origin xyz="0 0 0" rpy="${PI/2} 0 0"/>
            </collision>
            <xacro:cylinder_inertial_matrix m="${wheel_mass}" r="${wheel_radius}" h="${wheel_length}"/>
        </link>
        <gazebo reference="base_${name}">
            <material>Gazebo/Red</material>
        </gazebo>

        <!-- 驱动轮和底盘代码连杆实现 -->
        <joint name="${name}" type="continuous">
            <parent link="base_link"/>
            <child link="base_${name}"/>
            <origin xyz="0 ${flag * base_link_radius} ${-(map_space + base_link_length / 2 - wheel_radius)}"/>
            <axis xyz="0 1 0"/>
        </joint>
    </xacro:macro>
    <xacro:driving_wheels name="left_wheel" flag="1"/>
    <xacro:driving_wheels name="right_wheel" flag="-1"/>

重复步骤3.6,可以看到在rviz环境中拥有两个轮子的小车模型:

4.2、按照同样的方法,添加小车万向轮的代码如下:

    <!-- 支撑轮宏属性封装 -->
    <!-- 支撑轮半径 -->
    <xacro:property name="support_wheel_radius" value="0.0075"/>
    <!-- 支撑轮质量 -->
    <xacro:property name="support_wheel_mass" value="0.01"/>

    <!-- 支撑轮宏 -->
    <xacro:macro name="support_wheel" params="name flag">
        <link name="${name}">
            <visual>
                <geometry>
                    <sphere radius="${support_wheel_radius}"/>
                </geometry>
                <origin xyz="0 0 0" rpy="0 0 0"/>
                <material name="black"/>
            </visual>
            <collision>
                <geometry>
                    <sphere radius="${support_wheel_radius}"/>
                </geometry>
                <origin xyz="0 0 0" rpy="0 0 0"/>
            </collision>
            <xacro:sphere_inertial_matrix m="${support_wheel_mass}" r="${support_wheel_radius}"/>
        </link>
        <gazebo reference="${name}">
            <material>Gazebo/Red</material>
        </gazebo>

        <!-- 支撑轮与底盘的关节连接实现 -->
        <joint name="${name}_to_base_link" type="continuous">
            <parent link="base_link"/>
            <child link="${name}"/>
            <origin xyz="${flag * (base_link_radius - support_wheel_radius)} 0 ${-(base_link_length / 2 + map_space / 2)}" />
            <axis xyz="1 1 1"/>
        </joint>
    </xacro:macro>
    <xacro:support_wheel name="front_wheel" flag="1"/>
    <xacro:support_wheel name="back_wheel" flag="-1"/>

重复步骤3.6,在rviz中添加tf插件,可以观察到小车万向轮tf坐标如下:

4.3、到此为止,单个小车的xacro配置文件已经编写完毕,代码大体如下:

<!-- 根标签,必须声明 xmlns:xacro -->
<robot name="my_base" xmlns:xacro="http://www.ros.org/wiki/xacro">
    <!-- 封装变量、常量 -->
    <xacro:property name="PI" value="3.141"/>
    <!-- 封装宏属性——黑色和黄色 -->
    <material name="black">
        <color rgba="0.0 0.0 0.0 1.0"/>
    </material>
    <material name="yellow">
        <color rgba="0.5 0.3 0.0 0.5"/>
    </material>
    <!-- 底盘属性 -->
    <!-- 小车底盘中心点半径 -->
    <xacro:property name="base_footprint_radius" value="0.001"/>
     <!--小车底盘半径  -->
    <xacro:property name="base_link_radius" value="0.1"/>
    <!-- 小车底盘高度 -->
    <xacro:property name="base_link_length" value="0.08"/>
    <!-- 小车底盘质量 -->
    <xacro:property name="base_mass" value="2"/>
    <!-- 小车底盘离地高度 -->
    <xacro:property name="map_space" value="0.015"/>

    <!-- 小车底盘中心点 -->
    <link name="base_footprint">
        <visual>
            <geometry>
                <sphere radius="${base_footprint_radius}"/>
            </geometry>
        </visual>
    </link>

    <!-- 小车底盘连杆代码 -->
    <link name="base_link">
        <visual>
            <geometry>
                <cylinder radius="${base_link_radius}" length="${base_link_length}"/>
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0"/>
            <material name="yellow"/>
        </visual>
        <collision>
            <geometry>
                <cylinder radius="${base_link_radius}" length="${base_link_length}"/>
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0"/>       
        </collision>
        <xacro:cylinder_inertial_matrix m="${base_mass}" r="${base_link_radius}" h="${base_link_length}"/>
    </link>
    <gazebo reference="base_link">
        <material>Gazebo/Yellow</material>
    </gazebo>

    <!-- 小车底盘和底盘中心的关节连接 -->
    <joint name="base_link_to_base_footprint" type="fixed">
        <parent link="base_footprint"/>
        <child link="base_link"/>
        <!-- 关节的重心应该位于小车离地间距+一半的小车底盘高度 -->
        <origin xyz="0 0 ${map_space + base_link_length / 2}"/>
    </joint>

    <!-- 驱动轮属性封装 -->
    <!-- 驱动轮半径 -->
    <xacro:property name="wheel_radius" value="0.0325"/>
    <!-- 驱动轮宽度 -->
    <xacro:property name="wheel_length" value="0.015"/>
    <!-- 驱动轮质量 -->
    <xacro:property name="wheel_mass" value="0.05"/>

    <!-- 驱动轮宏代码实现 -->
    <xacro:macro name="driving_wheels" params="name flag">
        <!-- 小车驱动轮连杆代码 -->
        <link name="base_${name}">
            <visual>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_length}"/>
                </geometry>
                <origin xyz="0 0 0" rpy="${PI/2} 0 0"/>
                <material name="black"/>
            </visual>
            <collision>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_length}"/>
                </geometry>
                <origin xyz="0 0 0" rpy="${PI/2} 0 0"/>
            </collision>
            <xacro:cylinder_inertial_matrix m="${wheel_mass}" r="${wheel_radius}" h="${wheel_length}"/>
        </link>
        <gazebo reference="base_${name}">
            <material>Gazebo/Red</material>
        </gazebo>

        <!-- 驱动轮和底盘代码连杆实现 -->
        <joint name="${name}" type="continuous">
            <parent link="base_link"/>
            <child link="base_${name}"/>
            <origin xyz="0 ${flag * base_link_radius} ${-(map_space + base_link_length / 2 - wheel_radius)}"/>
            <axis xyz="0 1 0"/>
        </joint>
    </xacro:macro>
    <xacro:driving_wheels name="left_wheel" flag="1"/>
    <xacro:driving_wheels name="right_wheel" flag="-1"/>

    <!-- 支撑轮宏属性封装 -->
    <!-- 支撑轮半径 -->
    <xacro:property name="support_wheel_radius" value="0.0075"/>
    <!-- 支撑轮质量 -->
    <xacro:property name="support_wheel_mass" value="0.01"/>

    <!-- 支撑轮宏 -->
    <xacro:macro name="support_wheel" params="name flag">
        <link name="${name}">
            <visual>
                <geometry>
                    <sphere radius="${support_wheel_radius}"/>
                </geometry>
                <origin xyz="0 0 0" rpy="0 0 0"/>
                <material name="black"/>
            </visual>
            <collision>
                <geometry>
                    <sphere radius="${support_wheel_radius}"/>
                </geometry>
                <origin xyz="0 0 0" rpy="0 0 0"/>
            </collision>
            <xacro:sphere_inertial_matrix m="${support_wheel_mass}" r="${support_wheel_radius}"/>
        </link>
        <gazebo reference="${name}">
            <material>Gazebo/Red</material>
        </gazebo>

        <!-- 支撑轮与底盘的关节连接实现 -->
        <joint name="${name}_to_base_link" type="continuous">
            <parent link="base_link"/>
            <child link="${name}"/>
            <origin xyz="${flag * (base_link_radius - support_wheel_radius)} 0 ${-(base_link_length / 2 + map_space / 2)}" />
            <axis xyz="1 1 1"/>
        </joint>
    </xacro:macro>
    <xacro:support_wheel name="front_wheel" flag="1"/>
    <xacro:support_wheel name="back_wheel" flag="-1"/>
</robot>

5、添加小车控制运动的文件

5.1、在urdf文件夹下的子文件夹gazebo中创建一个名为move.xacro的文件

5.2、随后在该文件下输入控制小车运动的代码如下:

<robot name="my_car_move" xmlns:xacro="http://wiki.ros.org/xacro">

    <!-- 传动实现:用于连接控制器与关节 -->
    <xacro:macro name="joint_trans" params="joint_name">
        <!-- Transmission is important to link the joints and the controller -->
        <transmission name="${joint_name}_trans">
            <type>transmission_interface/SimpleTransmission</type>
            <joint name="${joint_name}">
                <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
            </joint>
            <actuator name="${joint_name}_motor">
                <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
                <mechanicalReduction>1</mechanicalReduction>
            </actuator>
        </transmission>
    </xacro:macro>

    <!-- 每一个驱动轮都需要配置传动装置 -->
    <xacro:joint_trans joint_name="left_wheel" />
    <xacro:joint_trans joint_name="right_wheel" />

    <!-- 控制器 -->
    <gazebo>
        <plugin name="differential_drive_controller" filename="libgazebo_ros_diff_drive.so">
            <rosDebugLevel>Debug</rosDebugLevel>
            <publishWheelTF>false</publishWheelTF>
            <robotNamespace>/</robotNamespace>
            <publishTf>1</publishTf>
            <publishWheelJointState>false</publishWheelJointState>
            <alwaysOn>true</alwaysOn>
            <updateRate>100</updateRate>
            <legacyMode>true</legacyMode>
            <leftJoint>left_wheel</leftJoint> <!-- 左轮 -->
            <rightJoint>right_wheel</rightJoint> <!-- 右轮 -->
            <wheelSeparation>${base_link_radius * 2}</wheelSeparation> <!-- 车轮间距 -->
            <wheelDiameter>${wheel_radius * 2}</wheelDiameter> <!-- 车轮直径 -->
            <broadcastTF>1</broadcastTF>
            <wheelTorque>30</wheelTorque>
            <wheelAcceleration>1.8</wheelAcceleration>
            <commandTopic>cmd_vel</commandTopic> <!-- 运动控制话题 -->
            <odometryFrame>odom</odometryFrame> 
            <odometryTopic>odom</odometryTopic> <!-- 里程计话题 -->
            <robotBaseFrame>base_footprint</robotBaseFrame> <!-- 根坐标系 -->
        </plugin>
    </gazebo>

</robot>

5.3、回到集成了demo01_car_base.urdf.xacrohead.xacro代码的car.urdf.xacro文件中,再集成一个控制小车运动的move.xacro文件。

    <!-- 包含控制小车的xacro文件 -->
    <xacro:include filename="gazebo/move.xacro"/>

5.4、重复步骤3.6,打开rviz仿真环境,将rviz之前保存的配置进行修,这里为了让小车进行运动,需要将odom坐标作为基坐标系,即将Fixed Frame(默认值为map)改成odom

使用快捷键Ctrl+Alt+T打开终端,输入rostopic list可以查看小车这时候发布的话题,如果能找到cmd_vel(博主这个话题在这里的第二行)这个话题说明我们可以控制小车的运动了,这时候介绍一个简单控制小车的办法,输入代码 rosrun teleop_twist_keyboard teleop_twist_keyboard.py后,我们就可以通过使用键盘控制小车运动

#在终端显示小车当前发布的话题
rostopic list
#使用键盘控制小车
rosrun teleop_twist_keyboard teleop_twist_keyboard.py 

5.5、

6、增加多个小车

6.1、类似步骤3.1的操作,我们需要在launch文件夹下面创建一个新的文件名为demo02_multi_car.launch,随后将之前的launch文件代码复制粘贴一份,我们需要在原来的代码上进行修改;同理,在urdf文件夹下创建一个新的文件夹名为demo02_multi_car.urdf.xacro,复制粘贴一份之前demo01_car_base.urdf.xacro的代码并进行修改;在gazebo文件夹下面创建multi_move.xacro文件,复制粘贴一份之前move.xacro的代码并进行修改。

6.2、创建多个小车最重要的部分在于给每个小车划分独立的命名空间,在这里我们使用<group ns>...</group>这种强命名(直接在小车的关节、连杆前面加上命名空间/robot1、/robot2)的方式。demo02_multi_car.launch修改后的代码如下:

<launch>
    <!-- 启动gazebo -->
    <include file="$(find gazebo_ros)/launch/empty_world.launch"/>
    <group ns="car1">
        <!-- 将xacro小车文件加载到参数服务器 -->
        <param name="robot_description" command ="$(find xacro)/xacro $(find urdf01_multi)/urdf/car.urdf.xacro ns:=car1"/>
        <!-- 在gazebo中显示机器人模型 -->
        <node pkg="gazebo_ros" type="spawn_model" name="car1" args="-urdf -model car1 -param robot_description -x 0.5"/>
        <!-- 发布机器人关节和状态节点 -->
        <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"/> 
        <!-- 发布一个map节点,同时将map节点与小车的odom节点通过静态变换联系起来,这是小车能在rviz中显示的关键代码 -->
        <node pkg="tf2_ros" type="static_transform_publisher" name="static_transform_publisher" args="0 0 0 0 0 0 /map /car1_odom"/>
    </group>

    <group ns="car2">
        <!-- 将xacro小车文件加载到参数服务器 -->
        <param name="robot_description" command ="$(find xacro)/xacro $(find urdf01_multi)/urdf/car.urdf.xacro ns:=car2"/>
        <!-- 在gazebo中显示机器人模型 -->
        <node pkg="gazebo_ros" type="spawn_model" name="car2" args="-urdf -model car2 -param robot_description -x 1.5"/>
        <!-- 发布机器人关节和状态节点 -->
        <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"/> 
        <!-- 发布一个map节点,同时将map节点与小车的odom节点通过静态变换联系起来,这是小车能在rviz中显示的关键代码 -->
        <node pkg="tf2_ros" type="static_transform_publisher" name="static_transform_publisher" args="0 0 0 0 0 0 /map /car2_odom"/>
    </group>
    
    <!-- 启动rviz -->
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdf01_multi)/config/mycar.rviz"/>
</launch>

6.3、将demo02_multi_car.urdf.xacro从单个小车的配置代码修改如下:

<!-- 根标签,必须声明 xmlns:xacro -->
<robot name="my_base" xmlns:xacro="http://www.ros.org/wiki/xacro">
    <!-- 封装多个机器人属性 -->
    <xacro:property name="ns" value="$(arg ns)"/>
    <!-- 封装变量、常量 -->
    <xacro:property name="PI" value="3.141"/>
    <!-- 封装宏属性——黑色和黄色 -->
    <material name="black">
        <color rgba="0.0 0.0 0.0 1.0"/>
    </material>
    <material name="yellow">
        <color rgba="0.5 0.3 0.0 0.5"/>
    </material>
    <!-- 底盘属性 -->
    <!-- 小车底盘中心点半径 -->
    <xacro:property name="base_footprint_radius" value="0.001"/>
     <!--小车底盘半径  -->
    <xacro:property name="base_link_radius" value="0.1"/>
    <!-- 小车底盘高度 -->
    <xacro:property name="base_link_length" value="0.08"/>
    <!-- 小车底盘质量 -->
    <xacro:property name="base_mass" value="2"/>
    <!-- 小车底盘离地高度 -->
    <xacro:property name="map_space" value="0.015"/>

    <!-- 小车底盘中心点 -->
    <link name="${ns}_base_footprint">
        <visual>
            <geometry>
                <sphere radius="${base_footprint_radius}"/>
            </geometry>
        </visual>
    </link>

    <!-- 小车底盘连杆代码 -->
    <link name="${ns}_base_link">
        <visual>
            <geometry>
                <cylinder radius="${base_link_radius}" length="${base_link_length}"/>
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0"/>
            <material name="yellow"/>
        </visual>
        <collision>
            <geometry>
                <cylinder radius="${base_link_radius}" length="${base_link_length}"/>
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0"/>       
        </collision>
        <xacro:cylinder_inertial_matrix m="${base_mass}" r="${base_link_radius}" h="${base_link_length}"/>
    </link>
    <gazebo reference="${ns}_base_link">
        <material>Gazebo/Yellow</material>
    </gazebo>

    <!-- 小车底盘和底盘中心的关节连接 -->
    <joint name="${ns}_base_link_to_base_footprint" type="fixed">
        <parent link="${ns}_base_footprint"/>
        <child link="${ns}_base_link"/>
        <!-- 关节的重心应该位于小车离地间距+一半的小车底盘高度 -->
        <origin xyz="0 0 ${map_space + base_link_length / 2}"/>
    </joint>

    <!-- 驱动轮属性封装 -->
    <!-- 驱动轮半径 -->
    <xacro:property name="wheel_radius" value="0.0325"/>
    <!-- 驱动轮宽度 -->
    <xacro:property name="wheel_length" value="0.015"/>
    <!-- 驱动轮质量 -->
    <xacro:property name="wheel_mass" value="0.05"/>

    <!-- 驱动轮宏代码实现 -->
    <xacro:macro name="driving_wheels" params="name flag">
        <!-- 小车驱动轮连杆代码 -->
        <link name="base_${name}">
            <visual>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_length}"/>
                </geometry>
                <origin xyz="0 0 0" rpy="${PI/2} 0 0"/>
                <material name="black"/>
            </visual>
            <collision>
                <geometry>
                    <cylinder radius="${wheel_radius}" length="${wheel_length}"/>
                </geometry>
                <origin xyz="0 0 0" rpy="${PI/2} 0 0"/>
            </collision>
            <xacro:cylinder_inertial_matrix m="${wheel_mass}" r="${wheel_radius}" h="${wheel_length}"/>
        </link>
        <gazebo reference="base_${name}">
            <material>Gazebo/Red</material>
        </gazebo>

        <!-- 驱动轮和底盘代码连杆实现 -->
        <joint name="${name}" type="continuous">
            <parent link="${ns}_base_link"/>
            <child link="base_${name}"/>
            <origin xyz="0 ${flag * base_link_radius} ${-(map_space + base_link_length / 2 - wheel_radius)}"/>
            <axis xyz="0 1 0"/>
        </joint>
    </xacro:macro>
    <xacro:driving_wheels name="${ns}_left_wheel" flag="1"/>
    <xacro:driving_wheels name="${ns}_right_wheel" flag="-1"/>

    <!-- 支撑轮宏属性封装 -->
    <!-- 支撑轮半径 -->
    <xacro:property name="support_wheel_radius" value="0.0075"/>
    <!-- 支撑轮质量 -->
    <xacro:property name="support_wheel_mass" value="0.01"/>

    <!-- 支撑轮宏 -->
    <xacro:macro name="support_wheel" params="name flag">
        <link name="${name}">
            <visual>
                <geometry>
                    <sphere radius="${support_wheel_radius}"/>
                </geometry>
                <origin xyz="0 0 0" rpy="0 0 0"/>
                <material name="black"/>
            </visual>
            <collision>
                <geometry>
                    <sphere radius="${support_wheel_radius}"/>
                </geometry>
                <origin xyz="0 0 0" rpy="0 0 0"/>
            </collision>
            <xacro:sphere_inertial_matrix m="${support_wheel_mass}" r="${support_wheel_radius}"/>
        </link>
        <gazebo reference="${name}">
            <material>Gazebo/Red</material>
        </gazebo>

        <!-- 支撑轮与底盘的关节连接实现 -->
        <joint name="${name}_to_base_link" type="continuous">
            <parent link="${ns}_base_link"/>
            <child link="${name}"/>
            <origin xyz="${flag * (base_link_radius - support_wheel_radius)} 0 ${-(base_link_length / 2 + map_space / 2)}" />
            <axis xyz="1 1 1"/>
        </joint>
    </xacro:macro>
    <xacro:support_wheel name="${ns}_front_wheel" flag="1"/>
    <xacro:support_wheel name="${ns}_back_wheel" flag="-1"/>
</robot>

6.4、因为我们小车的配置文件名变成了demo02_multi_car.urdf.xacro,那么对应的我们也需要修改multi_car.xacro中的文件名,具体修改如下:

<robot name="my_laser" xmlns:xacro="http://wiki.ros.org/xacro">
    <!-- 包含惯性矩阵 -->
    <xacro:include filename="head.xacro"/>
    <!-- 包含多个小车配置的xacro文件 -->
    <xacro:include filename="demo02_multi.urdf.xacro"/>
    <!-- 包含控制多个小车的xacro文件 -->
    <xacro:include filename="gazebo/move.xacro"/>
</robot>

6.5、这是我们在终端中启动demo02_multi_car.launch文件,可以发现在gazebo仿真环境中可以正常启动小车,但是rviz中无法显示小车,这是因为我们还没有修改multi_move.xacro文件,缺少了两个小车odom坐标的发布。

6.6、接下来对multi_car.xacro的文件进行修改,修改后的代码如下:

<robot name="my_car_move" xmlns:xacro="http://wiki.ros.org/xacro">
    <!-- 封装多个机器人宏属性 -->
    <xacro:property name="ns" value="$(arg ns)"/>
    <!-- 传动实现:用于连接控制器与关节 -->
    <xacro:macro name="joint_trans" params="joint_name">
        <!-- Transmission is important to link the joints and the controller -->
        <transmission name="${joint_name}_trans">
            <type>transmission_interface/SimpleTransmission</type>
            <joint name="${joint_name}">
                <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
            </joint>
            <actuator name="${joint_name}_motor">
                <hardwareInterface>hardware_interface/VelocityJointInterface</hardwareInterface>
                <mechanicalReduction>1</mechanicalReduction>
            </actuator>
        </transmission>
    </xacro:macro>

    <!-- 每一个驱动轮都需要配置传动装置 -->
    <xacro:joint_trans joint_name="${ns}_left_wheel" />
    <xacro:joint_trans joint_name="${ns}_right_wheel" />

    <!-- 控制器 -->
    <gazebo>
        <plugin name="differential_drive_controller" filename="libgazebo_ros_diff_drive.so">
            <rosDebugLevel>Debug</rosDebugLevel>
            <publishWheelTF>false</publishWheelTF>
            <robotNamespace>${ns}</robotNamespace>
            <publishTf>1</publishTf>
            <publishWheelJointState>false</publishWheelJointState>
            <alwaysOn>true</alwaysOn>
            <updateRate>100</updateRate>
            <legacyMode>true</legacyMode>
            <leftJoint>${ns}_left_wheel</leftJoint> <!-- 左轮 -->
            <rightJoint>${ns}_right_wheel</rightJoint> <!-- 右轮 -->
            <wheelSeparation>${base_link_radius * 2}</wheelSeparation> <!-- 车轮间距 -->
            <wheelDiameter>${wheel_radius * 2}</wheelDiameter> <!-- 车轮直径 -->
            <broadcastTF>1</broadcastTF>
            <wheelTorque>30</wheelTorque>
            <wheelAcceleration>1.8</wheelAcceleration>
            <commandTopic>cmd_vel</commandTopic> <!-- 运动控制话题 -->
            <odometryFrame>${ns}_odom</odometryFrame> 
            <odometryTopic>odom</odometryTopic> <!-- 里程计话题 -->
            <robotBaseFrame>${ns}_base_footprint</robotBaseFrame> <!-- 根坐标系 -->
        </plugin>
    </gazebo>

</robot>

6.7、启动demo02_multi_car.launch文件,这时候的rviz界面如下:

那么想要正常显示两个小车,我们需要将Fixed Frame修改成mapAdd两个RobotModel,并且将RobotModel的Robot Description选项改成我们的小车名字,我这儿是/car1/robot_description(如果不进行修改,默认是robot_description,无法识别到小车的模型,从而无法现实小车并报错)。最后使用快捷键Ctrl++Shift+S保存我们多个小车配置为另一个rviz文件。

那么保存了这个multi.rviz文件后,我们需要重新回到demo02_multi_car.launch文件,将rviz启动项的rviz配置文件改成我们刚刚保存的文件,这样我们每次启动时候就不需要添加小车了,rviz会自动显示小车。

<!-- 修改args参数这一项,将我们的rviz配置文件修改成multi_car.rviz -->
    <node pkg="rviz" type="rviz" name="rviz" args="-d $(find urdf01_multi)/config/multi_car.rviz"/>
</launch>

### Gazebo 差速四轮小车仿真教程 #### 功能包创建 为了在Gazebo中进行差速四轮小车的仿真,首先需要创建一个新的ROS功能包来管理所有的配置文件和脚本。这可以通过一系列命令完成: ```bash cd ~/catkin_ws/src catkin_create_pkg diff_wheeled_robot_control rospy tf geometry_msgs urdf rviz xacro gazebo_ros gazebo_ros_control gazebo_plugins ``` 此过程初始化了一个名为`diff_wheeled_robot_control`的功能包,包含了构建和运行仿真所需的各种依赖项[^4]。 #### 文件结构设置 接下来要建立适当的工作空间目录结构以便于管理和组织项目文件。具体操作如下所示: ```bash mkdir -p ~/fjy_xm/catkin_urdf_gazebo/{src,devel} source /opt/ros/noetic/setup.bash cd ~/fjy_xm/catkin_urdf_gazebo/src catkin_init_workspace cd .. catkin_make source devel/setup.bash ``` 上述指令不仅设置了工作区还编译了代码,并使新创建的环境生效。之后还需进一步细化子模块下的文件夹布局以适应特定需求[^5]。 #### 小车型号描述 (URDF/XACRO) 对于机械臂或其他类型的移动平台来说,精确地定义其物理属性至关重要。通常采用XML格式编写统一机器人描述格式(URDF),有时也会借助XACRO宏简化复杂的几何形状表示方法。下面给出一个简单的示例框架供参考: ```xml <?xml version="1.0"?> <robot name="differential_drive_bot"> <!-- 定义链接 --> <link name="base_link"/> <!-- 描述传感器和其他部件 --> </robot> ``` 该模板可以作为起点逐步扩展成完整的车辆模型,包括但不限于轮轴间距、悬挂系统以及动力传动装置等细节部分。 #### 启动文件配置 最后一步是准备启动(.launch)文件用来一键加载整个场景到Gazebo环境中去。这里提供了一种基本形式: ```xml <launch> <!-- 加载机器人状态发布器节点 --> <!-- 发布关节状态话题 --> <!-- 运行gazebo并传入world参数 --> <!-- 导入机器人的urdf/xacro文件 --> <!-- 配置控制器插件 --> </launch> ``` 以上就是有关如何利用Gazebo开展基于ROS系统的差速四轮小车仿真的概览介绍。实际应用过程中可能还会涉及到更多方面比如路径规划算法测试或是视觉伺服控制实验等等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值