gazebo/Nav2

nav2 - Setting Up URDF

정지홍 2025. 4. 15. 11:58

https://docs.nav2.org/setup_guides/urdf/setup_urdf.html#

 

Setting Up The URDF — Nav2 1.0.0 documentation

Note Note that you will also be setting up a SDF for simulation in Gazebo in the next tutorials. URDF is used to set up the robot frames and describe the robot’s structure for run-time use on hardware and possibly in simulation. SDF is a specific file fo

docs.nav2.org

 

 

  • 해당되는 튜토리얼에서는 URDF파일을 이용하여 간단한 differential drive robot을 만들어 볼것이다.
    • 또한 로봇의 state publisher와 RVIZ 시각화를 위한 세팅도 할 것이다.
    • 마지막에는 시뮬레이션이라는 목적에 맞게, kinematic 속성을 urdf파일에 추가할 것 이다.
      • 이러한 과정들은 네비게이션에서 센서,hw,robot transform을 사용하기 위해서 필요하다.

 

  • 우리는 https://jihong.tistory.com/591의 튜토리얼에서 말했듯이, nav2를 사용하기 위해서는 base_link에서 다양한 센서들을 기준 좌표 프레임으로의 transform이 필요합니다.
  • transform tree는 단순하게 링크가 1개몬 존재하는 구조일수 있으며( base_link --> laser_link ), 여러 위치에 여러 센서들이 각각의 좌표프레임을 가진 상태로 설치되어 있는 복잡한 구조일 수도 있다.
    • 이러한 모든 좌표의 변환을 처리하기 위해서 publisher를 각각 만드는 것은 번거러울 것이다. 그래서 우리는 Robot_state_Publisher 패키지를 사용해서 publish할 것이다.
  • ROS_State_Publisher
    • ROS2의 패키지이다.
    • tf 패키지와 상호작용하며 로봇의 기하학적 구조로부터 직접 유추할 수 있는 모든 필요한 좌표 변환을 publish한다.
    • 해당 패키지에 올바른 URDF파일을 제공하면, transform publish를 자동으로 해준다.

우선 튜토리얼 마지막에는 이러한 디렉토리 구조가 되어있을 것이다.

 

 

 

 


1. URDF 파일 생성

 

  • 우선 로봇 본체의 크기를 정의한다. base_link의 가로 세로 높이이다.

 

  • 바퀴의 반지름 , 바퀴 두께 , 바퀴와 본체 사이의 y축 거리 , 바닥을 기준으로 바닥의 높이 , 바퀴의 x축 위치

 

  • 앞쪽 캐스터의 x축 위치이다. 캐스터는 회전이 가능한 바퀴이다.

 

  • link는 로봇의 물리적 구성요소이다.
  • visual은 gazebo에서 보이게 될 3d모양
  • geometry는 박스 형상
  • material에서 색상을 지정중

 

  • 시뮬레이션 상에서는 보이지 않는 가상의 링크이다. 로봇이 바닥에 투영되었을때 중심점 역할을 수행

 

  • fixed 조인트로 base_link와 base_footprint를 연결한다.
  • z축의 위치는 로봇 바닥이 지면에 닿도록 설정한다. ${ -( wheel_radius + wheel_zoof ) }

 

  • 바퀴 생성을 위한 매크로를 정의
    • params에서 'prefix는 바퀴 이름 앞에 붙일 식별자'이며 'x_reflect와 y_reflect'는 x,y축을 기준으로 좌우/앞뒤 대칭 위치를 계산
    • 바퀴는 원통형으로 정의하며, rpy로 x축을 중심으로 90도 회전 시켜서 바퀴가 y축을 따라서 회전하도록 설정
    • joint는 continuos로 회전이 가능하게
    • axis는 y축을 기준으로 회전함을 의미
<?xml version="1.0"?>
<robot name="sam_bot" xmlns:xacro="http://ros.org/wiki/xacro">
	  <!-- Define robot constants -->
  <xacro:property name="base_width" value="0.31"/>
  <xacro:property name="base_length" value="0.42"/>
  <xacro:property name="base_height" value="0.18"/>

  <xacro:property name="wheel_radius" value="0.10"/>
  <xacro:property name="wheel_width" value="0.04"/>
  <xacro:property name="wheel_ygap" value="0.025"/>
  <xacro:property name="wheel_zoff" value="0.05"/>
  <xacro:property name="wheel_xoff" value="0.12"/>

  <xacro:property name="caster_xoff" value="0.14"/>

  <!-- Robot Base -->
  <link name="base_link">
    <visual>
      <geometry>
        <box size="${base_length} ${base_width} ${base_height}"/>
      </geometry>
      <material name="Cyan">
        <color rgba="0 1.0 1.0 1.0"/>
      </material>
    </visual>
  </link>

  <!-- Robot Footprint -->
  <link name="base_footprint"/>

  <joint name="base_joint" type="fixed">
    <parent link="base_link"/>
    <child link="base_footprint"/>
    <origin xyz="0.0 0.0 ${-(wheel_radius+wheel_zoff)}" rpy="0 0 0"/>
  </joint>

  <!-- Wheels -->
  <xacro:macro name="wheel" params="prefix x_reflect y_reflect">
    <link name="${prefix}_link">
      <visual>
        <origin xyz="0 0 0" rpy="${pi/2} 0 0"/>
        <geometry>
            <cylinder radius="${wheel_radius}" length="${wheel_width}"/>
        </geometry>
        <material name="Gray">
          <color rgba="0.5 0.5 0.5 1.0"/>
        </material>
      </visual>
    </link>

    <joint name="${prefix}_joint" type="continuous">
      <parent link="base_link"/>
      <child link="${prefix}_link"/>
      <origin xyz="${x_reflect*wheel_xoff} ${y_reflect*(base_width/2+wheel_ygap)} ${-wheel_zoff}" rpy="0 0 0"/>
      <axis xyz="0 1 0"/>
    </joint>
  </xacro:macro>

  <xacro:wheel prefix="drivewhl_l" x_reflect="-1" y_reflect="1" />
  <xacro:wheel prefix="drivewhl_r" x_reflect="-1" y_reflect="-1" />

  <!-- Caster Wheel -->
  <link name="front_caster">
    <visual>
      <geometry>
        <sphere radius="${(wheel_radius+wheel_zoff-(base_height/2))}"/>
      </geometry>
      <material name="Cyan">
        <color rgba="0 1.0 1.0 1.0"/>
      </material>
    </visual>
  </link>

  <joint name="caster_joint" type="fixed">
    <parent link="base_link"/>
    <child link="front_caster"/>
    <origin xyz="${caster_xoff} 0.0 ${-(base_height/2)}" rpy="0 0 0"/>
  </joint>


</robot>

2. launch파일

from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.conditions import IfCondition, UnlessCondition
from launch.substitutions import Command, LaunchConfiguration
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
import os

def generate_launch_description():
    # sam_bot_description이라는 ros 패키지에서 공유 디렉토리 경로를 찾는다.
    pkg_share = FindPackageShare(package='sam_bot_description').find('sam_bot_description')
    # 로봇 모델 URDF 파일의 기본 경로를 정의
    default_model_path = os.path.join(pkg_share, 'src', 'description', 'sam_bot_description.urdf')
    # rviz 설정 파일의 경로를 정의
    default_rviz_config_path = os.path.join(pkg_share, 'rviz', 'config.rviz')

    # robot_state_publisher 노드를 정의합니다. 
    robot_state_publisher_node = Node(
        package='robot_state_publisher', # 패키지 이름 ( 반드시 실존하는 ros패키지 이름 명시)
        executable='robot_state_publisher', # 실행할 노드 이름 ( 위의 package안에 있는 실행 파일 이름을 지정)
        # parameters는 노드를 실행할때 전달할 파라미터 목록이다.
        parameters=[{'robot_description': Command(['xacro ', LaunchConfiguration('model')])}]
    )
    joint_state_publisher_node = Node(
        package='joint_state_publisher',
        executable='joint_state_publisher',
        name='joint_state_publisher',
        parameters=[{'robot_description': Command(['xacro ', default_model_path])}],
        condition=UnlessCondition(LaunchConfiguration('gui'))
    )
    joint_state_publisher_gui_node = Node(
        package='joint_state_publisher_gui',
        executable='joint_state_publisher_gui',
        name='joint_state_publisher_gui',
        condition=IfCondition(LaunchConfiguration('gui'))
    )
    rviz_node = Node(
        package='rviz2',
        executable='rviz2',
        name='rviz2',
        output='screen',
        arguments=['-d', LaunchConfiguration('rvizconfig')],
    )

    # 최종적으로 launchDescription 객체를 생성하여, 모든 액션을 리스트로 반환
    return LaunchDescription([
        # gui인자 선언
        DeclareLaunchArgument(name='gui', default_value='True', description='Flag to enable joint_state_publisher_gui'),
        # model 이자를 선언
        DeclareLaunchArgument(name='model', default_value=default_model_path, description='Absolute path to robot model file'),
        # rviz 설정
        DeclareLaunchArgument(name='rvizconfig', default_value=default_rviz_config_path, description='Absolute path to rviz config file'),
        joint_state_publisher_node,
        joint_state_publisher_gui_node,
        robot_state_publisher_node,
        rviz_node
    ])

 

 


3. package.xml 수정

<exec_depend>joint_state_publisher</exec_depend>
<exec_depend>joint_state_publisher_gui</exec_depend>
<exec_depend>robot_state_publisher</exec_depend>
<exec_depend>rviz</exec_depend>
<exec_depend>xacro</exec_depend>

 


4. rviz.config 생성

Panels:
  - Class: rviz_common/Displays
    Help Height: 78
    Name: Displays
    Property Tree Widget:
      Expanded:
        - /Global Options1
        - /Status1
        - /RobotModel1/Links1
        - /TF1
      Splitter Ratio: 0.5
    Tree Height: 557
Visualization Manager:
  Class: ""
  Displays:
    - Alpha: 0.5
      Cell Size: 1
      Class: rviz_default_plugins/Grid
      Color: 160; 160; 164
      Enabled: true
      Name: Grid
    - Alpha: 0.6
      Class: rviz_default_plugins/RobotModel
      Description Topic:
        Depth: 5
        Durability Policy: Volatile
        History Policy: Keep Last
        Reliability Policy: Reliable
        Value: /robot_description
      Enabled: true
      Name: RobotModel
      Visual Enabled: true
    - Class: rviz_default_plugins/TF
      Enabled: true
      Name: TF
      Marker Scale: 0.3
      Show Arrows: true
      Show Axes: true
      Show Names: true
  Enabled: true
  Global Options:
    Background Color: 48; 48; 48
    Fixed Frame: base_link
    Frame Rate: 30
  Name: root
  Tools:
    - Class: rviz_default_plugins/Interact
      Hide Inactive Objects: true
    - Class: rviz_default_plugins/MoveCamera
    - Class: rviz_default_plugins/Select
    - Class: rviz_default_plugins/FocusCamera
    - Class: rviz_default_plugins/Measure
      Line color: 128; 128; 0
  Transformation:
    Current:
      Class: rviz_default_plugins/TF
  Value: true
  Views:
    Current:
      Class: rviz_default_plugins/Orbit
      Name: Current View
      Target Frame: <Fixed Frame>
      Value: Orbit (rviz)
    Saved: ~

5. CMakeList.txt에 다음 내용 추가

install(
  DIRECTORY src launch rviz
  DESTINATION share/${PROJECT_NAME}
)

 

 


colcon build
. install/setup.bash

ros2 launch sam_bot_description display.launch.py