Describing Robots with URDF

https://articulatedrobotics.xyz/tutorials/ready-for-ros/urdf

Describing a Robot

URDF

  • slider joint (prismatic)

  • arm joint (revolute)

  • joint

    • origin: the relationship between the 2 links before any motion is applied

URDF Example

https://github.com/joshnewans/urdf_example

example_include.xacro

<?xml version="1.0"?>
<robot name="robot_name">
    
</robot>
  • Specify colors
    <material name="white">
        <color rgba="1 1 1 1" />
    </material>
    <material name="orange">
        <color rgba="1 0.3 0.1 1"/>
    </material>
 
    <material name="blue">
        <color rgba="0.2 0.2 1 1"/>
    </material>

example_robot.urdf.xacro

  • World link

    • An empty, non-visual link- just represents an anchor point for the world
  • Base joint

    • Goes from world to base link
    • 1.5m across and 1.0m forward picture 0
  • Base link

    • collision is same as visual but without material tag
    • inertial parameters from inertial matrix for rectangular prism with mass 12
  • Slider joint- from base_link to slider_link

    • offset from base_link by (-1.25, 0, 0.1)
    • axis x=1, moves along x axis picture 1
  • Slider Link

    • inertial_box
      • specify mass, xyz, and origin and macro will do the calculations
  • Arm joint

    • axis: -1 in Y, rotates upward
    • Upper limit is 90 degrees
      • change to radians using macro to calculate (pi/2) picture 2
  • Arm link

    • Use property xacro to change arm length and radius values
    • Cylinder rotated by pi/2 so that it is oriented along x instead of z axis
  • Camera joint

picture 5

  • Camera link

    • composed of 2 visual components (box and cylinder) but collision is just a box that covers the area
      • In rviz, can turn off visual to see the collision area picture 4
  • build

colcon build --symlink-install --packages-select urdf_example
  • Source the setup file
source install/setup.bash
  • Launch node
ros2 launch urdf_example rsp.launch.py
  • Launch “joint_state_publisher_gui`
ros2 run joint_state_publisher_gui joint_state_publisher_gui
  • Run rviz
rviz2 -d src/urdf_example/config/urdf_example.rviz

picture 6

Simulating with Gazebo

https://articulatedrobotics.xyz/tutorials/ready-for-ros/gazebo

Gazebo overview

  • Launch Gazebo with the “seesaw” world
gazebo /usr/share/gazebo-11/worlds/seesaw.world
  • Move the box to make the seesaw move

    • Press ctrl+r to reset picture 0
  • We no longer need to use joint_state_publisher_gui to publish fake messages to the /joint_states to move the transforms

    • Gazebo has a spawner_script that can read the description from the topic being published and simulate the robot
      • and use Joint state publisher plugin to see how the joints are moving and publish to /joint_states
      • Joint controller plugin can take control inputs and force the joints to move picture 1

Gazebo and ROS

  • Launch Gazebo with an empty world
ros2 launch gazebo_ros gazebo.launch.py
  • Spawn the robot into Gazebo
    • Gazebo will convert the URDF to SDF
      • but links connected by a fixed joint (e.g. world + base_link and arm + camera) will collapse into a single link
      • The entity name (e.g. my_bot) can be anything
ros2 run gazebo_ros spawn_entity.py -topic robot_description -entity my_bot

picture 2

  • Create a rsp_sim.launch.py file
import os
 
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
 
from launch.substitutions import LaunchConfiguration
from launch.actions import DeclareLaunchArgument
from launch_ros.actions import Node
 
import xacro
 
 
def generate_launch_description():
 
    # Check if we're told to use sim time
    use_sim_time = LaunchConfiguration('use_sim_time')
 
    # Process the URDF file
    pkg_path = os.path.join(get_package_share_directory('urdf_example'))
    xacro_file = os.path.join(pkg_path,'description','robot.urdf.xacro')
    robot_description_config = xacro.process_file(xacro_file)
    
    # Create a robot_state_publisher node
    params = {'robot_description': robot_description_config.toxml(), 'use_sim_time': use_sim_time}
    node_robot_state_publisher = Node(
        package='robot_state_publisher',
        executable='robot_state_publisher',
        output='screen',
        parameters=[params]
    )
 
    gazebo = IncludeLaunchDescription(
        PythonLaunchDescriptionSource([os.path.join(
            get_package_share_directory('gazebo_ros'), 'launch'), '/gazebo.launch.py']),
        )
 
    spawn_entity = Node(package='gazebo_ros', executable='spawn_entity.py',
                        arguments=['-topic', 'robot_description',
                                   '-entity', 'my_bot'],
                                   output='screen')
 
    # Launch!
    return LaunchDescription([
        DeclareLaunchArgument(
            'use_sim_time',
            default_value='true',
            description='Use sim time if true'),
 
        node_robot_state_publisher,
        gazebo,
        spawn_entity
    ])
 
  • Launch nodes
ros2 launch urdf_example rsp_sim.launch.py

picture 3

  • Publish a joint trajectory message
ros2 topic pub -1 /set_joint_trajectory trajectory_msgs/msg/JointTrajectory  '{header: {frame_id: world}, joint_names: [slider_joint, arm_joint], points: [  {positions: {0.8,0.6}} ]}'

picture 4

Create a wold in Gazebo

  • Add a Construction Barrel and Construction Cone

    • Insert Add Path picture 5
  • Use building editor to construct a wall

picture 6

  • Delete robot and save world picture 7

  • Run launch the file with world parameter

ros2 launch urdf_example rsp_sim.launch.py world:=src/urdf_example/worlds/my_world.world
  • Simulate camera
    <!-- The next section shows an example of adding a sensor, in this case a depth camera. -->
 
    <!-- Due to a quirk of how cameras work, an extra joint/link is required to create an
            "optical frame" for the sensor. That isn't the focus for this tutorial, but you can
            look at https://www.ros.org/reps/rep-0103.html#suffix-frames for slightly more information. -->
 
    
    
    <!-- First, create the link and joint for the optical frame -->
 
    <joint name="camera_optical_joint" type="fixed">
        <origin xyz="0 0 0" rpy="-1.571 0 -1.571" />
        <parent link="camera_link" />
        <child link="camera_link_optical" />
    </joint>
 
    <link name="camera_link_optical"></link>
    <!-- Add a gazebo tag for the ORIGINAL camera_link (but in the plugin we reference the optical frame so that ROS can orient things correctly) -->
    <!-- Within the gazebo tag we have the sensor tag, and inside that there is (among other things) the camera tag with the camera parameters, 
            and the plugin tag with some extra parameters the plugin needs. -->
    <!-- Note that although visualise is set to true, it won't actually visualise the depth camera in gazebo. To see the preview, 
            try swapping "depth" to "camera"-->
    <gazebo reference="camera_link">
        <sensor type="depth" name="my_camera">
            <update_rate>20</update_rate>
            <visualize>true</visualize>
            <camera name="cam">
                <horizontal_fov>1.3962634</horizontal_fov>
                <image>
                    <width>640</width>
                    <height>480</height>
                    <format>R8B8G8</format>
                </image>
                <clip>
                    <near>0.02</near>
                    <far>300</far>
                </clip>
                <noise>
                    <type>gaussian</type>
                    <mean>0.0</mean>
                    <stddev>0.007</stddev>
                </noise>
            </camera>
            <plugin name="camera_controller" filename="libgazebo_ros_camera.so">
                <frame_name>camera_link_optical</frame_name>
                <min_depth>0.1</min_depth>
                <max_depth>500</max_depth>
            </plugin>
        </sensor>
    </gazebo>

picture 8

  • Add image_raw topic in rviz
    • The image taken by the camera is simulated in Gazebo which is then passed to ROS and rviz can subscribe to the /image_raw topic

picture 10

  • Enable depth camera and show 3D point cloud
    <!-- in gazebo. To see the preview, 
            try swapping "depth" to "camera"-->
    <gazebo reference="camera_link">
        <sensor type="depth" name="my_camera">
            <update_rate>20</update_rate>
    ...
  • Add PointCloud2 in rviz and choose /points topic

picture 12

https://github.com/joshnewans/urdf_example