본문 바로가기

ROS

간단한 urdf모델 만들고 rviz로 보기

이 글은 아래 링크를 보고 따라한 글입니다.

https://gbiggs.github.io/rosjp_urdf_tutorial_text/mobile_robot_urdf.html#mobile_robot_links

 

ロボットモデリング講習会:URDFの作成方法 by gbiggs

移動型ロボットのURDF作成 Updated on: 2018-02-27 トップに戻る 本セクションではURDFの基本を説明し、簡単な移動型ロボットのURDFの作成によってURDFの作成方法を学習します。 作成する移動型ロボ

gbiggs.github.io

 

우선 패키지를 만들어줍니다.

cd ~/catkin_ws/src
catkin_create_pkg rt_mouse_replica geometry_msgs roscpp rospy std_msgs

 

rt_mouse_replica - 예시로 rt사의 mouse 로봇의 레플리카를 만들거라서 패키지명을 이렇게 정했습니다.

geometry_msgs - SLAM로봇의 제어의 메시지 타입으로 자주 쓰이는 Twist가 이 패키지에 소속됩니다

rospy - 마찬가지로 제어 메시지를 생성해주는 turtlebot 관련 스크립트를 실행하기 위해 사용했습니다.

roscpp - 아직 미정입니다만, 몇가지 시뮬레이터는 cpp코드로 제어메시지를 생성하기도 하므로 사용했습니다.

std_msgs - 미정이지만 일단 넣었습니다.

 

그 다음 패키지 안에 urdf폴더를 만들고 mouse.xacro 파일을 만듭니다.

cd ~/catkin_ws/src/rt_mouse_replica
mkdir urdf
cd urdf
touch mouse.xacro

 

urdf파일을 만드는게 아닌 xacro파일을 만드는 이유는, 나중에 제어 관련 코드를 넣기 위함입니다. xacro라이브러리가 xacro파일을 해석하면서 urdf파일을 만들면서 제어 관련 프로그램들도 연결해줍니다.

<?xml version="1.0" ?>
<robot name="mobilerobot" xmlns:xacro="http://ros.org/wiki/xacro">
    <link name="base_link">
        <visual>
            <geometry>
                <box size="0.13 0.1 0.052"/>
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0"/>
        </visual>
        <visual name="regulators">
            <geometry>
                <box size="0.005 0.065 0.02"/>
            </geometry>
            <origin xyz="0.04 0 0.036" rpy="0 0 0"/>
        </visual>
        <visual name="connector">
            <geometry>
                <box size="0.075 0.016 0.026"/>
            </geometry>
            <origin xyz="0 -0.027 0.039" rpy="0 0 0"/>
        </visual>
    </link>

 

<?xml version="1.0" ?> - 이 문서가 xml문서임을 의미합니다.

<robot name="mobilerobot" xmlns:xacro="http://ros.org/wiki/xacro"> - 로봇의 이름을 설정하고, </robot>가 나오기 이전에 나오는 서술들을 이 로봇에 소속시킵니다. 또한, xmlns:xacro="http://ros.org/wiki/xacro" 는 이를 해석하기 위한 네임스페이스의 지정입니다.

<link name="base_link"> - base_link라는 이름으로 링크를 하나 만듭니다. urdf형식에서 로봇은 링크link들과 이를 연결하는 조인트joint로 이루어져있습니다. 링크가 무엇인지는 후술하겠습니다만, 그냥 "파츠"정도로만 생각해 주세요.

<visual> - 해당 링크가 시뮬레이터상에서 어떻게 시각적 정보를 표현할지 서술합니다. <visual>이외에도 시뮬레이션상 충돌을 예산하기 위한 <collision>이나 질량이나 관성모멘트 행렬을 계산하기 위한 <inertial>도 있습니다. 하나의 link가 복수의 visual을 가지는 것은 문제 없습니다.

<geometry> - 해당 출력요소의 기하학적 형태의 정보(크기 등)를 기록합니다. box이외에도 sphere(구), cylinder(원통)도 있습니다.

<origin xyz="0.04 0 0.036" rpy="0 0 0"/> - 해당 출력 요소(박스)의 원점의 x/y/z축위치 및 x,y,z축방향으로 회전한 양을 서술합니다. 예를 들어, rpy="0 0 1"이라고 적었다면 오른손으로 따봉 손모양을 했을 때, z축이 엄지손가락 방향이라면, 나머지 손가락들이 휘감은 방향으로 회전한다고 생각하시면 됩니다.

 

그 다음엔 이 xacro를 urfg로 만든 후 rviz에 쏴주는 실행파일을 만듭니다.

cd ~/catkin_ws/src/rt_mouse_replica
mkdir launch
cd launch
touch view_mouse.launch

 

view_mouse.launch파일을 열고 내용을 이렇게 적어줍니다.

<?xml version="1.0" ?>
<launch>
<arg name="model" />
<!-- Parsing xacro and setting robot_description parameter -->
<param name="robot_description" command="$(find xacro)/xacro $(find rt_mouse_replica)/urdf/mouse.xacro" />
<node name="robot_state_publisher" pkg="robot_state_publisher" type="robot_state_publisher" />
<node name="joint_state_publisher_gui" pkg="joint_state_publisher_gui" type="joint_state_publisher_gui" />
<!-- Launch visualization in rviz -->
<node name="rviz" pkg="rviz" type="rviz" args="-f /base_link" required="true" />
</launch>

 

<param name="robot_description" command="$(find xacro)/xacro $(find rt_mouse_replica)/urdf/mouse.xacro" />

 - 아까 만든 mouse.xacro를 xacro로 파싱한 것을 robot_description이라는 패러미터로 로드시켜두라고 합니다. 이는 시각화 툴에서 robot_description이 필요하기때문입니다.

robot_state_publisher, joint_state_publisher_gui 로봇의 현재 상태를 ros를 통해 수신하기 위한 것입니다. 특히 joint_state_publisher_gui는 나중에 gui로 조인트의 회전각도를 시뮬레이터 내부로 보낼 때 필요합니다.

 

<node name="rviz" pkg="rviz" type="rviz" args="-f /base_link" required="true" />

rviz로 하고 기준점을 base_link로 설정합니다. 여기서 기준점을 주지 않고 그냥 실행시키게 되면, 아래의 기동화면에서 Fixed Frame에서 직접 설정을 해줘야됩니다. 모델링할 때는 내용물 확인하고 코딩하는 과정의 반복이니 이런 반복공정을 줄여주기 위해서 입력해줍시다.

나중에 설정을 저장했다면 <node name="rviz" pkg="rviz" type="rviz" args="-d $(find rt_mouse_replica)/launch/view_mouse_config.rviz -f /base_link" required="true" /> 같은 식으로 설정파일을 rviz기동과 동시에 불러오게 합시다.

 

그럼 기동시킵니다.

roslaunch rt_mouse_replica view_mouse.launch

기동했다면 이렇게 횡한 화면이 나옵니다. 여기서 왼쪽 아래에 Add를 누르면

이런 화면이 나오는데 RobotModel을 선택하고 Ok를 눌러줍니다.

 

그러면 아까 만든 모델이 화면 한가운데 나오는 걸 확인할 수 있습니다.

스샷에선 그냥 빨간 점으로 나오지만 마우스 휠로 확대할 수 있어요.

그리고 왼쪽 위 File 메뉴에서 Save config로 현재 설정을 저장해주고 몇 줄 위에 서술했듯이 런치파일의 arguments에서 -d 로 부여해줍니다. 

 

그럼 계속해서 xacro파일을 손 봐줍시다.

<?xml version="1.0" ?>
<robot name="mobilerobot" xmlns:xacro="http://ros.org/wiki/xacro">
    <link name="base_link">
        <visual>
            <geometry>
                <box size="0.13 0.1 0.052"/>
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0"/>
        </visual>
        <visual name="regulators">
            <geometry>
                <box size="0.005 0.065 0.02"/>
            </geometry>
            <origin xyz="0.04 0 0.036" rpy="0 0 0"/>
        </visual>
        <visual name="connector">
            <geometry>
                <box size="0.075 0.016 0.026"/>
            </geometry>
            <origin xyz="0 -0.027 0.039" rpy="0 0 0"/>
        </visual>
        <collision>
            <geometry>
                <box size="0.13 0.1 0.078"/>
            </geometry>
            <origin xyz="0 0 0.013" rpy="0 0 0"/>
        </collision>
    </link>
    
</robot>

 

<collision>이 늘었습니다.  이는 충돌 여부 판정을 할때 사용됩니다.  몸통 뿐 아니라 윗부분에 놓여있는 오브젝트들도 포함시켜주기 위해서 아래와 같이 좀 크게 잡아줍니다.

rviz에서 확인할 때에는 Collision Enabled를 체크 시켜주면 됩니다. 이렇게되면 collision에 뒤덮여서 아까 배치한 상자들이 안보이게 되니 Alpha값을 좀 내려줍니다.

그 다음엔 색칠도 해줍니다.

<?xml version="1.0" ?>
<robot name="mobilerobot" xmlns:xacro="http://ros.org/wiki/xacro">
    <material name="black">
        <color rgba="0.2 0.2 0.2 1"/>
    </material>
    <material name="grey">
        <color rgba="0.75 0.75 0.75 1"/>
    </material>
    <link name="base_link">
        <visual>
            <geometry>
                <box size="0.13 0.1 0.052"/>
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0"/>
            <material name="grey"/>
        </visual>
        <visual name="regulators">
            <geometry>
                <box size="0.005 0.065 0.02"/>
            </geometry>
            <origin xyz="0.04 0 0.036" rpy="0 0 0"/>
            <material name="black"/>
        </visual>
        <visual name="connector">
            <geometry>
                <box size="0.075 0.016 0.026"/>
            </geometry>
            <origin xyz="0 -0.027 0.039" rpy="0 0 0"/>
            <material name="black"/>
        </visual>
        <collision>
            <geometry>
                <box size="0.13 0.1 0.078"/>
            </geometry>
            <origin xyz="0 0 0.013" rpy="0 0 0"/>
        </collision>
    </link>
    
</robot>

 

<material>태그를 활용해서 색을 칠해줬습니다.

아까 설정한 config파일을 활용해서 기동시키면 튕기던데, 그럼 -d 인수를 빼고 그냥 직접 로드시켜줍니다. (config파일을 새로 저장하고-d를 다시 써도 되구요.) 

 

다음엔 뒷바퀴를 지지해줄 지지대와, 이를 회전시켜줄 관절을 추가해줍니다.

 

  </link>
    <joint name="caster_support_joint" type="continuous">
        <axis xyz="0 0 1"/>
        <parent link="base_link"/>
        <child link="caster_support"/>
        <origin xyz="-0.065 0 -0.01" rpy="0 0 0"/>
    </joint>
    <link name="caster_support">
        <visual>
            <geometry>
                <box size="0.02 0.02 0.04"/>
            </geometry>
            <origin xyz="-0.01 0 0" rpy="0 0 0"/>
            <material name="grey"/>
        </visual>
        <collision>
            <geometry>
                <box size="0.02 0.02 0.04"/>
            </geometry>
            <origin xyz="-0.01 0 0" rpy="0 0 0"/>
        </collision>
    </link>
    
</robot>

 

<joint>

type - 이 관절의 타입을 정합니다. 모터가 주로 생각나는 힌지 조인트는 continous(범위제한 없음), revolute(범위제한 있음)이 있고, 단순히 링크를 나누기 위해서 만들었을 뿐, 차일드 링크가 움직이지 않기를 원하는경우 fixed를 사용하고 그 외엔, planar(평면위 운동), prismatic(1차원운동 - 미닫이문 생각하면 됨), floating(사실상 관절과 분리되서 자유롭게 움직임 - This joint allows motion for all 6 degrees of freedom.)

<axis> - 이 관절이 움직이게 허용해주는 축을 결정합니다. 이게 타입이 continous니까 한 축만 설정이 가능할 거고 z축을 설정해줍니다.

<origin> - Link에서의 origin과 같습니다. 그런데 주의할 점은, 여기서 지정하는 좌표가 바로 child link의 원점이 됩니다.

caster_support링크의 내용은 전반적으로 base_link와 같지만, 원점이 관절에서 -0.01만큼 떨어져있습니다. 이 이유는 왜냐면 이 모델로 시뮬레이션 중, 로봇이 앞으로 움직이고 있을 때 기준 이 링크도 함께 앞방향을 가리키게 위함입니다. 0이나 0.01로 해도 물리적으로 뒤로 돌기때문에 별 차이는 없지만, 머릿속에서 이미지하기 쉽다는 장점이 있죠.

 

joint니 link니 단어가 무엇인지 모르시고, 감이 안잡히신다면 http://wiki.ros.org/urdf/XML/model 이 링크의 글을 한번 슥 보시면 됩니다.

 

 

Add에서 Tf를 골라주고 Scale를 잘 조정해주면 이렇게 보입니다.

같이 나온 팝업창에서 슬라이더바를 움직여주면 조인트를 회전시켜 볼 수도 있습니다.

 

마저 뒷바퀴도 달아줍니다.

 

<link name="caster_wheel">
        <visual>
            <geometry>
                <cylinder length="0.005" radius="0.02"/>
            </geometry>
            <material name="black"/>
        </visual>
        <collision>
            <geometry>
                <cylinder length="0.005" radius="0.02"/>
            </geometry>
        </collision>
    </link>
    <joint name="caster_wheel_joint" type="continuous">
        <axis xyz="0 0 1"/>
        <parent link="caster_support"/>
        <child link="caster_wheel"/>
        <origin xyz="-0.02 0 -0.02" rpy="-1.5708 0 0"/>
    </joint>

 

별다르게 눈여겨 볼 곳은 geometry로 정의되어있고, length, radius가 붙어있습니다. 바퀴니까 원통형이라고 생각하면 좋겠죠.

그런데 이 cylinder은 기본적으로 지면에 놓인 드럼통처럼 둥근 단면이 하늘로 향하게 되어 있습니다. 바퀴처럼 데굴데굴 구르게 하려면 옆으로 눕혀줄 필요가 있습니다. 선택지는 두개인데

1. 링크 자신을 눕힌다

2. 조인트의 원점을 눕힌다.

링크 자신을 눕히는 경우 visual, collision, inertia의 rpy값을 전부 바꿔주어야합니다. 일이 세 배로 됩니다.

조인트를 돌리는 경우 이 조인트의 rpy값만 바꿔주면 됩니다만, 눕히고 싶은 오브젝트는 링크인데 돌아가 있는 오브젝트는 조인트인 형태니, 가독성이 떨어지게 됩니다. 또한, 바퀴는 앞뒤로 구르니까 모션으로 치면 pitch(y축회전)인데, z축으로 돌리는 듯하게 해줘야됩니다.

위의 코드는 2번의 형태이고 1번의 형태로 하려면

<link name="caster_wheel">
        <visual>
            <geometry>
                <cylinder length="0.005" radius="0.02"/>
            </geometry>
            <origin rpy="-1.5708 0 0"/>
            <material name="black"/>
        </visual>
        <collision>
            <geometry>
                <cylinder length="0.005" radius="0.02"/>
            </geometry>
            <origin rpy="-1.5708 0 0"/>
        </collision>
    </link>
    <joint name="caster_wheel_joint" type="continuous">
        <axis xyz="0 1 0"/>
        <parent link="caster_support"/>
        <child link="caster_wheel"/>
        <origin xyz="-0.02 0 -0.02"/>
    </joint>

로 적어도 같은 결과를 얻을 수 있습니다. 

 

마저 바퀴 두개까지 달아줍니다.

<?xml version="1.0" ?>
<robot name="mobilerobot" xmlns:xacro="http://ros.org/wiki/xacro">
    <material name="black">
        <color rgba="0.2 0.2 0.2 1"/>
    </material>
    <material name="grey">
        <color rgba="0.75 0.75 0.75 1"/>
    </material>
    <link name="base_link">
        <visual>
            <geometry>
                <box size="0.13 0.1 0.052"/>
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0"/>
            <material name="grey"/>
        </visual>
        <visual name="regulators">
            <geometry>
                <box size="0.005 0.065 0.02"/>
            </geometry>
            <origin xyz="0.04 0 0.036" rpy="0 0 0"/>
            <material name="black"/>
        </visual>
        <visual name="connector">
            <geometry>
                <box size="0.075 0.016 0.026"/>
            </geometry>
            <origin xyz="0 -0.027 0.039" rpy="0 0 0"/>
            <material name="black"/>
        </visual>
        <collision>
            <geometry>
                <box size="0.13 0.1 0.078"/>
            </geometry>
            <origin xyz="0 0 0.013" rpy="0 0 0"/>
        </collision>
    </link>
    <joint name="caster_support_joint" type="continuous">
        <axis xyz="0 0 1"/>
        <parent link="base_link"/>
        <child link="caster_support"/>
        <origin xyz="-0.065 0 -0.01" rpy="0 0 0"/>
    </joint>
    <link name="caster_support">
        <visual>
            <geometry>
                <box size="0.02 0.02 0.04"/>
            </geometry>
            <origin xyz="-0.01 0 0" rpy="0 0 0"/>
            <material name="grey"/>
        </visual>
        <collision>
            <geometry>
                <box size="0.02 0.02 0.04"/>
            </geometry>
            <origin xyz="-0.01 0 0" rpy="0 0 0"/>
        </collision>
    </link>
    <link name="caster_wheel">
        <visual>
            <geometry>
                <cylinder length="0.005" radius="0.02"/>
            </geometry>
            <origin rpy="-1.5708 0 0"/>
            <material name="black"/>
        </visual>
        <collision>
            <geometry>
                <cylinder length="0.005" radius="0.02"/>
            </geometry>
            <origin rpy="-1.5708 0 0"/>
        </collision>
    </link>
    <joint name="caster_wheel_joint" type="continuous">
        <axis xyz="0 1 0"/>
        <parent link="caster_support"/>
        <child link="caster_wheel"/>
        <origin xyz="-0.02 0 -0.02"/>
    </joint>
    
    <link name="right_wheel">
        <visual>
            <geometry>
                <cylinder length="0.008" radius="0.024"/>
            </geometry>
            <material name="black"/>
            <origin rpy="-1.5708 0 0"/>
        </visual>
        <collision>
            <geometry>
                <cylinder length="0.008" radius="0.024"/>
            </geometry>
            <origin rpy="-1.5708 0 0"/>
        </collision>
    </link>
    <joint name="right_wheel_joint" type="continuous">
        <axis xyz="0 1 0"/>
        <parent link="base_link"/>
        <child link="right_wheel"/>
        <origin xyz="0 0.054 -0.021"/>
    </joint>

    <link name="left_wheel">
        <visual>
            <geometry>
                <cylinder length="0.008" radius="0.024"/>
            </geometry>
            <material name="black"/>
            <origin rpy="-1.5708 0 0"/>
        </visual>
        <collision>
            <geometry>
                <cylinder length="0.008" radius="0.024"/>
            </geometry>
            <origin rpy="-1.5708 0 0"/>
        </collision>
  </link>
  <joint name="left_wheel_joint" type="continuous">
        <axis xyz="0 1 0"/>
        <parent link="base_link"/>
        <child link="left_wheel"/>
        <origin xyz="0 -0.054 -0.021"/>
  </joint>
    
</robot>