Skip to content

Latest commit

Β 

History

History
190 lines (121 loc) Β· 6.75 KB

README.md

File metadata and controls

190 lines (121 loc) Β· 6.75 KB

DEScription temPLATEs

This repository contains various examples for how to template description files in ROS 2. Each example demonstrates the use of a templating engine, with a description format, at compile time or launch time. All examples have the same final result, which makes it easy to compare them side-by-side.

Templating engines:

Description formats:

Is your engine or format of choice not represented? Consider opening a pull request to add it!

Quick start

  1. Install ROS Humble or higher

  2. Clone this repository:

    mkdir -p ~/ws/src
    cd ~/ws/src
    git clone https://github.com/chapulina/desplate
    
  3. Install dependencies:

    cd ~/ws
    rosdep install --from-paths src --ignore-src -r -y
    
  4. Build and install:

    cd ~/ws
    colcon build
    
  5. Run one of the examples, i.e.:

    ros2 launch desplate_empy vehicle_sdf_generate.launch.py
    
  6. You should see a differential drive robot (like dolly) on RViz:

    vehicle_rviz

  7. Also try checking the inertia visualization:

    vehicle_rviz

Try out all examples

Templating engine Format Stage Command
EmPy SDF launch ros2 launch desplate_empy vehicle_sdf_generate.launch.py
EmPy URDF launch ros2 launch desplate_empy vehicle_urdf_generate.launch.py
EmPy SDF compilation ros2 launch desplate_empy vehicle_sdf_installed.launch.py
EmPy URDF compilation ros2 launch desplate_empy vehicle_urdf_installed.launch.py
ERB SDF launch ros2 launch desplate_erb vehicle_sdf_generate.launch.py
ERB URDF launch ros2 launch desplate_erb vehicle_urdf_generate.launch.py
ERB SDF compilation ros2 launch desplate_erb vehicle_sdf_installed.launch.py
ERB URDF compilation ros2 launch desplate_erb vehicle_urdf_installed.launch.py
Xacro SDF launch ros2 launch desplate_xacro vehicle_sdf_generate.launch.py
Xacro URDF launch ros2 launch desplate_xacro vehicle_urdf_generate.launch.py
Xacro SDF compilation ros2 launch desplate_xacro vehicle_sdf_installed.launch.py
Xacro URDF compilation ros2 launch desplate_xacro vehicle_urdf_installed.launch.py

How it works

Launch time

Generating description files at launch time is convenient if you're often iterating on parameters for those files. On the other hand, if your files aren't changing much, consider generating them at compile time to save some time every time you launch.

Generate templates at launch file following these steps:

  1. Install all template files, i.e.:

    # Templates to be generated at launch time
    install(
    DIRECTORY
    sdf
    urdf
    DESTINATION
    share/${PROJECT_NAME}/
    )

  2. In a launch file, get the path to the installed template file, for example:

    pkg = os.path.join(get_package_share_directory('desplate_empy'))
    template_path = os.path.join(pkg, 'sdf', 'vehicle.sdf.em')

  3. Use the templating engine to generate a file and store it in a string variable. See each engine below.

  4. Pass that description string to another node. For robots, that's usually robot_state_publisher, i.e.:

    robot_state_publisher = Node(
    package='robot_state_publisher',
    executable='robot_state_publisher',
    output='screen',
    parameters=[{'robot_description': LaunchConfiguration('description_str')}]
    )

EmPy

Add these lines to a launch file to generate a description from an EmPy template:

# These 3 lines generate a description file from an EmPy template
with open(template_path) as template_file:
template = template_file.read()
description_str = em.expand(template, {})

ERB

Add this line to a launch file to generate a description from an ERB template:

# This line generates a description file from an ERB template
description_str = subprocess.run(['erb', template_path], capture_output=True).stdout.decode()

Xacro

Add this line to a launch file to generate a description from a Xacro template:

# This line generates a description file from a Xacro template
description_str = xacro.process_file(template_path).toxml()

Compile time

Generating description files at compile time is efficient if you're not iterating on parameters for those files, because you're not generating them over and over every time the application is launched. On the other hand, if your files often take different arguments for each run, consider generating them at launch time.

Generate templates at compile file following these steps:

  1. Invoke the templating engine with CMake to generate the description into the build directory. One way to do it is creating a custom command and making a target that depends on it. The difference for each engine will be what command is invoked, see below for each engine.

    file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${FORMAT})
    add_custom_command(
    OUTPUT generate_template_${FORMAT}
    COMMAND empy3
    ${CMAKE_CURRENT_SOURCE_DIR}/${FORMAT}/vehicle.${FORMAT}.em >
    ${CMAKE_CURRENT_BINARY_DIR}/${FORMAT}/vehicle.${FORMAT}
    )
    add_custom_target(generate_template_target_${FORMAT} ALL
    DEPENDS generate_template_${FORMAT}
    )

  2. Install the generated description, i.e.:

    # Descriptions generated at compile time
    install(
    DIRECTORY
    ${CMAKE_CURRENT_BINARY_DIR}/sdf
    ${CMAKE_CURRENT_BINARY_DIR}/urdf
    DESTINATION
    share/${PROJECT_NAME}/
    )

  3. In a launch file, find the installed description and store it in a string, i.e.:

    # Load installed file
    pkg = os.path.join(get_package_share_directory('desplate_empy'))
    description_path = os.path.join(pkg, 'sdf', 'vehicle.sdf')
    with open(description_path, 'r') as description_file:
    description_str = description_file.read().replace('\n', '')

  4. Pass that description string to another node. For robots, that's usually robot_state_publisher, i.e.:

    robot_state_publisher = Node(
    package='robot_state_publisher',
    executable='robot_state_publisher',
    output='screen',
    parameters=[{'robot_description': LaunchConfiguration('description_str')}]
    )

EmPy

Invoke empy on .em files from the custom CMake command:

COMMAND empy3
${CMAKE_CURRENT_SOURCE_DIR}/${FORMAT}/vehicle.${FORMAT}.em >
${CMAKE_CURRENT_BINARY_DIR}/${FORMAT}/vehicle.${FORMAT}

ERB

Invoke erb on .erb files from the custom CMake command:

COMMAND erb
${CMAKE_CURRENT_SOURCE_DIR}/${FORMAT}/vehicle.${FORMAT}.erb >
${CMAKE_CURRENT_BINARY_DIR}/${FORMAT}/vehicle.${FORMAT}

Xacro

Invoke xacro on .xacro files from the custom CMake command:

COMMAND xacro
${CMAKE_CURRENT_SOURCE_DIR}/${FORMAT}/vehicle.${FORMAT}.xacro >
${CMAKE_CURRENT_BINARY_DIR}/${FORMAT}/vehicle.${FORMAT}

Compare

This package makes it possible to compare how the same result can be achieved using different templating engines and description formats. You can use a tool like Meld to see these files side-by-side.

For example, to compare Xacro and EmPy:

diff Xacro EmPy

Or to compare URDF and SDF:

diff URDF SDF