Skip to content

基于 ROS1 多机框架的修改

与 urdf 模型相关的 tf_prefix

tf_prefix从名称意义上表明了该参数是用来修改 tf 坐标系名称前缀的。而 urdf 模型通过 robot_state_publisher 节点发布 /tf 广播,所以 tf_prefix 参数的修改会直接影响 tf 坐标系名称,即它的命名空间。

atlas_run.xacro

xml
<?xml version="1.0"?>
<robot name="atlas" xmlns:xacro="http://www.ros.org/wiki/xacro">
    <xacro:property name="prefix" value="$(arg prefix)" />

    <xacro:if value="${prefix == '/' or prefix == '' or prefix == ' '}">
    <xacro:property name="tf_prefix" value="" />
    </xacro:if>

    <xacro:unless value="${prefix == '/' or prefix == '' or prefix == ' '}">
    <xacro:property name="tf_prefix" value="${prefix}/" />
    </xacro:unless>

    <xacro:include filename="$(find atlas_gazebo)/urdf/atlas.xacro" />

</robot>
<?xml version="1.0"?>
<robot name="atlas" xmlns:xacro="http://www.ros.org/wiki/xacro">
    <xacro:property name="prefix" value="$(arg prefix)" />

    <xacro:if value="${prefix == '/' or prefix == '' or prefix == ' '}">
    <xacro:property name="tf_prefix" value="" />
    </xacro:if>

    <xacro:unless value="${prefix == '/' or prefix == '' or prefix == ' '}">
    <xacro:property name="tf_prefix" value="${prefix}/" />
    </xacro:unless>

    <xacro:include filename="$(find atlas_gazebo)/urdf/atlas.xacro" />

</robot>

atlas.xacro

xml
<?xml version="1.0" encoding="utf-8"?>

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

  <xacro:include filename="$(find atlas_gazebo)/urdf/macros.xacro" />

  <link name="${tf_prefix}base_footprint">
  </link>

  <link name="${tf_prefix}base_link">
    <visual>
      <geometry>
        <!-- <box size="0.28 0.1 0.03"/> -->
        <mesh filename="package://atlas_description/meshes/base_link.STL" />
      </geometry>
      <origin xyz="-0.13 0 0" rpy="0 0 0" />

      <material name="gray">
        <color rgba="0.5 0.5 0.5 1.0" />
      </material>
    </visual>
    <collision>
      <geometry>
        <box size="0.28 0.1 0.03" />
      </geometry>
      <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
    </collision>

  </link>

  <joint name="base_link2base_footprint" type="fixed">
    <parent link="${tf_prefix}base_footprint" />
    <child link="${tf_prefix}base_link" />
    <origin xyz="0 0 0.032" rpy="0 0 0" />
  </joint>
  .........

  <xacro:include filename="$(find atlas_gazebo)/urdf/atlas.gazebo" />
</robot>
<?xml version="1.0" encoding="utf-8"?>

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

  <xacro:include filename="$(find atlas_gazebo)/urdf/macros.xacro" />

  <link name="${tf_prefix}base_footprint">
  </link>

  <link name="${tf_prefix}base_link">
    <visual>
      <geometry>
        <!-- <box size="0.28 0.1 0.03"/> -->
        <mesh filename="package://atlas_description/meshes/base_link.STL" />
      </geometry>
      <origin xyz="-0.13 0 0" rpy="0 0 0" />

      <material name="gray">
        <color rgba="0.5 0.5 0.5 1.0" />
      </material>
    </visual>
    <collision>
      <geometry>
        <box size="0.28 0.1 0.03" />
      </geometry>
      <origin xyz="0.0 0.0 0.0" rpy="0.0 0.0 0.0" />
    </collision>

  </link>

  <joint name="base_link2base_footprint" type="fixed">
    <parent link="${tf_prefix}base_footprint" />
    <child link="${tf_prefix}base_link" />
    <origin xyz="0 0 0.032" rpy="0 0 0" />
  </joint>
  .........

  <xacro:include filename="$(find atlas_gazebo)/urdf/atlas.gazebo" />
</robot>

.gazebo文件中的<gazebo reference="${tf_prefix}base_link">.so插件中的命名空间参数(如<robotNamespace>、 <topicName>、<frameName>),应当与tf_prefix需要一致。

atlas.gazebo

xml
<?xml version="1.0"?>
<robot name="atlas" xmlns:xacro="http://www.ros.org/wiki/xacro">

  <!-- Gazebo references -->

  <gazebo reference="${tf_prefix}base_link">
    <mu1 value="0.0" />
    <mu2 value="0.0" />
    <kp value="10000000.0" />
    <kd value="1.0" />
    <material>Gazebo/DarkGray</material>
  </gazebo>

  .......

  <!-- Gazebo Plugins -->
  <gazebo>
    <plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
      <robotNamespace>/${tf_prefix}</robotNamespace>
      <robotParam>robot_description</robotParam>
      <robotSimType>gazebo_ros_control/DefaultRobotHWSim</robotSimType>
      <legacyModeNS>true</legacyModeNS>
    </plugin>
  </gazebo>

  <!-- hokuyo -->

  <gazebo reference="${tf_prefix}laser">
    <sensor type="ray" name="hokuyo_sensor">
      <pose>0 0 0.0124 0 0 0</pose>
      <visualize>false</visualize>
      <update_rate>40</update_rate>
      <ray>
        <scan>
          <horizontal>
            <samples>1081</samples>
            <resolution>1</resolution>
            <min_angle>-2.3561944902</min_angle>
            <max_angle>2.3561944902</max_angle>
          </horizontal>
        </scan>
        <range>
          <min>0.1</min>
          <max>10.0</max>
          <resolution>0.01</resolution>
        </range>
        <noise>
          <mean>0.0</mean>
          <stddev>0.01</stddev>
        </noise>
      </ray>
      <plugin name="gazebo_ros_hokuyo_controller" filename="libgazebo_ros_laser.so">
        <topicName>/${tf_prefix}scan</topicName>
        <frameName>/${tf_prefix}base_footprint</frameName>
      </plugin>
    </sensor>
  </gazebo>

</robot>
<?xml version="1.0"?>
<robot name="atlas" xmlns:xacro="http://www.ros.org/wiki/xacro">

  <!-- Gazebo references -->

  <gazebo reference="${tf_prefix}base_link">
    <mu1 value="0.0" />
    <mu2 value="0.0" />
    <kp value="10000000.0" />
    <kd value="1.0" />
    <material>Gazebo/DarkGray</material>
  </gazebo>

  .......

  <!-- Gazebo Plugins -->
  <gazebo>
    <plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
      <robotNamespace>/${tf_prefix}</robotNamespace>
      <robotParam>robot_description</robotParam>
      <robotSimType>gazebo_ros_control/DefaultRobotHWSim</robotSimType>
      <legacyModeNS>true</legacyModeNS>
    </plugin>
  </gazebo>

  <!-- hokuyo -->

  <gazebo reference="${tf_prefix}laser">
    <sensor type="ray" name="hokuyo_sensor">
      <pose>0 0 0.0124 0 0 0</pose>
      <visualize>false</visualize>
      <update_rate>40</update_rate>
      <ray>
        <scan>
          <horizontal>
            <samples>1081</samples>
            <resolution>1</resolution>
            <min_angle>-2.3561944902</min_angle>
            <max_angle>2.3561944902</max_angle>
          </horizontal>
        </scan>
        <range>
          <min>0.1</min>
          <max>10.0</max>
          <resolution>0.01</resolution>
        </range>
        <noise>
          <mean>0.0</mean>
          <stddev>0.01</stddev>
        </noise>
      </ray>
      <plugin name="gazebo_ros_hokuyo_controller" filename="libgazebo_ros_laser.so">
        <topicName>/${tf_prefix}scan</topicName>
        <frameName>/${tf_prefix}base_footprint</frameName>
      </plugin>
    </sensor>
  </gazebo>

</robot>

roslaunch 中的 arg 标签

在最上层的 launch 文件中,使用 arg 标签来设置可变参数。这些参数可以在后续的 launch 文件中使用,被调用的子文件中可以不设定初始值。

parent.launch

xml
<?xml version="1.0"?>
<launch>
    <!-- set param of launch file -->
    ..........
    <arg name="world" default="tianracer_racetrack" />
    <arg name="robot_name" default="$(optenv ATLAS_NAME /)" doc="robot name [atlas_No1, atlas_No2, atlas_No3, ...]"/>
    <arg name="default_ns" default="atlas"/>
    ..........
</launch>
<?xml version="1.0"?>
<launch>
    <!-- set param of launch file -->
    ..........
    <arg name="world" default="tianracer_racetrack" />
    <arg name="robot_name" default="$(optenv ATLAS_NAME /)" doc="robot name [atlas_No1, atlas_No2, atlas_No3, ...]"/>
    <arg name="default_ns" default="atlas"/>
    ..........
</launch>

child.launch

xml
<?xml version="1.0"?>
<launch>
    <!-- set param of launch file -->
    ..........
    <arg name="world" />
    <arg name="robot_name" />
    ..........
</launch>
<?xml version="1.0"?>
<launch>
    <!-- set param of launch file -->
    ..........
    <arg name="world" />
    <arg name="robot_name" />
    ..........
</launch>

map_server 修改地图发布坐标

根据 map_server 修改地图发布坐标,修改为 map 即可,通过添加 <param name="frame_id" value="map" /> 实现。 如果要给 /map 话题添加命名空间,则可以通过ns="$(arg namespace)"实现。

xml
<group if="$(eval arg('robot_name') == '/')">
    <node name="map_server" pkg="map_server" type="map_server" ns="$(arg namespace)" args="$(find atlas_gazebo)/maps/$(arg world).yaml" >
        <param name="frame_id" value="map" />
    </node>
</group>
<group if="$(eval arg('robot_name') == '/')">
    <node name="map_server" pkg="map_server" type="map_server" ns="$(arg namespace)" args="$(find atlas_gazebo)/maps/$(arg world).yaml" >
        <param name="frame_id" value="map" />
    </node>
</group>

基于 group 的条件判断

基于 eval 表达式将 <group if="$(eval arg('robot_name') == '/')"> 改为 <group unless="$(eval arg('robot_name') == '/')"> 即可实现类似 python 代码中的 if else 的判断语句效果。

xml
<launch>
    <!-- Config map file -->
    <arg name="world" default="atlas_racetrack" />
    <arg name="robot_name" default="$(optenv ATLAS_NAME /)" doc="robot name [atlas_No1, atlas_No2, atlas_No3, ...]"/>
    <arg name="namespace" default="atlas"/>

    <group if="$(eval arg('robot_name') == '/')">

        <!-- Map server, load map-->
        <node name="map_server" pkg="map_server" type="map_server" ns="$(arg namespace)" args="$(find atlas_gazebo)/maps/$(arg world).yaml" >
            <param name="frame_id" value="map" />
        </node>

        <!-- launch gazebo simulation environment -->
        <include file="$(find atlas_gazebo)/launch/atlas_on_racetrack.launch" >
            <arg name="world" value="$(arg world)" />
            <arg name="robot_name" value="$(arg namespace)" />
        </include>

        <!-- launch atlas control -->
        <include file="$(find atlas_gazebo)/launch/atlas_control.launch" >
            <arg name="robot_name" value="$(arg namespace)" />
        </include>

        <!-- move base -->
        <include file="$(find atlas_gazebo)/launch/includes/teb_base.launch.xml" >
            <arg name="robot_name" value="$(arg namespace)" />
        </include>

        <!-- AMCL -->
        <include file="$(find atlas_gazebo)/launch/includes/amcl.launch.xml" >
            <arg name="robot_name" value="$(arg namespace)" />
        </include>

        <node pkg="rviz" type="rviz" name="rviz" args="-d $(find atlas_gazebo)/rviz/nav_$(arg namespace).rviz"/>
    </group>

    <group unless="$(eval arg('robot_name') == '/')">

        <!-- Map server, load map-->
        <node name="map_server" pkg="map_server" type="map_server" ns="$(arg robot_name)" args="$(find atlas_gazebo)/maps/$(arg world).yaml" >
            <param name="frame_id" value="map" />
        </node>

        <!-- launch gazebo simulation environment -->
        <include file="$(find atlas_gazebo)/launch/atlas_on_racetrack.launch">
            <arg name="world" value="$(arg world)" />
            <arg name="robot_name" value="$(arg robot_name)" />
        </include>

        <!-- launch atlas control -->
        <include file="$(find atlas_gazebo)/launch/atlas_control.launch" >
            <arg name="robot_name" value="$(arg robot_name)" />
        </include>

        <!-- move base -->
        <include file="$(find atlas_gazebo)/launch/includes/teb_base.launch.xml" >
            <arg name="robot_name" value="$(arg robot_name)" />
        </include>

        <!-- AMCL -->
        <include file="$(find atlas_gazebo)/launch/includes/amcl.launch.xml" >
            <arg name="robot_name" value="$(arg robot_name)" />
        </include>

        <node pkg="rviz" type="rviz" name="rviz" args="-d $(find atlas_gazebo)/rviz/nav_$(arg robot_name).rviz"/>
    </group>

</launch>
<launch>
    <!-- Config map file -->
    <arg name="world" default="atlas_racetrack" />
    <arg name="robot_name" default="$(optenv ATLAS_NAME /)" doc="robot name [atlas_No1, atlas_No2, atlas_No3, ...]"/>
    <arg name="namespace" default="atlas"/>

    <group if="$(eval arg('robot_name') == '/')">

        <!-- Map server, load map-->
        <node name="map_server" pkg="map_server" type="map_server" ns="$(arg namespace)" args="$(find atlas_gazebo)/maps/$(arg world).yaml" >
            <param name="frame_id" value="map" />
        </node>

        <!-- launch gazebo simulation environment -->
        <include file="$(find atlas_gazebo)/launch/atlas_on_racetrack.launch" >
            <arg name="world" value="$(arg world)" />
            <arg name="robot_name" value="$(arg namespace)" />
        </include>

        <!-- launch atlas control -->
        <include file="$(find atlas_gazebo)/launch/atlas_control.launch" >
            <arg name="robot_name" value="$(arg namespace)" />
        </include>

        <!-- move base -->
        <include file="$(find atlas_gazebo)/launch/includes/teb_base.launch.xml" >
            <arg name="robot_name" value="$(arg namespace)" />
        </include>

        <!-- AMCL -->
        <include file="$(find atlas_gazebo)/launch/includes/amcl.launch.xml" >
            <arg name="robot_name" value="$(arg namespace)" />
        </include>

        <node pkg="rviz" type="rviz" name="rviz" args="-d $(find atlas_gazebo)/rviz/nav_$(arg namespace).rviz"/>
    </group>

    <group unless="$(eval arg('robot_name') == '/')">

        <!-- Map server, load map-->
        <node name="map_server" pkg="map_server" type="map_server" ns="$(arg robot_name)" args="$(find atlas_gazebo)/maps/$(arg world).yaml" >
            <param name="frame_id" value="map" />
        </node>

        <!-- launch gazebo simulation environment -->
        <include file="$(find atlas_gazebo)/launch/atlas_on_racetrack.launch">
            <arg name="world" value="$(arg world)" />
            <arg name="robot_name" value="$(arg robot_name)" />
        </include>

        <!-- launch atlas control -->
        <include file="$(find atlas_gazebo)/launch/atlas_control.launch" >
            <arg name="robot_name" value="$(arg robot_name)" />
        </include>

        <!-- move base -->
        <include file="$(find atlas_gazebo)/launch/includes/teb_base.launch.xml" >
            <arg name="robot_name" value="$(arg robot_name)" />
        </include>

        <!-- AMCL -->
        <include file="$(find atlas_gazebo)/launch/includes/amcl.launch.xml" >
            <arg name="robot_name" value="$(arg robot_name)" />
        </include>

        <node pkg="rviz" type="rviz" name="rviz" args="-d $(find atlas_gazebo)/rviz/nav_$(arg robot_name).rviz"/>
    </group>

</launch>