이타인클럽

Gazebo에 kobuki 여러 대 로드하기

Gazebo에 Kobuki 4대를 올라간다
토픽 이타인클럽 > ROS

토픽 결과물: Gazebo에 Kobuki가 4대 나타나게 됩니다.

 

이번 토픽은 아래 그림과 같이 Gazebo에 kobuki를 여러 대 올리는 방법을 설명합니다. 뭔가 멀티로 할 때 유용하겠죠? 요즘 유행하는 Deep Reinforcement Learning에도 유용하게 사용됩니다.

이전 토픽의 kobuki_hokuyo 패키지에 추가하여 작업 합니다. 이번 토픽에서는 소스 파일을 생성하지 않고 urdf 파일과 launch 파일만을 이용하려고 합니다.

kobuki 색깔 추가

kobuki_description 패키지가 없다면 설치합니다.

sudo apt-get install ros-kinetic-kobuki-description

색깔별 mesh 파일 생성

kobuki_description 패키지의 meshes 디렉터리 밑에 main_body.dae라는 파일이 있습니다. 이 파일을 색깔별로 복사하여 생성합니다. 여기서는 검정, 파랑, 초록, 하양 4가지 파일을 만듭니다. 파일 이름은 main_body_black.dae, main_body_blue.dae, main_body_green.dae, main_body_white.dae로 하기로 합니다. main_body_black.dae 파일을 에디터로 열어보면 아래와 같은 코드를 찾아갑니다.

<technique sid="common">
          <blinn>
            <emission>
     	      <!-- change color here -->
              <color>0 0 0 1</color>
            </emission>
            ...

위 코드에 주석을 달아놓았는데 주석 밑의 태그에 값을 변경하면 main_body의 색깔이 변경됩니다. 태그의 값은 R G B Alpha 값으로 <color>0 0 0 1</color>은 경우 검정색을 나타내고 있습니다. 이것을 파랑으로 하려면 <color>0 0 1 1</color>로 바꿔주면 됩니다. 나머지 파일들도 색깔에 맞게 바꿔서 저장합니다.

색깔별 urdf 파일 생성

이전 토픽의 kobuki.urdf.xacro 파일을 색깔별로 복사하여 생성합니다. 즉, kobuki_black.urdf.xacro, kobuki_blue.urdf.xacro, kobuki_green.urdf.xacro, kobuki_white.urdf.xacro와 같이 생성합니다. kobuki_black.urdf.xacro 파일을 열어서 먼저 아래와 같이 패키지가 설정되어 있는지 확인합니다.

<robot name="kobuki" xmlns:xacro="http://ros.org/wiki/xacro">
  <xacro:include filename="$(find kobuki_hokuyo)/urdf/common_properties.urdf.xacro"/>
  <xacro:include filename="$(find kobuki_hokuyo)/urdf/kobuki_gazebo.urdf.xacro"/>

만약 find 패키지 부분이 위와 같지 않다면 위와 같이 변경시켜준니다. 그 다음 파일에서 아래와 같은 부분을 찾습니다.

<link name="base_link">
      <visual>
        <geometry>
          <!-- new mesh -->
          <mesh filename="package://kobuki_hokuyo/urdf/meshes/main_body_black.dae" />
        </geometry>

위 파일에서 라고 주석을 달아놓은 곳이 변경할 곳입니다. 앞에서 생성한 mesh 파일을 이곳에 적어줍니다. 위의 경우는 검정색이므로 mesh 파일이 main_body_black.dae입니다. 나머지 urdf.xacro 파일들도 색깔별로 맞는 mesh 파일 이름으로 바꿔줍니다.

그 다음으로는 hokuyo 센서가 추가된 kobuki_hokuyo.urdf.xacro 파일도 색깔별로 복사하여 생성합니다. 파일 이름은 kobuki_hokuyo_black.urdf.xacro, kobuki_hokuyo_blue.urdf.xacro, kobuki_hokuyo_green.urdf.xacro, kobuki_hokuyo_white.urdf.xacro로 합니다. kobuki_hokoyo_black.urdf.xacro파일을 열면 아래와 같습니다.

<?xml version="1.0"?>
<robot name="kobuki_hokuyo"
       xmlns:sensor="http://playerstage.sourceforge.net/gazebo/xmlschema/#sensor"
       xmlns:controller="http://playerstage.sourceforge.net/gazebo/xmlschema/#controller"
       xmlns:interface="http://playerstage.sourceforge.net/gazebo/xmlschema/#interface"
       xmlns:xacro="http://ros.org/wiki/xacro">

  <!-- Defines the kobuki component tag. -->
  <xacro:include filename="$(find kobuki_hokuyo)/urdf/kobuki_black.urdf.xacro" /> 
  <!-- include hokuyo model and set its pose -->
  <xacro:include filename="$(find kobuki_hokuyo)/urdf/hokuyo.urdf.xacro"/> 
		<xacro:sensor_hokuyo name="laser" parent="base_link">
        <origin xyz="0 0 0.12" rpy="0 0 0"/>
    </xacro:sensor_hokuyo> 
  <kobuki/> 
</robot>

위 코드를 보면 <xacro:include filename="$(find kobuki_hokuyo)/urdf/kobuki_black.urdf.xacro" />부분에 위에서 생성한 kobuki_black.urdf.xacro 파일이 사용되고 있는 것을 알 수 있습니다. 다른 파일들도 색깔별로 변경하여 저장합니다.

이렇게 하면 색깔별 urdf 파일 준비가 완료됩니다. 이제 이 파일들을 gazebo에서 불러들이는 launch 파일들을 생성합니다.

Single robot launch

앞에서 생성한 것들은 동일한 kobuki 로봇인데 main_body 색깔만 다른 것입니다. 따라서 아래와 같이 launch 파일 템플릿을 사용합니다. 단, 로봇의 이름, 초기 위치, 색깔 정보를 argument로 받게 합니다. robot.launch.xml이란 파일을 만들고 아래와 같이 채워넣습니다.

<!--
  Spawns Kobuki inside a Gazebo simulation
  -->
<launch>
  <arg name="robot_name" default="mobile_base"/>
  <arg name="init_pose"  default="-x 0 -y 0 -z 0"/>
  <arg name="color" default="black"/>

  <param name="robot_description"
        command="$(find xacro)/xacro.py '$(find kobuki_hokuyo)/urdf/kobuki_hokuyo_$(arg color).urdf.xacro'"/>
  <node pkg="gazebo_ros" type="spawn_model" name="spawn_$(arg robot_name)" 
        args="$(arg init_pose) -unpause -urdf -param robot_description -model $(arg robot_name)" respawn="false">
  </node>

  <node pkg="robot_state_publisher" type="robot_state_publisher" name="robot_state_publisher">
    <param name="publish_frequency" type="double" value="30.0" />
  </node>
  
  <node pkg="nodelet" type="nodelet" name="$(arg robot_name)_nodelet_manager" args="manager"/>
</launch>

argument가 어떻게 사용되고 있는지 주의깊게 살펴봅니다. <param name="robot_description" 태그에서 위에서 생성한 hokuyo센서가 부착된 색깔별 kobuki urdf 모델을 불러들이고 있습니다. 그리고 <node pkg="gazebo_ros" ..>에서 로봇의 초기 위치와 robot_name이 설정되는 것을 확인합니다.

Multiple robots launch

위에서 생성한 robot.launch.xml파일을 로봇 수 만큼 불러들이도록 아래와 같이 multi-robots.launch.xml 이름으로 파일을 생성하여 내용을 추가합니다.

<launch>

  <!-- BEGIN ROBOT 0. index starts from zero to coinside with the array index in the code-->
  <group ns="robot_0">
    <param name="tf_prefix" value="robot_0" />
    <include file="$(find kobuki_hokuyo)/launch/includes/robot.launch.xml" >
      <arg name="init_pose" value="-x 0.5 -y 0.5 -z 0" />
      <arg name="robot_name"  value="robot_0" />
      <arg name="color" value="black" />
    </include>
  </group>

  <!-- BEGIN ROBOT 1-->
  <group ns="robot_1">
    <param name="tf_prefix" value="robot_1" />
    <include file="$(find kobuki_hokuyo)/launch/includes/robot.launch.xml" >
      <arg name="init_pose" value="-x 2.5 -y 0.5 -z 0" />
      <arg name="robot_name"  value="robot_1" />
      <arg name="color" value="blue" />
    </include>
  </group>

  <!-- BEGIN ROBOT 2-->
  <group ns="robot_2">
    <param name="tf_prefix" value="robot_2" />
    <include file="$(find kobuki_hokuyo)/launch/includes/robot.launch.xml" >
      <arg name="init_pose" value="-x 2.5 -y 2.5 -z 0" />
      <arg name="robot_name"  value="robot_2" />
      <arg name="color" value="green" />
    </include>
  </group>

  <!-- BEGIN ROBOT 3-->
  <group ns="robot_3">
    <param name="tf_prefix" value="robot_3" />
    <include file="$(find kobuki_hokuyo)/launch/includes/robot.launch.xml" >
      <arg name="init_pose" value="-x 0.5 -y 2.5 -z 0" />
      <arg name="robot_name"  value="robot_3" />
      <arg name="color" value="white" />
    </include>
  </group>

</launch>

위 코드에서 4대의 로봇이 생성됩니다. 각각의 로봇을 구별하기 위해 <group ns="robot_0">를 사용했습니다. 그리고 편의를 위해 group 네임스페이스와 로봇이름을 동일하게 했습니다. 또한 robot index를 0부터 하여 code에서 robot 배열 index와 맞췄습니다. 또한 robot_name에 언더바를 넣어 robot_name 파싱할 때 편리하게 했습니다. <param name="tf_prefix" value="robot_0" /> 태그로 인해서 각 로봇과 관련한 topics은 접두에 "robot_0"과 같이 robot_name이 붙어서 publish 됩니다.

gazebo launch

드디어 모든 준비가 끝났습다. 이제 gazebo의 world와 multiple kobuki 로봇들을 불러들이는 launch 파일을 multiple_kobuki.launch 파일이란 이름으로 생성하고 아래와 같이 내용을 입력합니다.

<!-- Launches Kobuki Gazebo simulation in an empty world -->
<launch>
  <!-- start Gazebo with an empty world -->
  <include file="$(find gazebo_ros)/launch/empty_world.launch">
    <arg name="use_sim_time" value="true"/>
    <arg name="debug" value="false"/>
    <arg name="world_name" value="$(find kobuki_hokuyo)/worlds/simple.world"/>
  </include>
  
  <!-- include multiple robots -->
  <include file="$(find kobuki_hokuyo)/launch/includes/multi-robots.launch.xml"/>

</launch>

위 코드를 보면 위에서 생성한 <include file="$(find kobuki_hokuyo)/launch/includes/multi-robots.launch.xml"/> 파일을 include하고 있습니다. 자 이제 아래와 같이 launch 해보죠.

$ roslaunch kobuki_hokuyo multiple_kobuki.launch

간혹 launch 시에 segment fault 에러가 발생하기도 하는데, 다시 실행하면 됩니다. 실행 후 아래와 같이 topic list를 출력해 보면, 각 로봇별 topic이 구별되는 것을 알 수 있습니다. 따라서 소스코드에서는 robot_name과 함께 topic을 수신하여 처리하면 됩니다. 예를 들어 robot_1의 odometry는 /robot_1/odom topic을 수신하면 됩니다.

$ rostopic list
/clock
/gazebo/link_states
/gazebo/model_states
/gazebo/parameter_descriptions
/gazebo/parameter_updates
/gazebo/set_link_state
/gazebo/set_model_state
/robot_0/joint_states
/robot_0/mobile_base/commands/motor_power
/robot_0/mobile_base/commands/reset_odometry
/robot_0/mobile_base/commands/velocity
/robot_0/mobile_base/events/bumper
/robot_0/mobile_base/events/cliff
/robot_0/mobile_base/sensors/imu_data
/robot_0/odom
/robot_1/joint_states
/robot_1/mobile_base/commands/motor_power
/robot_1/mobile_base/commands/reset_odometry
/robot_1/mobile_base/commands/velocity
/robot_1/mobile_base/events/bumper
/robot_1/mobile_base/events/cliff
/robot_1/mobile_base/sensors/imu_data
/robot_1/odom
/robot_2/joint_states
/robot_2/mobile_base/commands/motor_power
/robot_2/mobile_base/commands/reset_odometry
/robot_2/mobile_base/commands/velocity
/robot_2/mobile_base/events/bumper
/robot_2/mobile_base/events/cliff
/robot_2/mobile_base/sensors/imu_data
/robot_2/odom
/robot_3/joint_states
/robot_3/mobile_base/commands/motor_power
/robot_3/mobile_base/commands/reset_odometry
/robot_3/mobile_base/commands/velocity
/robot_3/mobile_base/events/bumper
/robot_3/mobile_base/events/cliff
/robot_3/mobile_base/sensors/imu_data
/robot_3/odom
/rosout
/rosout_agg
/scan
/tf
/tf_static

댓글

댓글 본문