본문 바로가기

Robot/Robot Program - ROS

ROS URDF의 기초예제 Pan/Tilt 시스템

우연히 검색하던중 ROS 공부에 유용한 Github 페이지를 하나 찾았습니다. ROS 로보틱스 프로그래밍이라는 책의 소스코드가 있는 곳[바로가기]인데요. 실습하기 좋은 코드가 많더라구요. 사실 예전에 ROS 3D 시삭화툴 RVIZ에 대해 기초스러운 글[바로가기]을 올렸었는데요. 그 후 너무 오랜 시간이 지나 그나마 살짝 공부하던 기초가 머리를 떠나셔서ㅠㅠ. 다시 한 번 학습을 했습니다.^^  물론 첫 문장에서 이야기한 누군가가 올려준 학습용 예제를 따라하는 것이지만 말이죠^^

팬틸트라는 시스템은 이것 저것 학습하기 참 좋은 시스템인 것 같습니다.^^아무튼~~~ 오늘은 위 그림처럼 팬틸트 이야기 해볼려구요^^

먼저 catkin_create_pkg ex_urdf roscpp tf geometry_msgs urdf rviz xacro로 패키지를 만듭니다. 아.. 만들때 catkin_ws/src에서 만들어야 합니다. 그러면 위 그림처럼 기본적으로 생성되는 아이들이 있습니다.

거기에.. launchurdf라는 폴더를 두 개 만들어 둡니다. 그리고 catkin_make로 빌드도 해두구요^^

이제 우리는 저런 아이를 하나 만들고... 이쁘게 데리고 노는게 목표거든요^^

일단, urdf 파일을 하나 만들어야죠... urdf 폴더 안에 pan_tilt.urdf라고 하고 만들면 됩니다. 기본 뼈대는 위 그림과 같습니다. 오른쪽 코드 기준으로 base_link, pan_joint, pan_link, tilt_joint, tilt_link로 만들어 가면 됩니다. 두 개 있는 joint는 모두 revolute형입니다.[바로가기] 순서대로 뼈대를 완성했으니~~~

하나씩 보면~ 먼저 base_link입니다. link들은 통상 visual, collision, inertial이라는 항목을 가집니다. 그 각 항목을 기술해 주면 됩니다. 코드의 의미가 어렵진 않으실 겁니다. visual은 외형으로 저렇게 단순하게 사용할 수도 있고, 혹은 3D 도면 파일을 연결할 수도 있습니다. collision은 충돌방지나 시뮬레이션에서 충돌요소에 대한 시뮬레이션에서 사용하는 용도입니다.

그리고 pan_joint를 정의합니다. joint는 위 그림 좌측 상단에도 있지만, joint의 parent link의 frame 축에서부터의 위치정보를 origin에 기술하면 됩니다. 그리고 회전 중심축을 axis에서 알려주면 되구요^^

그 다음은 pan_link입니다. base와 다르지 않습니다.^^

그 다음.. tilt_joint를 기술하고

tilt_link를 기술하면 됩니다.

이제.. check_urdf pan_tilt.urdf라고 하면 뭐.. 원체 간단한 구조라서 짧지만 저렇게 결과가 나오네요~

또... urdf_to_graphiz pan_tilt.urdf를 사용하면 pdf로 구조가 나타납니다.

뭐... 잘 나타난듯 한데요^^ 이제 아래에 전체 urdf 코드입니다.

<?xml version="1.0"?>
<robot name="ex_urdf_pan_tilt">

    <link name="base_link">
        <visual>
            <geometry>
                <cylinder length="0.01" radius="0.2"/>
            </geometry>
            <origin rpy="0 0 0" xyz="0 0 0"/>
            <material name="yellow">
                <color rgba="1 1 0 1"/>
            </material>
        </visual>

        <collision>
            <geometry>
                <cylinder length="0.03" radius="0.2"/>
            </geometry>
            <origin rpy="0 0 0" xyz="0 0 0"/>
        </collision>

        <inertial>
            <mass value="1"/>
            <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
        </inertial>
    </link>

    <joint name="pan_joint" type="revolute">
        <parent link="base_link"/>
        <child link="pan_link"/>
        <origin xyz="0 0 0.1"/>
        <axis xyz="0 0 1" />
        <limit effort="300" velocity="0.1" lower="-3.14" upper="3.14"/>
        <dynamics damping="50" friction="1"/>
    </joint>

    <link name="pan_link">
        <visual>
            <geometry>
                <cylinder length="0.4" radius="0.04"/>
            </geometry>
            <origin rpy="0 0 0" xyz="0 0 0.09"/>
            <material name="red">
                <color rgba="0 0 1 1"/>
            </material>
        </visual>

        <collision>
            <geometry>
                <cylinder length="0.4" radius="0.06"/>
            </geometry>
            <origin rpy="0 0 0" xyz="0 0 0.09"/>
        </collision>

        <inertial>
            <mass value="1"/>
            <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
        </inertial>
    </link>

    <joint name="tilt_joint" type="revolute">
        <parent link="pan_link"/>
        <child link="tilt_link"/>
        <origin xyz="0 0 0.2"/>
        <axis xyz="0 1 0" />
        <limit effort="300" velocity="0.1" lower="-4.71239" upper="-1.570796"/>
        <dynamics damping="50" friction="1"/>
    </joint>

    <link name="tilt_link">
        <visual>
            <geometry>
                <cylinder length="0.4" radius="0.04"/>
            </geometry>
            <origin rpy="0 1.570796 0" xyz="0 0 0"/>
            <material name="green">
                <color rgba="1 0 0 1"/>
            </material>
        </visual>

        <collision>
            <geometry>
                <cylinder length="0.4" radius="0.06"/>
            </geometry>
            <origin rpy="0 1.570796 0" xyz="0 0 0"/>
        </collision>

        <inertial>
            <mass value="1"/>
            <inertia ixx="1.0" ixy="0.0" ixz="0.0" iyy="1.0" iyz="0.0" izz="1.0"/>
        </inertial>
    </link>
    
</robot>

그리고, 위 그림처럼 launch폴더에 view_pan_tilt_urdf.launch라는 launch파일을 만들어 둡니다.

<launch>
    <arg name="model" />

    <param name="robot_description" textfile="$(find ex_urdf)/urdf/pan_tilt.urdf" />

    <!-- Setting gui parameter to true for display joint slider -->
    <param name="use_gui" value="true"/>
    <!-- Starting Joint state publisher node which will publish the joint values -->
    <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />
    <!-- Starting robot state publish which will publish tf -->
    <node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher" />
    <!-- Launch visualization in rviz -->
    <node name="rviz" pkg="rviz" type="rviz" args="-d $(find ex_urdf)/urdf.rviz" required="True" />
</launch>

쉬워 보이지 않지만, 뭐 그렇다고 완전히 이해가 안되는 것도 아닙니다. 일단 이대로 사용하는 걸로^^(조금더 시간이 지나면 제가 ROS에 좀더 적응하고 나면 더 쉽게 풀어쓸 수 있겠죠^^)

그리고.. roslaunch ex_urdf view_pan_tilt_urdf.launch라고 입력하면 됩니다.

야호~~~~ 할려고 했는데 아무것도 없네요ㅠㅠ. 예전에도 이야기했었지만... 여기서...

add를 눌러 RobotModelTF를 추가해 줍니다.^^

그러면 저렇게 딱~ 뜹니다. 마우스의 오른쪽, 왼쪽 버튼과 휠을 사용해보면... 특히 휠을 클릭하는 것도~~ 그러면 회전, 이동, 확대/축소는 쉽습니다.^^

저렇게 joint_state_publisher를 사용해서 각도를 바꿔볼 수 있습니다.

종료하기 전에 묻는 저 질문에 저장하시면~

rviz파일이 하나 생성되구요.. 다음에 launch파일을 기동할때는 바로 모든 것이 보입니다.^^

아~ 그런데 하나 더~~~ XACRO라는 파일이 있습니다. 사실.. URDF파일은 직접 모든 내용을 기술하기 때문에 나중에 유지보수하기 어려울 수 있는데요~ XACRO를 사용하면 변수지정, 매크로 사용 등등이 가능해집니다. Pan/Tilt야 그런것까지 할 만한 복잡한 아이는 아니지만. 그래도 이런 아이로 연습하는게 좋죠^^ 일단... URDF 폴더에 pan_tilt.xacro파일을 만들고 내용을 넣으면 됩니다. 위 사진에 보이듯이 변수를 정의할 수 있습니다. 그리고 macro를 통해 공통적으로 사용되는 inertial에 대한 부분을 따로 정의할 수도 있습니다.

<?xml version="1.0"?>

<robot xmlns:xacro="http://www.ros.org/wiki/xacro" 
    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"
    name="ex_urdf_pan_tilt">


    <xacro:property name="base_link_length" value="0.01" />
    <xacro:property name="base_link_radius" value="0.2" />

    <xacro:property name="pan_link_length" value="0.4" />
    <xacro:property name="pan_link_radius" value="0.04" />

    <xacro:property name="tilt_link_length" value="0.4" />
    <xacro:property name="tilt_link_radius" value="0.04" />


    <xacro:macro name="inertial_matrix" params="mass">
               <inertial>
                       <mass value="${mass}" />
                       <inertia ixx="1." ixy="0.0" ixz="0.0"
                                iyy="1." iyz="0.0"
                                izz="1." />
               </inertial>
    </xacro:macro>



  <link name="base_link">

    <visual>
      <geometry>
         <cylinder length="${base_link_length}" radius="${base_link_radius}"/>
      </geometry>
      <origin rpy="0 0 0" xyz="0 0 0"/>
      <material name="yellow">
        <color rgba="1 1 0 1"/>
      </material>
    </visual>

    <collision>
      <geometry>
         <cylinder length="${base_link_length+0.02}" radius="0.2"/>
      </geometry>
      <origin rpy="0 0 0" xyz="0 0 0"/>
    </collision>
    <xacro:inertial_matrix mass="1"/>
  </link>

  <joint name="pan_joint" type="revolute">
    <parent link="base_link"/>
    <child link="pan_link"/>
    <origin xyz="0 0 0.1"/>
    <axis xyz="0 0 1" />
    <limit effort="300" velocity="0.1" lower="-3.14" upper="3.14"/>
    <dynamics damping="50" friction="1"/>
  </joint>

  <link name="pan_link">
    <visual>
      <geometry>
         <cylinder length="${pan_link_length}" radius="${pan_link_radius}"/>
      </geometry>
      <origin rpy="0 0 0" xyz="0 0 0.09"/>
      <material name="red">
        <color rgba="0 0 1 1"/>
      </material>
    </visual>
    <collision>
      <geometry>
         <cylinder length="${pan_link_length}" radius="${pan_link_radius+0.02}"/>
      </geometry>
      <origin rpy="0 0 0" xyz="0 0 0.09"/>
    </collision>
    <xacro:inertial_matrix mass="1"/>
  </link>

  <joint name="tilt_joint" type="revolute">
    <parent link="pan_link"/>
    <child link="tilt_link"/>
    <origin xyz="0 0 0.2"/>
    <axis xyz="0 1 0" />
    <limit effort="300" velocity="0.1" lower="-4.71239" upper="-1.570796"/>
    <dynamics damping="50" friction="1"/>
  </joint>

  <link name="tilt_link">
    <visual>
      <geometry>
         <cylinder length="${tilt_link_length}" radius="${tilt_link_radius}"/>
      </geometry>
      <origin rpy="0 1.5 0" xyz="0 0 0"/>
      <material name="green">
        <color rgba="1 0 0 1"/>
      </material>
    </visual>
    <collision>
      <geometry>
         <cylinder length="${tilt_link_length}" radius="${tilt_link_radius+0.2}"/>
      </geometry>
      <origin rpy="0 1.570796 0" xyz="0 0 0"/>
    </collision>
    <xacro:inertial_matrix mass="1"/>
  </link>


</robot>

위 코드와 아까 urdf를 비교해보면 쉽게 눈치챌 수 있을 듯 합니다.

일부만 보면 저런식인거죠... 변수명을 사용할 수 있으니.. 수정할때는 상단 변수명에 있는 숫자만 바꿔주면 됩니다^^

이를 urdf로 바꿔주는 명령은 rosrun xacro xacro --inorder pan_tilt.xacro > pan_tilt.urdf입니다. ...

그리고 변환된 urdf를 열어보면 동일한 내용입니다. 원래 다루었던 내용인데.. 기억도 되살릴겸 한 번 적어봤네요~~~ ROS를 오랜만에 다시 공부하는데 마음이 급해요.. ㅎㅎ^^

반응형