1. URDF (Unified Robot Description Format)

URDF[2]는 “Unified Robot Description Format” 이라는 약자로 XML 파일 형식으로 로봇의 기구에 해당되는 링크(link)와 동적인 움직임을 갖는 조인트(joint) 등으로 로봇을 모델링하고 이를 시각화 툴인 RViz(ROS Visualization, [3])나 3차원 시뮬레이션 툴인 Gazebo[4]와 같은 프로그램에서 모델링한 로봇을 사용할 수 있게 해주는 포맷을 말한다.

그리고 이전 TF 강좌[5]에서 tf2[6]를 이용하여 3차원 로봇 좌표들을 변환하는 작업을 프로그래밍 했었는데 URDF를 이용하면 보다 쉽게 좌표 변환 기능을 사용할 수도 있다. 예를 들어 프로그래밍으로만 좌표 변환을 하여 로봇 모델을 작성하는 것과는 달리 URDF를 이용하게 되면 로봇의 동작 환경 및 설계한 로봇의 외형, 동적인 움직임을 링크와 조인트 등으로 URDF 파일 형식에 맞추어 작성하고, 이를 ROS 시각화 툴인 RViz에서 확인할 수 있어서 시각화 기능으로 로봇 모델링의 디버깅을 더 쉽게 할 수 있다. 그리고 가상의 동작 환경을 꾸밀 수 있는 3D 시뮬레이터인 Gazebo 환경에서 URDF와 마찬가지로 XML을 사용하여 시뮬레이션 옵션을 추가한 SDF(Simulation Description Format, [7])파일을 통해 쉽게 3차원 시뮬레이션 환경을 제작할 수 있어서 로봇 없이도 가상의 공간에서 가상의 로봇을 제어해볼 수도 있다.

여기서 사용되는 포맷은 아래와 같이 3가지인데 각 포맷마다 그 사용 목적이 조금씩 상이하다. URDF가 이 강의에서 다룰 로봇 모델링의 기본 포맷이고, SDF(Simulation Description Format)는 시뮬레이션 기능이 추가된 형태로 Gazebo에서 사용되는 포맷이고, SRDF(Semantic Robot Description Format, [8])는 매니퓰레이션 툴인 MoveIt!에서 사용하고 있다. 이 SRDF 포맷을 새로 익힐 필요는 없고 MoveIt!의 GUI 환경 설정용 설정 툴인 MoveIt! Setup Assistant 프로그램을 통해 URDF를 SRDF로 쉽게 변환 가능하다.

- URDF: Unified Robot Description Format [2] / RViz

- SDF: Simulation Description Format [7] / Gazebo

- SRDF: Semantic Robot Description Format [8] / MoveIt!

그리고 SDF의 경우 시뮬레이션 기능을 더 포함하고 있는데 이는 Gazebo에서 변환 프로그램인 ‘gz sdf’[9]를 통해 하기 예제와 같이 URDF를 SDF로 변환하여 사용 가능하다. 즉 URDF만 정확히 알고 있어도 관련 툴을 적절히 이용하는 것으로도 SRDF 및 SDF로의 변환은 비교적 쉽게 이용 가능하다.

$ gz sdf -p model.urdf > model.sdf

* 참고로 조인트(joint)는 매니퓰레이터의 경우 관절로 설명하면 더 쉽게 이해될 수 있지만 조인트라는 개념이 모바일 로봇에서 사용될 때에는 바퀴의 동적 움직임에 해당되기에 관절로 설명하지 않고 영어 발음 그대로 표기하여 사용하겠다.

2. 로봇 모델의 기본 정보

이 강좌에서는 URDF를 가지고 실제 모바일 로봇 및 매니퓰레이터 로봇을 시각화 및 가상공간에서 시뮬레이션 할 수 있도록 각 구성 요소를 모델링하는 방법에 대해 알아볼 것이다. 복잡한 구조의 URDF 모델을 다루기 앞서 간단히 조인트 3개와 링크 4개로 이루어진 비교적 간단한 구조의 3축 매니퓰레이터의 URDF를 직접 작성해보면서 URDF의 기본 사용 방법을 익혀보자.

우선 로봇 모델링에 앞서서 우리가 모델링할 매니퓰레이터의 기본 구성 요소에 대해 짚고 넘어가자. 매니퓰레이터의 구성 요소에는 그림[1]와 같이 기저(base), 링크(link), 조인트(joint), 말단 장치(end effector)으로 구성되어 있다.

기저(base) 매니퓰레이터가 고정되어 있는 부분: 목적에 따라 작업 공간내 바닥이 될 수 있고, 동적으로 움직이는 모바일 로봇이 될 수도 있다.
링크(link) 기저, 조인트, 말단 장치를 연결해주는 강체 역할: 쉽게 말해 프레임이라고 보면 된다.
조인트(joint) 로봇의 움직임을 만들어내는 부분: 회전(revolute) 운동형과 병진(prismatic) 운동형 등의 동적 움직임을 가짐
말단 장치(end effector) 사람의 손에 해당하는 부분 또는 장비: 집거나 흡착하여 들어올리거나 페인트를 분사하는 등 로봇의 목적에 따라 달라짐

[표 1: 매니퓰레이터의 기본 구성 요소]

img

[그림 1: 매니퓰레이터의 기본 구조]

여기서 링크와 조인트 부분이 가장 중요한데 링크(link) 정보에는 기하학적 정보가 주가 된다. 예를 들어 외형을 표현해주기 위해 원통, 원뿔, 직육면체 등의 간단한 모델을 쓰기도 하고, 복잡한 구조가 필요할 때에는 메쉬(mesh)을 표현할 수 있는 STL 또는 DAE(COLLDA)과 같은 3차원 설계 파일을 이용하기도 한다. 이 정보에는 무게(mass, Kg), 관성 모멘트(moments of inertia, Kg·m^2) 등도 포함된다.

“링크 정보 = 링크의 이름 / 외형 / 무게 / 관성 모멘트”

그리고 조인트(joint) 정보에는 전/후 링크와의 관계를 기술하고 그림 [2]와 같은 움직임별로 구별한 조인트의 종류와 회전 및 병진 운동의 기준 축 정보, 최소/최대 조인트 값, 조인트에 부여되는 힘, 속도 등과 같은 물성치의 한계 값이 포함된다.

조인트 = 조인트의 이름 / 종류 / 운동의 기준 축 / 최소, 최대 조인트 값 / 조인트에 부여되는 힘 / 속도”

이러한 링크와 조인트 정보들은 모두 URDF의 XML 태그[10]를 통해 기입해주면 된다. 이 이외에도 로봇의 동역학적 요소, 시각화 그리고 충돌 모델을 쉽게 설정해 줄 수 있다. URDF는 태그[11]를 통해 시작되며 세부 내용으로는 로봇의 구성 요소인 링크와 조인트를 정의하기 위한 태그[12]와 태그[13]가 번갈아 가면서 나오는 것이 일반적이다. 여기에 조인트와 액츄에이터 간의 관계를 설정할 수 있는 태그[14]도 ros_control[15]과의 연동을 위해 포함시키기도 한다.

img

[그림 2: 조인트(joint)의 종류]

3. Description 패키지와 URDF 작성

위에서 언급한 3축 매니퓰레이터의 기본 정보들을 URDF로 작성해보자. 이를 위해 다음과 같이 testbot_description 패키지를 생성한 다음, urdf 폴더를 생성하자. 그리고 편집기를 이용해 testbot.urdf 파일을 생성하고, testbot.urdf 예제를 입력하자.

* 참고로 ROS 커뮤니티에서는 로봇의 모델링 정보를 담은 패키지를 ‘로봇명_description‘라는 이름으로 주로 사용하고 있다. 다양한 URDF를 참고하고 싶다면 https://index.ros.org/ 사이트에서 description 이라고 검색해보면 로봇뿐만이 아니라 카메라 등 센서들의 모델링 파일도 찾아볼 수 있다.

$ cd ~/robot_ws/src $ ros2 pkg create testbot_description –build-type ament_cmake –dependencies urdf $ cd testbot_description $ mkdir urdf $ cd urdf $ nano testbot.urdf

testbot_description/urdf/testbot.urdf

https://github.com/robotpilot/ros2-seminar-examples/testbot_description

<?xml version=”1.0” ?>

</link> </link> </link> </link>

URDF는 정해놓은 XML 태그[10]를 이용해 로봇의 각 구성 요소를 기술한다. URDF 형식으로 먼저 로봇의 이름, 기저의 이름과 종류, 기저에 연결되어 있는 링크를 기술한 다음 이어지는 링크와 조인트의 내용을 하나씩 기술하여 트리구조로 만들게 된다. 이 예제에서는 기저가 고정되어 있다고 간주했다.

(생략) 다음의 **material 태그**는 **링크의 색상 및 질감 등의 정보를 기술**한다. 다음 예제에서는 각 링크를 구별하기 위해 검정과 오렌지색의 두 재질을 정의했다. 색상은 color 태그를 이용하는데 rgba 옵션 뒤에 빨강, 초록, 파랑에 해당하는 0.0 ~ 1.0 사이의 숫자를 각각 기입하여 설정할 수 있다. 마지막 숫자는 투명도(알파)로 0.0 ~ 1.0 값을 가지며 1.0 이면 투명 옵션을 사용하지 않은 고유 색상을 그대로 표시하는 상태를 의미한다. **4. URDF의 링크(link)** 매니퓰레이터의 구성 요소 그 첫 번째인 기저는 URDF에서 링크로 표현한다. 기저는 첫 번째 링크와 조인트로 연결되어 있으며 이 조인트는 동작하지 않고 고정되어 원점(0.0, 0.0, 0.0)에 위치해 있다. 태그의 보다 자세한 설명을 위해 첫 번째 링크(link1) 태그를 살펴보자. </link> URDF의 ** 태그**는 앞서 본 link1 예제와 같이 **관성 , 시각화 , 충돌 태그**로 구성되어 있다. 그림 [3]을 참고하도록 하자. ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDRfNzIg/MDAxNjE0ODYzNDMxNjE4.YTqLIjRffgJ9emoKHBFNX1UocQxl-rBramuwOiwGSyMg.Q5nqLn82m-kJE7lLshSSwTSe2sZjytoc33_6CD3UQHYg.PNG/Selection_104.png?type=w1600) [그림 3: 링크의 모델링 요소] **** 태그에는 주로 관성 정보를 기재하게 되는데, **** 태그에는 이전 링크로부터 x, y, z 위치 변환과 r, p ,y 자세 변환한 상태 좌표(단위: meter, radian)를 기입한다. 그리고 **** 태그에는 링크의 무게(mass, 단위: Kg), **** 태그에는 관성 모멘트(moments of inertia [16], 단위:kg·m^2)를 기입한다. 이 관성 정보는 설계 소프트웨어나 혹은 실제 측정과 계산을 통해 얻을 수 있으며 시뮬레이션 할 때 주로 사용한다. **** 태그에는 실제 형상을 적는다. **** 태그는 위의 태그의 태그와 동일하다. **** 태그는 origin 좌표 중심으로 표시 범위의 모양과 크기를 적는다. 예를 들어 사각 기둥(box)형의 표시 범위는 가로, 세로, 높이의 값이다. 사각 기둥 형 이외에도, 원통형(cylinder), 구형(sphere) 등이 있는데 각각 입력하는 내용이 다르다. 간단한 모양으로 표현하기 어려울 때에는 여기에 STL과 DAE 등의 CAD 파일을 입력할 수도 있다. **** 태그에는 링크의 간섭 범위를 나타내는 기하학적 정보를 입력할 수 있다. **** 태그 및 **** 태그는 위에서 언급한 내용과 동일한데 표시 범위가 아닌 간섭 범위로 태그의 표시 범위보다 더 크게하여 안전을 더 고려할 수도 있다. 태그에 기입한 내용은 MoveIt 및 Gazebo에서 사용되는 값인 만큼 기입에 주의를 기울여야 한다. 태그의 태그와 마찬가지로 태그의 또한 CAD 파일을 기입할 수 있는데 메시 형태가 복잡한 경우 이를 간섭 계산 등에 사용되어 계산 시간이 길어질 수 있으니 해상도를 적절히 사용하여 계산에 불필요히 늘어나지 않도록 주의하여 사용해야 한다. 또한 ODE 또는 Bullet 등 일부 물리 엔진에서만 사용할 수 있으며 DART과 Simbody [17]등은 지원하지 않는 경우도 있다. | **** | 링크의 시각화와 충돌 그리고 관성 정보 설정 | | --------------- | ------------------------------------------------------------ | | **** | 링크의 관성 정보 설정 | | **** | 링크의 시각화 정보 설정 | | **** | 링크의 충돌 계산을 위한 간섭 정보 설정 | | **** | 링크의 무게(단위: kg) 설정 | | **** | 관성 텐서(Inertia tensor) 설정 | | **** | 링크의 상대 좌표계를 기준으로 이동과 회전 설정 | | **** | 모델의 모양 입력. box, cylinder, sphere 형태를 기본 제공하며 COLLADA(.dae), STL(.stl) 형식의 설계 파일을 불러 올 수도 있음 | | **** | 링크의 색깔과 텍스쳐 설정 | [ 표 2: 링크(link) 태그의 속성] 예제 testbot.urdf에서 기술된 **link1, link2, link4**는 연결된 상위 조인트(각각 순서대로 fixed, joint1, joint3)의 원점으로부터 0.25m씩 origin의 오프셋 이동 후, 이동된 원점에서 z축 방향으로 뻗은 길이 0.5m(+방향으로 0.25m, -방향으로 0.25m)에 가로 0.1m, 세로 0.1m의 사각 기둥이며, **link3** 도 마찬가지로 연결된 상위 조인트(joint2)의 원점으로부터 0.5m 위치만큼 origin의 오프셋 이동 후, z축 방향으로 뻗은 길이 1m에 가로 0.1m, 세로 0.1m의 사각 기둥이다. URDF에서 상대 좌표 변환에 대한 이해는 처음 접할 경우 상당히 난해할 수 있다. 이는 직접 눈으로 보면서 각 설정 값을 이해하면 편한데 그림 [4]와 같이 각 축의 상대 좌표 변환이 RViz상에서 어떻게 표현되는지 살펴보고, 해당 값들을 변경해가며 RViz상의 변화를 살펴보는 것이 이해하는데 도움이 될 것이다. ***이건 생각으로만 이해되지 않는다. 꼭 직접 값을 변경해가며 테스트 해보기를 추천한다.*** ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMTE5/MDAxNjE1MTU3NTQzNzg0.wkYPUa20d_rumCvmnPUlQakbKurtEGoRbybmJbajmnUg.CFhPlcX6dYM6OlzVSnqq9jvL8q_RGT2YYlR3HJ5-e8wg.PNG/Selection_106.png?type=w1600) [그림 4: RViz에서 각 조인트와 링크의 모습] **5. URDF의 조인트(joint)** 다음으로 링크와 링크를 연결하는 **조인트(joint)** 태그에 대해서 알아보자. 조인트 태그는 그림 [5]와 같이 조인트의 특성을 기술한다. ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDRfMTQx/MDAxNjE0ODYzNDc0ODI2.OlOspoisUbJcwcPtbFwG9qj0m-bTgSfQgKErkrK2-l4g.ONBbKGf0Cu8FDnq24imG1JdqqdA5TRfYTH85VcpjvuAg.PNG/Selection_105.png?type=w1600) [그림 5: 조인트의 모델링 요소] 구체적으로는 **조인트 태그**에서는 **조인트의 이름, 종류**, 예를 들어 revolute(회전 운동 형), prismatic(병진 운동 형), continuous(연속 회전을 하는 휠), fixed(고정형), floating(비고정) 그리고 planar(축과 수직 방향으로 놓여진 평면상에서 움직이는 형태) 등을 기술한다. 그리고 **조인트를 기구적으로 연결하는 2개의 링크의 이름, 조인트의 위치, 회전 및 병진 운동 기준 축, 동작의 제한** 등도 기술한다. 연결하는 링크로는 부모 링크(parent link)와 자식 링크(child link)의 이름을 지정하는데 일반적으로 기저에 가까운 링크를 부모 링크라고 보면 된다. 다음 예제는 그 중 joint2에 해당되는 조인트에 대한 설정이다. 이해를 돕기 위하여 좀 더 자세히 살펴보자. joint2의 유형(type)은 회전 운동형 조인트인 revolute로 설정하였다. 부모 링크(parent link)는 link2로 자식 링크(child link)는 link3로 설정했다. 또한 origin에는 하나 전 조인트인 joint1의 좌표계를 원점으로 joint2의 좌표계의 상대 위치 자세(위치+방향)를 지정한다. 예를 들어 joint2 좌표계의 원점은 joint1 좌표계의 z축 방향으로 joint1에서 0.5m만큼 떨어진 위치이다. 다음은 축 설정이다. 축 설정인 axis에는 회전 운동형 조인트이면 회전 축의 방향, 병진 운동형 조인트이면 운동 방향을 기입한다. joint2의 경우, y축 방향으로 회전하는 조인트로 설정하였다. limit는 조인트 동작에 대한 제한 사항을 설정한다. 속성으로는 최소/최대 조인트 값(lower, upper, 단위: radian), 조인트에 주어지는 힘(effort, 단위: N), 속도(단위: rad/s)의 제한값을 설정 한다. * 참고로 2.617 radian은 약 150도이다. | **** | 링크와의 관계와 조인트 형태 설정 | | ------------ | ------------------------------------------------------------ | | **** | 조인트의 부모 링크 | | **** | 조인트의 자식 링크 | | **** | 부모 링크 좌표계를 자식 링크 좌표계로 변환 | | **** | 회전 축 설정 | | **** | 최소/최대 조인트 값, 조인트에 부여되는 힘, 속도 (조인트가 revolute 혹은 prismatic일 때만 적용) | [표 3: 조인트(joint) 태그에 속성] **6. URDF의 검토 작업** 로봇 모델 작성이 완료되면 각 링크와 조인트가 논리적으로 이상이 없는지 검토해보자. ROS에서는 다음의 예제처럼 **check_urdf** 명령어로 작성한 URDF의 문법적 오류 및 각 링크의 연결 관계를 확인할 수 있다. 문법, 논리적으로 문제 없이 작성되었다면 다음과 같이 링크 1, 2, 3, 4가 연결되어 있음을 확인할 수 있다. $ check_urdf testbot.urdf robot name is: testbot ---------- Successfully Parsed XML --------------- root Link: base has 1 child(ren) child(1): link1 child(1): link2 child(1): link3 child(1): link4 다음으로 **urdf_to_graphiz** 프로그램을 이용해 작성된 모델을 그래프로 나타내보자. 다음 예제처럼 urdf_to_graphiz를 실행하면 .gv 파일과 .pdf 파일이 생성된다. PDF 뷰어로 확인해보면 그림 [6]처럼 링크와 조인트와의 관계 및 각 조인트과 조인트 사이의 상대 좌표 변환을 한눈에 확인해 볼 수 있다. $ urdf_to_graphiz testbot.urdf Created file testbot.gv Created file testbot.pdf ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMjA5/MDAxNjE1MTU3ODI3MjM4.C3UiHNdBIexaL85eXLbSdXqZwYYp6n0ugEuiEne1RWsg.XnC-bTInofMaJkoSrU9UPLVA6b7hJdhRZiILoClZ2iUg.PNG/testbot_pdf.png?type=w1600) [그림 6: URDF의 link와 joint의 관계] **7. URDF의 런치 파일** check_urdf 및 urdf_to_graphiz으로 모델의 링크 관계를 확인하는 방법이 가장 빠르지만 시각적 정보가 부족하다. 더 자세히 모델을 확인해 보기 원한다면 RViz에서 로봇 모델을 확인해보자. 이를 위하여 우선 다음 예제와 같이 testbot_description 패키지 폴더로 이동해 testbot.launch.py 파일을 생성해보자. $ cd ~/robot_ws/src/testbot_description $ mkdir launch $ cd launch $ nano testbot.launch.py > testbot_description/launch/testbot.launch.py > > https://github.com/robotpilot/ros2-seminar-examples/testbot_description import os from ament_index_python.packages import get_package_share_directory from launch import LaunchDescription from launch_ros.actions import Node def generate_launch_description(): rviz_display_config_file = os.path.join( get_package_share_directory('testbot_description'), 'rviz', 'testbot.rviz') urdf_file = os.path.join( get_package_share_directory('testbot_description'), 'urdf', 'testbot.urdf') with open(urdf_file, 'r') as infp: robot_description_file = infp.read() ld = LaunchDescription() robot_state_publisher = Node( package='robot_state_publisher', executable='robot_state_publisher', parameters=[ {'use_sim_time': False}, {'robot_description': robot_description_file} ], output='screen') joint_state_publisher_gui = Node( package='joint_state_publisher_gui', executable='joint_state_publisher_gui', output='screen') rviz2 = Node( package='rviz2', executable='rviz2', arguments=['-d', rviz_display_config_file], output='screen') ld.add_action(robot_state_publisher) ld.add_action(joint_state_publisher_gui) ld.add_action(rviz2) return ld 런치 파일에는 URDF를 담은 **robot_description 파라미터**와 **joint_state_publisher_gui** [18]노드 그리고 **robot_state_publisher** [19]노드로 구성되어 있다. **joint_state_publisher_gui** 노드는 URDF로 만들어진 로봇의 **조인트 상태(joint_state)**를 sensor_msgs/msg/JointState 메시지 형태로 퍼블리시 해주는 역할을 하며 조인트에 명령을 주는 GUI 툴을 제공한다. **robot_state_publisher** 노드는 URDF에 설정된 로봇 정보와 sensor_msgs/msg/JointState 토픽 정보를 가지고 계산한 forward kinematics 결과인 **TF**를 geometry_msgs/msg/TransformStamped 메시지 형태로 퍼블리시 해주는 역할을 한다(그림 [7] 참조). ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMTk0/MDAxNjE1MTYwMTY5MDk3.fULbKhzLUkD6b3_OZiVH-BBuz0zUzdiHWeJVap2595cg.J3d2xMzmk6Bj9F0w8TwCPhOMkGgyHYTkxfH4r8HEqqQg.PNG/rqt_graph_urdf.png?type=w1600) [그림 7: joint_state_publisher_gui 노드와 robot_state_publisher 노드의 토픽] **8. 그 외 rviz 파일 및 빌드 설정 파일** 지금까지 우리는 testbot_description 패키지를 생성하였고 urdf 폴더를 만들어 testbot.urdf 만들었다. 그리고 위에서 이를 실행하기 위한 launch 폴더를 만들고 testbot.launch.py 런치 파일을 만들어보았다. 여기에 rviz 디스플레이 설정 파일을 생성하고 빌드 설정 파일인 CMakeLists.txt 을 약간 수정해줘야 한다. 이는 하기 리포지토리의 원본 파일을 참고하여 추가로 변경하도록 하자. > testbot_description > > https://github.com/robotpilot/ros2-seminar-examples/testbot_description 참고로 예제로 작성한 testbot_description 패키지는 하기와 같은 패키지를 의존하고 있기에 빌드 전에 설치해주자. $ sudo apt install ros-foxy-joint-state-publisher ros-foxy-joint-state-publisher-gui ros-foxy-robot-state-publisher **9. 빌드 및 실행** 자. 모든 준비가 완료되었다면 다음과 같이 빌드를 먼저 하고 testbot.launch.py 런치 파일을 실행하자. $ cd ~/robot_ws/ $ colcon build --symlink-install $ roslaunch testbot_description testbot.launch.py $ rviz 런치 파일이 실행되면 그림 [8]과 같이 joint_state_publisher_gui 노드의 GUI도 함께 실행된다. 여기서 joint 1, 2, 3의 조인트 값을 사용자가 조절할 수 있고 함께 실행된 RViz에서 각 조인트과 링크의 모습을 확인할 수 있다. 더불어 'TF' 디스플레이를 추가해주고 로봇 모델의 'Alpha'값을 0.3정도로 수정해주면 그림 [9]과 같이 각 링크의 형상과 조인트간의 관계를 확인해 볼 수도 있다. 그리고 joint_state_publisher_gui 노드의 GUI 막대를 조정하면 그림 [10]과 같이 RViz상의 가상 로봇이 동작되는 것을 확인해 볼 수 있다. ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMzIg/MDAxNjE1MTU3OTc3MDg2.e_aO1pSg5MbdGgB8yq00v9WOgJr1fb6jkUmWd2aOp6Mg.mziBG5m4t65SDMIECdiiz4szOOibC-TqB5WtjORIwF0g.PNG/Selection_004.png?type=w1600) [그림 8: Joint State Publisher의 GUI] ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMTI2/MDAxNjE1MTU3OTk0MTIy.CuhmVyrxtZUB9R8VuBJifrH8VcFBpCodvP_xVMWhpTUg.fBFoW3w4jA4VUtFW_UaSpmQgaYad-AxQKB6_8BbWwYcg.PNG/Selection_006.png?type=w1600) [그림 9: RViz에서 각 조인트와 링크의 모습] ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMTIx/MDAxNjE1MTU4MDExMzY4.8nJxPcVVcKAcsWKgv5_e-9tyitU_Z3wAWTtuF0TJ0Twg.n4sdbrb-up_0ARARnmOWyIlEdw8TAab-Bsm2ODkHKlAg.PNG/Selection_005.png?type=w1600) [그림 10: Joint State Publisher GUI 도구에서 각 조인트를 조종한 결과] **10. 모바일 로봇 및 매니퓰레이터의 URDF** 앞서 간단한 3축 매니퓰레이터를 URDF 형식에 맞게 모델링하여 RViz로 확인해 보았다. 이번에는 모바일 로봇이나 다른 로봇들의 URDF 구성 및 사용법에 대해서 알아보자. 우선 모바일 로봇이다. 모바일 로봇이 앞서 다룬 매니퓰레이터와 동작이나 외형은 달라 보이지만 링크와 조인트로 표현하는 것은 동일하다. 틀린점이 있다면 동적으로 이동하는 조인트가 revolute(회전 운동 형)가 아닌 continuous(연속 회전을 하는 휠) 형태라는 것이다. 그 이외 모바일 로봇의 기구, 바퀴, 캐스터, 센서류는 동적 움직임을 가지지 않는 고정형이기에 링크라고 볼 수 있다. 일반적인 Differential Drive 형태의 2륜 구동 모바일 로봇의 일반적인 형태는 다음과 같은 TurtleBot3 처럼 구성한다. odom은 odometry의 약자로 사용하며 일반적으로 매니퓰레이터가 기저라는 것에 고정하여 이용하는 형태라면 모바일 로봇은 고정이 아닌 좌, 우 모터가 회전 동작을 하며 이동하는 로봇으로 odom은 world 또는 map 이라는 특정 좌표로부터 이동한 상대 위치의 좌표라고 보면 된다. 그 위에 로봇의 좌/우 회전축의 중심부가 바닥면에 맞닫는 좌표를 base_footprint 이라하며 그 base_footprint에서 로봇의 실제 기구부에 닫는 로봇의 밑바닥을 base_link 이라 일반적으로 정의한다. base_link 링크에는 수동적 움직임을 같는 caster_back_link와 같은 부품이나 imu_link, camera_link, base_scan과 같은 센서류가 있고 이들 또한 하나씩 조인트가 있지만 fixed 형태로 고정되어 있다. 그리고 wheel_left_link 와 wheel_right_link과 같은 움직임을 갖는 요소도 있는데 이들은 wheel_left_joint, wheel_right_joint에 의해 동적 움직임을 갖게 된다. 이를 TF Tree 형태로 도식화하면 그림 [11]과 같다. 1) 기본 링크: odom ---> base_footprint ---> base_link 2) 고정 링크: caster_back_link, imu_link, camera_link, base_scan 3) 동적 링크: wheel_left_link, wheel_right_link ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMTk5/MDAxNjE1MTYwNDkyODA4.2xS_dBp-qcxLdFMqFbIBzibdYRR2p5r1rb_6IbcGJ_kg.QqOv4tj9IQjVItdyejE3ODF4VHOol2RotKVA7GUWez0g.PNG/Selection_108.png?type=w1600) [그림 11: TurtleBot3의 TF 구성] 위에서 설명한 모바일 로봇의 대표적인 예로 TurtleBot3의 모델을 RViz에서 확인해보자. 이를 위한 과련 패키지 설치는 아래와 같으며 turtlebot3_fake_node 패키지에서 RViz와 함께 실행시키면 그림 [12]와 같이 확인해볼 수 있다. $ sudo apt install ros-foxy-turtlebot3 ros-foxy-turtlebot3-msgs ros-foxy-turtlebot3-simulations ros-foxy-dynamixel-sdk $ export TURTLEBOT3_MODEL=burger $ ros2 launch turtlebot3_fake_node turtlebot3_fake_node.launch.py ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMzkg/MDAxNjE1MTU4MDk1ODcy.FQVuxkCo2DkOcAZz7htGMqrx1jrOwyCVXD9AmpHSe3Ag.DKFEqfNwE_FOw2MtS5gAdhOPRdt2MJPxhLN-gSHqigQg.PNG/Screenshot_from_2021-03-04_19-38-03.png?type=w1600) [그림 12: turtlebot3_fake_node 실행 화면] 앞서 나무 젓가락을 이어 붙인 간단한 모양의 3축 매니퓰레이터를 URDF 실습으로 작성해 보았는데 이번 TurtleBot3에서는 모양이 비교적 복잡하고 자세하다는 것을 확인할 수 있다. 이는 태그의 태그에 사각 기둥(box)형, 원통형(cylinder), 구형(sphere) 등 단순한 형태의 모형을 기입했었는데 여기서는 간단한 모양으로 표현하기 어렵기 때문에 태그를 이용하여 3차원 CAD 파일을 입력하였다. 이 뒤에 기술하는 OpenManipulator나 다른 로봇들의 외형도 태그를 사용하여 3차원 CAD 파일을 사용한 것이다. > turtlebot3_burger.urdf > > https://github.com/ROBOTIS-GIT/turtlebot3/blob/foxy-devel/turtlebot3_description/urdf/turtlebot3_burger.urdf (이하 생략) 위 turtlebot3_burger.urdf 에서 사용한 burger_base.stl은 그림 13과 같은 메쉬타입의 3D 설계 파일이다. 그 이외에 바퀴, 라이다 등의 구성요소는 별도의 stl 파일들을 불러오게 된다. ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMjQw/MDAxNjE1MTU4MjAzMjMz.yvry1xGa05MijKPzu4N6p4uWHZLk_VWyF6gPTHcfhFAg.5jGy9Ain_K776MDnal1lEByCp9t8gXBEqAIzn5Zel6Qg.PNG/Selection_101.png?type=w1600) [그림 13: burger_base.stl의 모습] 이번에는 시각화 툴 RViz가 아닌 3차원 시뮬레이터 Gazebo에서 로봇 모델을 불러와 보도록 하자. 다음 예제와 같이 launch 파일을 실행하면 앞에서 다룬 RViz를 이용한 시뮬레이션과 동일할 것이다. 하지만 Gazebo 에서는 URDF가 아닌 SDF를 이용하여 가상 로봇의 외형만을 갖춘 게 아니라, 몸체의 충돌을 체크할 수 있고, 위치를 계측하고, IMU 센서, 카메라 센서를 가상으로 사용할 수 있게 설정되어 있다. 이는 시뮬레이션을 위한 SDF 파일만의 태그로 센서를 추가하고 태그에서 가지보의 다양한 플러그인을 사용할 수 있도록 설정하였기 때문이다. 어떻게 구성되어 있는지는 아래 링크를 참고 하도록 하자. > model.sdf > > https://github.com/ROBOTIS-GIT/turtlebot3_simulations/blob/foxy-devel/turtlebot3_gazebo/models/turtlebot3_burger/model.sdf 하기와 같이 empty_world.launch.py 런치 파일을 이용하면 그림 [14]와 같이 3차원 시뮬레이터 Gazebo에서 TurtleBot3 모델을 확인할 수 있다. $ export TURTLEBOT3_MODEL=burger $ ros2 launch turtlebot3_gazebo empty_world.launch.py 위에서 기본으로 로봇만 Gazebo에서 불러와 봤는데 아래와 같이 가상 환경 파일도 SDF로 구성하여 불러올 수도 있다. 그림 [15]는 turtlebot3_world 라는 가상 환경 파일과 함께 불러왔으며 그림 [16]은 turtlebot3_house 라는 가상 환경 파일과 함께 로봇 모델을 불러온 것이다. $ export TURTLEBOT3_MODEL=waffle $ ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py $ export TURTLEBOT3_MODEL=waffle_pi $ ros2 launch turtlebot3_gazebo turtlebot3_house.launch.py ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfNjgg/MDAxNjE1MTU4MjQxMzQ1.rpTTqPb1E1_xEE7KaGGrdHc1Gej2KzkGiVcY-Bi2rNcg.vtA3RBfNt-hihnXdc-WHDjEwq9XgZX3ceTNmlvQE-1Qg.PNG/turtlebot3_empty_world.png?type=w1600) [그림 14: Gazebo 시뮬레이션 공간의 TurtleBot3 (empty_world)] ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMTE2/MDAxNjE1MTU4MjUyNTUy.5FSuQ5wiGvI0PslewPggbiAMINFB5qmRkij3yJDCkygg.FGBuLWN3kIChYcbKP_iDNfUW8bglrGjmYo7scGD5RGEg.PNG/Screenshot_from_2021-03-04_20-07-54.png?type=w1600) [그림 15: Gazebo 시뮬레이션 공간의 TurtleBot3 (turtlebot3_world)] ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMTEx/MDAxNjE1MTU4MzEzNTQ2.txyz9v-nj9Leqj3WQJsc8gkaFjOPHTdKZDTtsr1J6Kcg.Xm63_WQVIdgbgAhcezBbLFMG4M92OlIvxRrsPlkVUlEg.PNG/Screenshot_from_2021-03-04_20-01-36.png?type=w1600) [그림 16: Gazebo 시뮬레이션 공간의 TurtleBot3 (turtlebot3_house)] 이러한 모바일 로봇 이외에도 그림 [17]과 같이 매니퓰레이터를 모델링하여 사용할 수 있으며 모바일 로봇과 매니퓰레이터의 모델을 결합하여 그림 [18]과 같이 모바일 매니퓰레이터로 사용하 수 있도 있다. 이렇게 결합할 수 있는 것은 URDF의 TF Tree 구조를 변경하는 것만으로도 결합할 수 있는데 예를 들어 아래 URDF 예제 코드와 같이 매니퓰레이터의 기저 부분을 모바일 로봇의 일부분에 결합시키는 것으로 두개의 별개의 로봇 모델을 하나로 합칠 수 있다. ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMSAg/MDAxNjE1MTU4MzU1MTQx.rJaLZz1RxBAlQevFrUfrwGfgU9_83tUwtZ9IbCOQ1yAg.dXmlPs5WpqG0qepbocdK5YYdjYZjGV_b5tWT6Dg25-Ig.PNG/OpenManipulator_Chain_gazebo_2.png?type=w1600) [그림 17: Gazebo 시뮬레이션 공간의 OpenManipulator X] ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMjEx/MDAxNjE1MTU4MzYxODk3.7UmyhvqOHo73D33be0S6Ie6lvLO6FqpJPuRDCkJW12Mg.DrL9ccE2UbFXaT8Z4jPaPlmOtWtPABRbdgy_zj8D1SAg.PNG/open_manipulator_gazebo_1.png?type=w1600) [그림 18: TurtleBot3와 OpenManipulator X 결합으로 만들어진 모바일 매니퓰레이터] **11. URDF와 함께 사용할 수 있는 툴** **11.1 URDF for VSCode** IDE로 널리 쓰이는 VSCode에 URDF 작성 및 뷰어를 지원하는 확장기능이 있다. [20] 링크를 참조하여 VSCode의 extension 으로 설치하여 그림 19와 같이 URDF를 작성하는 기본 템플릿으로 사용할 수도 있다. ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMTMw/MDAxNjE1MTYxNzE2NDI1.ys2M8PWaaNr04j2zccMt2eykz3g5i0vHZSjpRv14FSUg.CTffyIw-eK0o2MBRUXu9J-aWN13ZOrNu2PYWd-nJ4Y8g.GIF/snippets.gif?type=w1600) [그림 19: URDF for VSCode] 작성된 URDF 파일은 'Ctrl + Shift + p' 입력 후 'ROS: Preview URDF'을 실행시키면 그림 [20]과 같이 URDF를 편집기에서 바로 확인하여 디버깅하기 쉽게 된다. 유용한 툴이니 URDF 작성에 참고하도록 하자. ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfNzYg/MDAxNjE1MTU4Nzk0Njgx.FJOyrAQDRtpIbBHZCUKJIc0iRERLRa4Z68i0DXNJ6_Ig.7HAdjVUBDm-qdpAwQtv7O1eet1nK4psAYLxS64iOG4Ag.PNG/Selection_107.png?type=w1600) [그림 20: VSCode에서 URDF 모델을 확인할 수 있는 URDF Preview] **11.2 XACRO** xacro 파일은 XML Macro [21]의 줄임말로 반복되는 코드를 불러올 수 있는 매크로 언어이다. URDF는 링크와 조인트의 연속적인 구조를 나타내기 위해 반복적인 구문이 많아 수정할 때 손이 많이 간다는 단점을 가지고 있다. 하지만 xacro 를 활용하면 이러한 작업을 많이 줄일 수 있다. 그 예로 원주율 변수를 설정하거나 또는 앞서 만든 물질 정보 파일과 Gazebo 설정 파일은 따로 관리하며 실제 사용할 파일에 포함시키는 방법 등 효율적으로 코드를 관리할 수 있다. **11.3 urdf_exporter** 3차원 기구 설계 소프트웨어인 SolidWorks에서는 설계한 3차원 모델을 바로 URDF로 출력해주는 플러그인[22]을 제공하고 있다. 이는 복잡한 기구 설계물의 URDF 변환에 유용하니 참고하도록 하자. **11.4 tf2_tools** ROS 2에서는 ROS 1에서 사용하던 rqt_tf_tree를 제공하고 있지 않는데 tf2_tools 패키지에서 비슷한 기능의 TF tree view를 제공하고 있다. 설치 방법은 다음과 같으며 우리가 작성한 testbot_description 패키지의 testbot.launch.py 런치 파일을 실행한 후 tf2_tools 패키지의 view_frames.py 파일을 실행시키면 그림 [21]과 같이 TF Tree 형태로 URDF를 확인할 수 있다. $ sudo apt install ros-foxy-tf2-tools $ roslaunch testbot_description testbot.launch.py $ ros2 run tf2_tools view_frames.py $ evince frames.pdf ![img](https://cafeptthumb-phinf.pstatic.net/MjAyMTAzMDhfMTIx/MDAxNjE1MTYyNDEwNTEy.RhZ6O8daET5zuVWEmzmDXIfql39tXoH06Ye0EOXp_scg.-FnS5I6A-qf47Uuurzf4oAXQR4zXQJ3UrqeMwkx7PXAg.PNG/testbot_frame_pdf.png?type=w1600) [그림 21: tf2_tools 패키지의 view_frames 실행 모습] **12. 맺음말** 이상으로 이 강좌에서는 URDF를 가지고 실제 모바일 로봇 및 매니퓰레이터 로봇을 시각화 및 가상공간에서 시뮬레이션 할 수 있도록 로봇의 각 구성 요소를 모델링하는 방법에 대해 알아보았고 URDF 작성 및 디버깅에 필요한 툴들의 사용법에 대해 알아보았다. URDF를 이용하여 로봇을 모델링하는 것은 로봇 프로그래밍에 앞서서 매우 중요한 부분으로 충분한 연습이 필요하다. 본 강좌에서 예제로 사용한 testbot_description 패키지[24]를 마음껏 변형해보기를 추천하며 본 강좌에서 예제로 언급된 TurtleBot3 [25] 및 OpenManipulator X [26]는 모든 모델링 파일 및 3차원 설계 파일을 공개하고 있어서 이를 가지고 RViz 또는 Gazebo와 함께 실행해보고 변형도 해보면서 연습을 충준히 하도록 하자. **[참고 자료]** [1] 로봇 운영체제 ROS 강좌 목차: https://cafe.naver.com/openrt/24070 [2] http://wiki.ros.org/urdf [3] http://wiki.ros.org/rviz [4] http://gazebosim.org/ [5] 051 TF, https://cafe.naver.com/openrt/25391 [6] https://wiki.ros.org/tf2 [7] http://sdformat.org/ [8] http://wiki.ros.org/srdf [9] http://gazebosim.org/tutorials/?tut=ros_urdf [10] https://wiki.ros.org/urdf/XML [11] https://wiki.ros.org/urdf/XML/robot [12] https://wiki.ros.org/urdf/XML/link [13] https://wiki.ros.org/urdf/XML/joint [14] https://wiki.ros.org/urdf/XML/Transmission [15] https://wiki.ros.org/ros_control [16] https://en.wikipedia.org/wiki/Moment_of_inertia [17] http://gazebosim.org/blog/four_physics [18] https://github.com/ros/joint_state_publisher/tree/foxy [19] https://github.com/ros/robot_state_publisher/tree/foxy [20] https://marketplace.visualstudio.com/items?itemName=smilerobotics.urdf [21] http://wiki.ros.org/xacro [22] http://wiki.ros.org/sw_urdf_exporter [23] https://github.com/ros2/geometry2/tree/foxy/tf2_tools [24] https://github.com/robotpilot/ros2-seminar-examples [25] https://emanual.robotis.com/docs/en/platform/turtlebot3/simulation/ [26] https://emanual.robotis.com/docs/en/platform/openmanipulator_x/overview/