My Robotic Manipulator #04: URDF/Transmission + Gazebo Controllers

URDF/Transmission + Gazebo Controllers

Written by Marco Arruda

30/08/2019

URDF/Transmission + Gazebo Controllers

Hey ROS developers! In this post, we will make our robot able to be spawned into Gazebo simulator. Based on the YouTube video series, we’ll show in this format the steps to achieve the final result of the series!

In this post number #4, I’m gonna create the Transmissions and controllers to some of our joints using the same XACROs files we have been working with. Up to the end of the post, we’ll have part of our model controllers by gazebo controllers!

 

Step 1 – Simplifying the robot

It turns out we have a very complex robot, with 6 links and 5 joints. I want to make it simpler in order to show how to use gazebo controller plugin.

Let’s start opening the file mrm.xacro and comment leave only the first links of the robot (the rest, we will comment). It will look like below:

<?xml version="1.0" ?>

<robot name="mrm" xmlns:xacro="http://www.ros.org/wiki/xacro">

  <!-- BGN - Include -->
  <xacro:include filename="$(find mrm_description)/urdf/links_joints.xacro" />
  <xacro:include filename="$(find mrm_description)/urdf/robot_parameters.xacro" />
  <!-- END - Include -->

  <!-- BGN - Robot description -->
  <m_link_box name="${link_00_name}"
           origin_rpy="0 0 0" origin_xyz="0 0 0"
           mass="1024"
           ixx="170.667" ixy="0" ixz="0"
           iyy="170.667" iyz="0"
           izz="170.667"
           size="1 1 1" />

  <m_joint name="${link_00_name}__${link_01_name}" type="revolute"
           axis_xyz="0 0 1"
           origin_rpy="0 0 0" origin_xyz="0 0 0.5"
           parent="${link_00_name}" child="${link_01_name}" />

  <m_link_cylinder name="${link_01_name}"
           origin_rpy="0 0 0" origin_xyz="0 0 0.2"
           mass="157.633"
           ixx="13.235" ixy="0" ixz="0"
           iyy="13.235" iyz="0"
           izz="9.655"
           length="0.4" radius="0.35" />

  <m_joint name="${link_01_name}__${link_02_name}" type="revolute"
           axis_xyz="0 1 0"
           origin_rpy="0 0 0" origin_xyz="0 0 0.4"
           parent="${link_01_name}" child="${link_02_name}" />

  <m_link_cylinder name="${link_02_name}"
           origin_rpy="0 0 0" origin_xyz="0 0 0.4"
           mass="57.906"
           ixx="12.679" ixy="0" ixz="0"
           iyy="12.679" iyz="0"
           izz="0.651"
           radius="0.15" length="0.8" />

<!--
  <m_joint name="${link_02_name}__${link_03_name}" type="revolute"
           axis_xyz="0 1 0"
           origin_rpy="0 0 0" origin_xyz="0 0 0.8"
           parent="${link_02_name}" child="${link_03_name}" />

  <m_link_cylinder name="${link_03_name}"
           origin_rpy="0 0 0" origin_xyz="0 0 0.4"
           mass="57.906"
           ixx="12.679" ixy="0" ixz="0"
           iyy="12.679" iyz="0"
           izz="0.651"
           radius="0.15" length="0.8" />

  <m_joint name="${link_03_name}__${link_04_name}" type="revolute"
           axis_xyz="0 1 0"
           origin_rpy="0 0 0" origin_xyz="0 0 0.8"
           parent="${link_03_name}" child="${link_04_name}" />

  <m_link_cylinder name="${link_04_name}"
           origin_rpy="0 0 0" origin_xyz="0 0 0.4"
           mass="57.906"
           ixx="12.679" ixy="0" ixz="0"
           iyy="12.679" iyz="0"
           izz="0.651"
           radius="0.15" length="0.8" />

  <m_joint name="${link_04_name}__${link_05_name}" type="revolute"
           axis_xyz="0 0 1"
           origin_rpy="0 0 0" origin_xyz="0 0 0.8"
           parent="${link_04_name}" child="${link_05_name}" />

  <m_link_cylinder name="${link_05_name}"
           origin_rpy="0 0 0" origin_xyz="0 0 0.125"
           mass="18.056"
           ixx="0.479" ixy="0" ixz="0"
           iyy="0.479" iyz="0"
           izz="0.204"
           radius="0.15" length="0.25" />
-->
  <!-- END - Robot description -->

</robot>

Start an empty world simulation and launch the robot from a web shell:

roslaunch mrm_description spawn.launch

Great! These are the parts we are going to control!

 

Step 2 – Adding gazebo controller dependencies

We need to modify two of our package files, in order to include the dependencies. They are:

CMakeLists.txt

In the command find_package, let’s add some new values:

find_package(catkin REQUIRED COMPONENTS
  urdf
  controller_manager
  joint_state_controller
  robot_state_publisher
)

And in the package.xml file, make sure you have the following instructions:

  <build_depend>urdf</build_depend>
  <build_depend>controller_manager</build_depend>
  <build_depend>joint_state_controller</build_depend>
  <build_depend>robot_state_publisher</build_depend>

  <build_export_depend>urdf</build_export_depend>
  <build_export_depend>controller_manager</build_export_depend>
  <build_export_depend>joint_state_controller</build_export_depend>
  <build_export_depend>robot_state_publisher</build_export_depend>

  <exec_depend>urdf</exec_depend>
  <exec_depend>controller_manager</exec_depend>
  <exec_depend>joint_state_controller</exec_depend>
  <exec_depend>robot_state_publisher</exec_depend>

 

Step 3 – Adding transmissions to the robot model

Next thing, we need some transmissions elements in our robot model.

Let’s get back to the URDF file: mrm.xacro

  <m_link_box name="${link_00_name}"
           origin_rpy="0 0 0" origin_xyz="0 0 0"
           mass="1024"
           ixx="170.667" ixy="0" ixz="0"
           iyy="170.667" iyz="0"
           izz="170.667"
           size="1 1 1" />

  <m_joint name="${link_00_name}__${link_01_name}" type="revolute"
           axis_xyz="0 0 1"
           origin_rpy="0 0 0" origin_xyz="0 0 0.5"
           parent="${link_00_name}" child="${link_01_name}" />

  <transmission name="trans_${link_00_name}__${link_01_name}">
    <type>transmission_interface/SimpleTransmission</type>
    <joint name="${link_00_name}__${link_01_name}">
        <hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
    </joint>
    <actuator name="motor_${link_00_name}__${link_01_name}">
        <hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
        <mechanicalReduction>1</mechanicalReduction>
    </actuator>
  </transmission>

  <m_link_cylinder name="${link_01_name}"
           origin_rpy="0 0 0" origin_xyz="0 0 0.2"
           mass="157.633"
           ixx="13.235" ixy="0" ixz="0"
           iyy="13.235" iyz="0"
           izz="9.655"
           length="0.4" radius="0.35" />

  <m_joint name="${link_01_name}__${link_02_name}" type="revolute"
           axis_xyz="0 1 0"
           origin_rpy="0 0 0" origin_xyz="0 0 0.4"
           parent="${link_01_name}" child="${link_02_name}" />

  <transmission name="trans_${link_01_name}__${link_02_name}">
    <type>transmission_interface/SimpleTransmission</type>
    <joint name="${link_01_name}__${link_02_name}">
        <hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
    </joint>
    <actuator name="motor_${link_01_name}__${link_02_name}">
        <hardwareInterface>hardware_interface/EffortJointInterface</hardwareInterface>
        <mechanicalReduction>1</mechanicalReduction>
    </actuator>
  </transmission>

  <m_link_cylinder name="${link_02_name}"
           origin_rpy="0 0 0" origin_xyz="0 0 0.4"
           mass="57.906"
           ixx="12.679" ixy="0" ixz="0"
           iyy="12.679" iyz="0"
           izz="0.651"
           radius="0.15" length="0.8" />

You can notice we have added a new element with the transmission tag.

What are we describing there?

First, we have a transmission for each joint. Then we define the type of the transmission, which in this case is just a SimpleTransmission.

Then, the joint we are referencing with the transmission.

Further, the actuator type, which is an Effort Joint Interface, in this case. And the mechanical reduction.

We do this for both joints we have left (in this simplified version of the robot).

 

Step 4 – Setup gazebo controllers on URDF model

Still on the same file, let’s add to the end of the description the tags related to gazebo controller plugin.

Just simple as below, append to the end of the file, just before the </robot>:

<gazebo>
    <plugin name="gazebo_ros_control" filename="libgazebo_ros_control.so">
    </plugin>
</gazebo>

 

Step 5 – Describe controller YAML file

This is something necessary for the gazebo controller, we must define some control variables (PID) to apply to our transmissions.

In order to do that, let’s create a new file: ~/simulation_ws/src/mrm_description/config/joints.yaml

It goes like that:

# Publish all joint states -----------------------------------
joint_state_controller:
  type: joint_state_controller/JointStateController
  publish_rate: 50

# Position Controllers ---------------------------------------
joint1_position_controller:
  type: effort_controllers/JointPositionController
  joint: base_link__link_01
  pid: {p: 2000.0, i: 100, d: 500.0}
joint2_position_controller:
  type: effort_controllers/JointPositionController
  joint: link_01__link_02
  pid: {p: 50000.0, i: 100, d: 2000.0}

We are defining the joint_state_publisher as reference.

Then tuning each one of the transmissions we have defined in our model. We need again the nametypejoint name and the PID values

 

Step 6 – Launch Gazebo Controllers

Now, let’s modify our launch file.

It goes like:

<?xml version="1.0" encoding="UTF-8"?>
<launch>
    <group ns="/mrm">

        <!-- Robot model -->
        <param name="robot_description" command="$(find xacro)/xacro --inorder '$(find mrm_description)/urdf/mrm.xacro'" />
        <arg name="x" default="0" />
        <arg name="y" default="0" />
        <arg name="z" default="0.5" />

        <!-- Spawn the robot model -->
        <node name="mybot_spawn" pkg="gazebo_ros" type="spawn_model" output="screen"
            args="-urdf -param robot_description -model mrm -x $(arg x) -y $(arg y) -z $(arg z)" />

        <!-- Load controllers -->
        <rosparam command="load" file="$(find mrm_description)/config/joints.yaml" />

        <node name="controller_spawner" pkg="controller_manager" type="spawner"
              respawn="false" output="screen" ns="/mrm"
              args="--namespace=/mrm
              joint_state_controller
              joint1_position_controller
              joint2_position_controller
              --timeout 60">
        </node>
    </group>
</launch>

First main modification is the group tag, where we define a namespace (mrm) for our robot processes. Everything inside this tag inherits the namespace. It’s necessary for the controller plugin.

Then, in the secion Load controllers we have a new parameter, that loads the config.yml file we have just created.

Finally, a new node to run the controller process.

 

Step 7 – Testing!

Great! Now we have already configured the controllers, you can spawn the robot again! Same commands as before, but this time you will notice the last link won’t fall down! This is very important to achieve since the controllers are already actuating.

Check the shell, you can see the controllers being loaded in the logs!

process[mrm/mybot_spawn-1]: started with pid [4817]
process[mrm/controller_spawner-2]: started with pid [4822]
[INFO] [1567187158.002693, 0.000000]: Controller Spawner: Waiting for service /mrm/controller_manager/load_controller
the rosdep view is empty: call 'sudo rosdep init' and 'rosdep update'
SpawnModel script started
[INFO] [1567187165.292282, 0.000000]: Loading model XML from ros parameter
[INFO] [1567187165.303925, 0.000000]: Waiting for service /gazebo/spawn_urdf_model
[INFO] [1567187165.312998, 0.000000]: Calling service /gazebo/spawn_urdf_model
[INFO] [1567187165.504207, 904.010000]: Spawn status: SpawnModel: Successfullyspawned entity
[mrm/mybot_spawn-1] process has finished cleanly
log file: /home/user/.ros/log/cfa21f58-cb4b-11e9-9ca9-0a2504d14030/mrm-mybot_spawn-1*.log
[INFO] [1567187166.829017, 904.050000]: Controller Spawner: Waiting for service /mrm/controller_manager/switch_controller
[INFO] [1567187166.831181, 904.050000]: Controller Spawner: Waiting for service /mrm/controller_manager/unload_controller
[INFO] [1567187166.848968, 904.070000]: Loading controller: joint_state_controller
[INFO] [1567187167.000380, 904.220000]: Loading controller: joint1_position_controller
[INFO] [1567187167.268639, 904.500000]: Loading controller: joint2_position_controller
[INFO] [1567187167.345849, 904.570000]: Controller Spawner: Loaded controllers: joint_state_controller, joint1_position_controller, joint2_position_controller
[INFO] [1567187167.355672, 904.590000]: Started controllers: joint_state_controller, joint1_position_controller, joint2_position_controller

We have also new ROS topics related to the controllers:

user:~$ rostopic list
/clock
/gazebo/link_states
/gazebo/model_states
/gazebo/parameter_descriptions
/gazebo/parameter_updates
/gazebo/set_link_state
/gazebo/set_model_state
/mrm/joint1_position_controller/command
/mrm/joint1_position_controller/pid/parameter_descriptions
/mrm/joint1_position_controller/pid/parameter_updates
/mrm/joint1_position_controller/state
/mrm/joint2_position_controller/command
/mrm/joint2_position_controller/pid/parameter_descriptions
/mrm/joint2_position_controller/pid/parameter_updates
/mrm/joint2_position_controller/state
/mrm/joint_states
/rosout
/rosout_agg

As a final test, let’s send a reference to the second joint:

rostopic pub -1 /mrm/joint2_position_controller/command std_msgs/Float64 "data: 0.7"

You must have the robot like:

In order to put it back to the original position, execute the command below:

rostopic pub -1 /mrm/joint2_position_controller/command std_msgs/Float64 "data: 0.0"

 

Related courses

Robot-creation-URDF Course Cover - ROS Online Courses - Robot Ignite Academy

URDF for Robot Modeling

ROS Manipulation Course Cover - ROS Online Courses - Robot Ignite Academy

ROS Manipulation

ROS Industrial robots Course Cover - ROS Online Courses - Robot Ignite Academy

ROS for Industrial Robots

Step 8 – Conclusion

Great! If you missed any of the steps or something just didn’t work, you can check the original project just clicking on the link: http://www.rosject.io/l/c1ed2ee/

See you in the next post!

Masterclass 2023 batch2 blog banner

Check Out These Related Posts

129. ros2ai

129. ros2ai

I would like to dedicate this episode to all the ROS Developers who believe that ChatGPT or...

read more

0 Comments

Submit a Comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Pin It on Pinterest

Share This