본문 바로가기
로봇 이야기/ros2

ROS2 URDF 시뮬레이션(simulation) workspace 만들기

by 노땅엔진니어 2022. 12. 13.

로봇을 만드는데 설계를 하고 부품을 구입하고 조립하면서 동작을 여러가지로 시도하면서 할 수 있습니다. 로봇이란 것이 물리적으로 동작을 하기 때문에 예기치 않은 동작에 부품이 고장나거나 망가지면 돈과 시간을 허비하게 됩니다.

ROS2와 연동하여 로봇 시뮬레이션을 할 수 있는 프로그램이 가제보(gazebo) 입니다. ROS2와 가제보에서 시뮬레이션을 위한 작업공간(workspace)를 만드는 방법입니다.

1. 가제보(gazebo) 프로그램 설치

가제보의 Fortress(발표일 : Sep 2021, EOL : Sep 2026) 버전을 설치 합니다. 가제보를 설치하기 위해서는 루트 권한을 갖고 있어야 하고 다음과 같이 먼저 필수 패키지를 설치 합니다.

$ sudo apt update
$ sudo apt install lsb-release wget gnupg

가제보(gazebo)는 우분투 기본 저장소에서 지원을 하지 않고 별도의 저장소를 사용 합니다. 다음과 같이 키와 저장소를 추가 합니다.

$ sudo wget https://packages.osrfoundation.org/gazebo.gpg -O /usr/share/keyrings/pkgs-osrf-archive-keyring.gpg
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/pkgs-osrf-archive-keyring.gpg] http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/gazebo-stable.list > /dev/null

저장소가 등록되면 가제보 프로그램을 설치 할 수 있습니다.

$ sudo apt update
$ sudo apt install ignition-fortress

가제보 프로그램 삭제

가제보 프로그램은 다음과 같이 삭제를 할 수 있습니다.

$ sudo apt remove ignition-fortress && sudo apt autoremove

2. ROS2 작업공간 만들기

우분투에 ROS2 설치를 하면 설치된 디렉토리는 /opt/ros 입니다. ros 밑에는 ros의 설치된 버전의 코드네임으로 디렉토리가 생성되고 설치 됩니다. ros2-foxy 버전이 설치되었다면 /opt/ros/foxy 디렉토리가 보일 것이고 ros2의 환경설정은 다음과 같습니다.

$ source /opt/ros/foxy/setup.bash

ROS2로 프로그램을 작성할 때 가장 먼저 작업공간(workspace)를 만들어야 합니다. 적당한 디렉토리를 생성한 후에 디렉토리에서 다음 명령을 실행 합니다.

$ colcon build

작업공간이라고 해서 거창한 것은 아니고 하위 디렉토리에 build, install, log 디렉토리가 생성 됩니다. install 디렉토리 밑에는 이 작업공간을 ROS2에서 인식할 수 있도록 환경 설정을 위한 쉘파일이 있습니다. /opt/ros/foxy/setup.bash 파일은 ROS2의 전역(global) 환경설정이라면 이 작업공간을 로컬(local) 환경설정은 다음과 같습니다.

$ source ./install/local_setup.bash

 

매번 실행하는 것이 귀찮다면 .bashrc 파일에 추가를 해도 됩니다. 다만, 여러 개의 작업공간을 만들어 놓았을 때는 터미널을 열 때마다 실행하는 것이 좋습니다.

3. ROS2 패키지(package) 만들기

ROS2의 패키지 생성은 ros2 유틸리티를 통해서 만들 수 있습니다. 작업공간(workspace)에서 다음과 같이 실행을 합니다.

$ ros2 pkg create --build-type ament_cmake manipulator

--build-type에는 대표적으로 ament_cmake와 ament_python이 있습니다. 위와 같이 패키지를 생성하면 비어있는 패키지가 하나 생성 됩니다.

4. URDF 시뮬레이션 환경 만들기

URDF(Unified Robot Description Format)는 ROS2에서 로봇을 시뮬레이션을 하기 위한 로봇을 설명한 파일 입니다. 이 문서에서는 URDF를 ROS2에서 시뮬레이션 화면까지 실행하는 것을 목표로 합니다.

위에서 manipulator라는 패키지가 생성되면 작업공간(workspace) 밑에 manipulator 이름으로 디렉토리가 생성 됩니다. 시뮬레이션을 위해서는 manipulator 디렉토리에 추가 디렉토리를 생성해야 합니다.

$ cd manipulator
$ mkdir config launch maps meshes models params rviz urdf worlds
$ cd ..

예제 URDF 파일

다음 manipulator.urdf를 manipulator/urdf 디렉토리에 생성을 합니다.

<?xml version="1.0" ?>
<robot name="manipulator" xmlns:xacro="http://ros.org/wiki/xacro">

</robot>

package.xml 파일

ros2에서 패키지를 생성하면 패키지 디렉토리에 package.xml 파일이 생성됩니다. 패키지에 대한 속성 및 설명을 하며 시뮬레이션에 필요한 속성을 <buildtool_depend>ament_cmake</buildtool_depend> 라인 밑에 다음과 같이  추가를 합니다.

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

위에서 "joint_state_publisher" 패키지를 추가로 설치를 해 주어야 합니다. 패키지는 ROS2 버전에 맞는 버전을 다음과 같이 추가로 설치를 합니다.

$ sudo apt install ros-foxy-joint-state-publisher-gui

버전이 설치되어 있는지는 다음 명령을 통해서 확인을 할 수 있습니다.

$ dpkg -L ros-foxy-joint-state-publisher-gui

런처(launch) 파일

이 예제에서는 사용하지 않지만 URDF를 작성하는데 xacro 패키지는 유용 합니다. 런처에서 xacro를 사용하도록 작성이 되었기 때문에 xacro 패키지를 설치해야 합니다.

$ sudo apt install ros-foxy-xacro

다음 런처파일을 manipulator/launch/manipulator.launch.py로 저장을 합니다.

import os
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

def generate_launch_description():

  # Set the path to this package.
  pkg_share = FindPackageShare(package='manipulator').find('manipulator')

  # Set the path to the RViz configuration settings
  default_rviz_config_path = os.path.join(pkg_share, 'rviz/rviz_basic_settings.rviz')

  # Set the path to the URDF file
  default_urdf_model_path = os.path.join(pkg_share, 'urdf/manipulator.urdf')

  ########### YOU DO NOT NEED TO CHANGE ANYTHING BELOW THIS LINE ##############  
  # Launch configuration variables specific to simulation
  gui = LaunchConfiguration('gui')
  urdf_model = LaunchConfiguration('urdf_model')
  rviz_config_file = LaunchConfiguration('rviz_config_file')
  use_robot_state_pub = LaunchConfiguration('use_robot_state_pub')
  use_rviz = LaunchConfiguration('use_rviz')
  use_sim_time = LaunchConfiguration('use_sim_time')

  # Declare the launch arguments  
  declare_urdf_model_path_cmd = DeclareLaunchArgument(
    name='urdf_model', 
    default_value=default_urdf_model_path, 
    description='Absolute path to robot urdf file')
    
  declare_rviz_config_file_cmd = DeclareLaunchArgument(
    name='rviz_config_file',
    default_value=default_rviz_config_path,
    description='Full path to the RVIZ config file to use')
    
  declare_use_joint_state_publisher_cmd = DeclareLaunchArgument(
    name='gui',
    default_value='True',
    description='Flag to enable joint_state_publisher_gui')
  
  declare_use_robot_state_pub_cmd = DeclareLaunchArgument(
    name='use_robot_state_pub',
    default_value='True',
    description='Whether to start the robot state publisher')

  declare_use_rviz_cmd = DeclareLaunchArgument(
    name='use_rviz',
    default_value='True',
    description='Whether to start RVIZ')
    
  declare_use_sim_time_cmd = DeclareLaunchArgument(
    name='use_sim_time',
    default_value='True',
    description='Use simulation (Gazebo) clock if true')
   
  # Specify the actions

  # Publish the joint state values for the non-fixed joints in the URDF file.
  start_joint_state_publisher_cmd = Node(
    condition=UnlessCondition(gui),
    package='joint_state_publisher',
    executable='joint_state_publisher',
    name='joint_state_publisher')

  # A GUI to manipulate the joint state values
  start_joint_state_publisher_gui_node = Node(
    condition=IfCondition(gui),
    package='joint_state_publisher_gui',
    executable='joint_state_publisher_gui',
    name='joint_state_publisher_gui')

  # Subscribe to the joint states of the robot, and publish the 3D pose of each link.
  start_robot_state_publisher_cmd = Node(
    condition=IfCondition(use_robot_state_pub),
    package='robot_state_publisher',
    executable='robot_state_publisher',
    parameters=[{'use_sim_time': use_sim_time, 
    'robot_description': Command(['xacro ', urdf_model])}],
    arguments=[default_urdf_model_path])

  # Launch RViz
  start_rviz_cmd = Node(
    condition=IfCondition(use_rviz),
    package='rviz2',
    executable='rviz2',
    name='rviz2',
    output='screen',
    arguments=['-d', rviz_config_file])
  
  # Create the launch description and populate
  ld = LaunchDescription()

  # Declare the launch options
  ld.add_action(declare_urdf_model_path_cmd)
  ld.add_action(declare_rviz_config_file_cmd)
  ld.add_action(declare_use_joint_state_publisher_cmd)
  ld.add_action(declare_use_robot_state_pub_cmd)  
  ld.add_action(declare_use_rviz_cmd) 
  ld.add_action(declare_use_sim_time_cmd)

  # Add any actions
  ld.add_action(start_joint_state_publisher_cmd)
  ld.add_action(start_joint_state_publisher_gui_node)
  ld.add_action(start_robot_state_publisher_cmd)
  ld.add_action(start_rviz_cmd)

  return ld

rviz 설정 파일

다음 rviz 설정 파일을 manipulator/rviz/rviz_basic_settings.rviz로 저장을 합니다. (런처 파일에 정의되어 있습니다.)

Panels:
  - Class: rviz_common/Displays
    Help Height: 78
    Name: Displays
    Property Tree Widget:
      Expanded:
        - /Global Options1
        - /Status1
        - /RobotModel1
        - /TF1
        - /TF1/Frames1
      Splitter Ratio: 0.5
    Tree Height: 617
  - Class: rviz_common/Selection
    Name: Selection
  - Class: rviz_common/Tool Properties
    Expanded:
      - /2D Goal Pose1
      - /Publish Point1
    Name: Tool Properties
    Splitter Ratio: 0.5886790156364441
  - Class: rviz_common/Views
    Expanded:
      - /Current View1
    Name: Views
    Splitter Ratio: 0.5
Visualization Manager:
  Class: ""
  Displays:
    - Alpha: 0.5
      Cell Size: 1
      Class: rviz_default_plugins/Grid
      Color: 160; 160; 164
      Enabled: true
      Line Style:
        Line Width: 0.029999999329447746
        Value: Lines
      Name: Grid
      Normal Cell Count: 0
      Offset:
        X: 0
        Y: 0
        Z: 0
      Plane: XY
      Plane Cell Count: 10
      Reference Frame: <Fixed Frame>
      Value: true
    - Alpha: 1
      Class: rviz_default_plugins/RobotModel
      Collision Enabled: false
      Description File: ""
      Description Source: Topic
      Description Topic:
        Depth: 5
        Durability Policy: Volatile
        History Policy: Keep Last
        Reliability Policy: Reliable
        Value: /robot_description
      Enabled: true
      Links:
        All Links Enabled: true
        Expand Joint Details: false
        Expand Link Details: false
        Expand Tree: false
        Link Tree Style: Links in Alphabetic Order
        base_footprint:
          Alpha: 1
          Show Axes: false
          Show Trail: false
        base_link:
          Alpha: 1
          Show Axes: false
          Show Trail: false
          Value: true
        drivewhl_l_link:
          Alpha: 1
          Show Axes: false
          Show Trail: false
          Value: true
        drivewhl_r_link:
          Alpha: 1
          Show Axes: false
          Show Trail: false
          Value: true
        front_caster:
          Alpha: 1
          Show Axes: false
          Show Trail: false
          Value: true
        gps_link:
          Alpha: 1
          Show Axes: false
          Show Trail: false
        imu_link:
          Alpha: 1
          Show Axes: false
          Show Trail: false
        lidar_link:
          Alpha: 1
          Show Axes: false
          Show Trail: false
          Value: true
      Name: RobotModel
      TF Prefix: ""
      Update Interval: 0
      Value: true
      Visual Enabled: true
    - Class: rviz_default_plugins/TF
      Enabled: true
      Frame Timeout: 15
      Frames:
        All Enabled: false
        base_footprint:
          Value: false
        base_link:
          Value: false
        drivewhl_l_link:
          Value: true
        drivewhl_r_link:
          Value: true
        front_caster:
          Value: false
        gps_link:
          Value: false
        imu_link:
          Value: false
        lidar_link:
          Value: false
      Marker Scale: 1
      Name: TF
      Show Arrows: false
      Show Axes: true
      Show Names: true
      Tree:
        base_footprint:
          base_link:
            drivewhl_l_link:
              {}
            drivewhl_r_link:
              {}
            front_caster:
              {}
            gps_link:
              {}
            imu_link:
              {}
            lidar_link:
              {}
      Update Interval: 0
      Value: 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
    - Class: rviz_default_plugins/SetInitialPose
      Topic:
        Depth: 5
        Durability Policy: Volatile
        History Policy: Keep Last
        Reliability Policy: Reliable
        Value: /initialpose
    - Class: rviz_default_plugins/SetGoal
      Topic:
        Depth: 5
        Durability Policy: Volatile
        History Policy: Keep Last
        Reliability Policy: Reliable
        Value: /goal_pose
    - Class: rviz_default_plugins/PublishPoint
      Single click: true
      Topic:
        Depth: 5
        Durability Policy: Volatile
        History Policy: Keep Last
        Reliability Policy: Reliable
        Value: /clicked_point
  Transformation:
    Current:
      Class: rviz_default_plugins/TF
  Value: true
  Views:
    Current:
      Class: rviz_default_plugins/Orbit
      Distance: 4.434264183044434
      Enable Stereo Rendering:
        Stereo Eye Separation: 0.05999999865889549
        Stereo Focal Distance: 1
        Swap Stereo Eyes: false
        Value: false
      Focal Point:
        X: 0.31193429231643677
        Y: 0.11948385089635849
        Z: -0.4807402193546295
      Focal Shape Fixed Size: true
      Focal Shape Size: 0.05000000074505806
      Invert Z Axis: false
      Name: Current View
      Near Clip Distance: 0.009999999776482582
      Pitch: 0.490397572517395
      Target Frame: <Fixed Frame>
      Value: Orbit (rviz)
      Yaw: 1.0503965616226196
    Saved: ~
Window Geometry:
  Displays:
    collapsed: false
  Height: 846
  Hide Left Dock: false
  Hide Right Dock: false
  QMainWindow State: 000000ff00000000fd000000040000000000000156000002f4fc0200000008fb0000001200530065006c0065006300740069006f006e00000001e10000009b0000005c00fffffffb0000001e0054006f006f006c002000500072006f007000650072007400690065007302000001ed000001df00000185000000a3fb000000120056006900650077007300200054006f006f02000001df000002110000018500000122fb000000200054006f006f006c002000500072006f0070006500720074006900650073003203000002880000011d000002210000017afb000000100044006900730070006c006100790073010000003d000002f4000000c900fffffffb0000002000730065006c0065006300740069006f006e00200062007500660066006500720200000138000000aa0000023a00000294fb00000014005700690064006500530074006500720065006f02000000e6000000d2000003ee0000030bfb0000000c004b0069006e0065006300740200000186000001060000030c00000261000000010000010f000002f4fc0200000003fb0000001e0054006f006f006c002000500072006f00700065007200740069006500730100000041000000780000000000000000fb0000000a00560069006500770073010000003d000002f4000000a400fffffffb0000001200530065006c0065006300740069006f006e010000025a000000b200000000000000000000000200000490000000a9fc0100000001fb0000000a00560069006500770073030000004e00000080000002e10000019700000003000004420000003efc0100000002fb0000000800540069006d00650100000000000004420000000000000000fb0000000800540069006d006501000000000000045000000000000000000000023f000002f400000004000000040000000800000008fc0000000100000002000000010000000a0054006f006f006c00730100000000ffffffff0000000000000000
  Selection:
    collapsed: false
  Tool Properties:
    collapsed: false
  Views:
    collapsed: false
  Width: 1200
  X: 246
  Y: 77

CMakeLists.txt 파일

amend_cmake는 CMakeLists.txt파일을 참조하여 패키지를 빌드 합니다. 새롭게 추가된 디렉토리를 추가해야 패키지 빌드시에 적용됩니다. 다음과 같이 CMakeLists.txt파일에 추가를 합니다.

install(
  DIRECTORY config launch maps meshes models params rviz src urdf worlds
  DESTINATION share/${PROJECT_NAME}
)

5. ROS2 패키지 빌드

ROS2의 빌드 시스템은 colcon입니다. colcon으로 빌드를 합니다.

$ colcon build
or
$ colcon build --packages-select manipulator

6. 시뮬레이션 실행

패키지 빌드가 성공을 하였다면 다음과 같이 실행을 하면 로봇이 없는 시뮬레이션 화면이 실행 됩니다.

$ ros2 launch manipulator manipulator.launch.py

manipulator/urdf/manipulator.urdf에 로봇을 추가하면 화면에 추가한 로봇이 보이게 됩니다.

7. 예제

https://github.com/duvallee/ros2-gazebo-simulation/archive/refs/tags/ros2_urdf_simulation_workspace.zip

 

'로봇 이야기 > ros2' 카테고리의 다른 글

기구학 (Kinematics) 이란?  (0) 2023.01.03
매니퓰레이터(manipulator) URDF 모델링  (0) 2022.12.31
xacro (XML macro)  (0) 2022.12.30
URDF(Unified Robot Description Format)란?  (0) 2022.12.13
ROS2 설치 - foxy  (0) 2022.12.13

댓글