[Bug] Unit 7: Custom Controller launch error

This is an error report.


Screenshot of the error


Error details

Hello,

I wanted to ask for some advice for unit 7; I had issues with the final example with executing the command to not only spawn Unit 2 RRbot with the new gazebo plugin for the custom rrbot controller we made in that unit. I was able to compile all of the code well and able to run this system properly in spawning it but when it comes to the final step of loading the controllers. It is stuck in a loop of waiting for the controller manager which is odd since we already added the plugins needed for gazebo custom controller + ros2 controls needed for the section are already stated in the robot xacro file. I will share the code I wrote in each segment needed. What could be the step I over look if at all possible?

rrobot_with_rrbot_controlller.launch.py

import os

from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import ExecuteProcess, IncludeLaunchDescription, RegisterEventHandler, TimerAction, LogInfo
from launch.event_handlers import OnProcessExit, OnExecutionComplete
from launch.launch_description_sources import PythonLaunchDescriptionSource
import xacro

def generate_launch_description():

rrbot_description_path = os.path.join(
    get_package_share_directory('rrbot_unit2'))

xacro_file = os.path.join(rrbot_description_path,
                          'urdf',
                          'rrbot.xacro')

doc = xacro.parse(open(xacro_file))
xacro.process_doc(doc)
robot_description_config = doc.toxml()
robot_description = {'robot_description': robot_description_config}

node_robot_state_publisher = Node(
    package='robot_state_publisher',
    executable='robot_state_publisher',
    output='screen',
    parameters=[robot_description]
)

spawn_entity = Node(package='gazebo_ros', executable='spawn_entity.py',
                    arguments=['-topic', 'robot_description',
                               '-entity', 'robot'],
                    output='screen')

joint_state_broadcaster_spawner = Node(
    package="controller_manager",
    executable="spawner",
    arguments=["joint_state_broadcaster",
               "--controller-manager", "/controller_manager"],
)

robot_controller_spawner = Node(
    package="controller_manager",
    executable="spawner",
    arguments=["rrbot_controller", "-c", "/controller_manager"],
)


return LaunchDescription([
    RegisterEventHandler(
        OnExecutionComplete(
            target_action=spawn_entity,
            on_completion=[
                LogInfo(
                    msg='Spawn finished, waiting 10 seconds to start controllers.'),
                TimerAction(
                    period=10.0,
                    actions=[joint_state_broadcaster_spawner],
                )
            ]
        )
    ),
    RegisterEventHandler(
        event_handler=OnProcessExit(
            target_action=joint_state_broadcaster_spawner,
            on_exit=[robot_controller_spawner],
        )
    ),
    spawn_entity,
    node_robot_state_publisher,
])

rrbot_controllers_custom.yaml:

Controller manager configuration

controller_manager:
ros__parameters:
update_rate: 50 # Hz

# Define a name for controllers that we plan to use
joint_state_broadcaster:
  type: joint_state_broadcaster/JointStateBroadcaster

rrbot_controller:
  type: rrbot_controller/RRBotController

Properties of the custom controler and definition of joints to use

rrbot_controller:
ros__parameters:
joints:
- joint1
- joint2
interface_name: position

RRbot Xacro:

All of the code is the same as in the unit2 robot what was changed is that the gazebo plugin line is only this:

gazebo_ros2_control/GazeboSystem $(find rrbot_controller)/config/rrbot_controllers_custom.yaml

rrbot_controller.cpp:

#include “rrbot_controller/rrbot_controller.hpp”

#include
#include
#include
#include

namespace rrbot_controller
{
RRBotController::RRBotController() : controller_interface::ControllerInterface() {}

CallbackReturn RRBotController::on_init() {
try {
auto_declare(“joints”, std::vectorstd::string());
auto_declare(“interface_name”, std::string());
} catch (const std::exception &e) {
fprintf(stderr, “Exception thrown during init stage with message: %s \n”,
e.what());
return CallbackReturn::ERROR;
}

return CallbackReturn::SUCCESS;
}

CallbackReturn RRBotController::on_configure(
const rclcpp_lifecycle::State & /previous_state/) {
auto error_if_empty = [&](const auto &parameter, const char *parameter_name) {
if (parameter.empty()) {
RCLCPP_ERROR(get_node()->get_logger(), “‘%s’ parameter was empty”,
parameter_name);
return true;
}
return false;
};

auto get_string_array_param_and_error_if_empty =
[&](std::vectorstd::string &parameter, const char *parameter_name) {
parameter = get_node()->get_parameter(parameter_name).as_string_array();
return error_if_empty(parameter, parameter_name);
};

auto get_string_param_and_error_if_empty =
[&](std::string &parameter, const char *parameter_name) {
parameter = get_node()->get_parameter(parameter_name).as_string();
return error_if_empty(parameter, parameter_name);
};

if (
get_string_array_param_and_error_if_empty(joint_names_, “joints”) ||
get_string_param_and_error_if_empty(interface_name_, “interface_name”)) {
return CallbackReturn::ERROR;
}

// Command Subscriber and callbacks
auto callback_command =
[&](const std::shared_ptr msg) → void {
if (msg->joint_names.size() == joint_names_.size()) {
input_command_.writeFromNonRT(msg);
} else {
RCLCPP_ERROR(get_node()->get_logger(),
"Received %zu , but expected %zu joints in command. "
“Ignoring message.”,
msg->joint_names.size(), joint_names_.size());
}
};
command_subscriber_ = get_node()->create_subscription(
“~/commands”, rclcpp::SystemDefaultsQoS(), callback_command);

// State publisher
s_publisher_ =
get_node()->create_publisher(
“~/state”, rclcpp::SystemDefaultsQoS());
state_publisher_ = std::make_unique(s_publisher_);

state_publisher_->lock();
state_publisher_->msg_.header.frame_id = joint_names_[0];
state_publisher_->unlock();

RCLCPP_INFO_STREAM(get_node()->get_logger(), “configure successful”);
return CallbackReturn::SUCCESS;
}

controller_interface::InterfaceConfiguration
RRBotController::command_interface_configuration() const {
controller_interface::InterfaceConfiguration command_interfaces_config;
command_interfaces_config.type =
controller_interface::interface_configuration_type::INDIVIDUAL;

command_interfaces_config.names.reserve(joint_names_.size());
for (const auto &joint : joint_names_) {
command_interfaces_config.names.push_back(joint + “/” + interface_name_);
}

return command_interfaces_config;
}

template
bool get_ordered_interfaces(
std::vector &unordered_interfaces,
const std::vectorstd::string &joint_names,
const std::string &interface_type,
std::vector<std::reference_wrapper> &ordered_interfaces) {
for (const auto &joint_name : joint_names) {
for (auto &command_interface : unordered_interfaces) {
if ((command_interface.get_name() == joint_name) &&
(command_interface.get_interface_name() == interface_type)) {
ordered_interfaces.push_back(std::ref(command_interface));
}
}
}

return joint_names.size() == ordered_interfaces.size();
}

CallbackReturn RRBotController::on_activate(
const rclcpp_lifecycle::State & /previous_state/) {
// Set default value in command
std::shared_ptr msg =
std::make_shared();
msg->joint_names = joint_names_;
msg->displacements.resize(joint_names_.size(),
std::numeric_limits::quiet_NaN());
input_command_.writeFromNonRT(msg);

return CallbackReturn::SUCCESS;
}

CallbackReturn RRBotController::on_deactivate(
const rclcpp_lifecycle::State & /previous_state/) {
return CallbackReturn::SUCCESS;
}

controller_interface::return_type
RRBotController::update(const rclcpp::Time &time,
const rclcpp::Duration & /period/) {
auto current_command = input_command_.readFromRT();

for (size_t i = 0; i < command_interfaces_.size(); ++i) {
if (!std::isnan((*current_command)->displacements[i])) {
command_interfaces_[i].set_value((*current_command)->displacements[i]);
}
}

if (state_publisher_ && state_publisher_->trylock()) {
state_publisher_->msg_.header.stamp = time;
state_publisher_->msg_.set_point = command_interfaces_[0].get_value();

state_publisher_->unlockAndPublish();

}

return controller_interface::return_type::OK;
}

} // namespace rrbot_controller

#include “pluginlib/class_list_macros.hpp”

PLUGINLIB_EXPORT_CLASS(rrbot_controller::RRBotController, controller_interface::ControllerInterface)

Hi @Agarcia5612 ,

Firstly, please format your codes that you are pasting here.
Copy-pasting the codes which are not properly formatted as Markdown text makes it difficult to read for anyone looking at your code to help you with your issue.
You can see your own post right? Does it look readable to you? Would you make use of a shabbily-presented code, if I give you one? Ask yourself that question every time you post a load of unformatted files. Please re-format your existing post by editing it (do not make a new post).

Now coming to your issue,

In your launch file:
Your node launch sequence is wrong. You want to launch joint_state_broadcaster_spawner after spawn_entity completes, but you have sequenced spawn_entity after joint_state_broadcaster_spawner. This will obviously not work.
The correct order is node_robot_state_publisher, spawn_entity, joint_state_broadcaster_spawner, robot_controller_spawner.

In your controller yaml file:

interface_name: position   # <--- replace this line with the lines below
interface_name:
    position

Your xacro file requires no change I suppose, that line that you have indicated is correct.

I am not looking into rrbot_controller.cpp file, as that file is provided to you and you don’t have to make any changes. If you followed the instructions correctly, that file should be fine.

Solution: Fix your node launch order in your launch file, your problem should be resolved.

Let me know if this fixed your issue.

Regards,
Girish

Hello @girishkumar.kannan,

My apologies for the formatting of the code and thank you for the recommendations. 

The solution recommended did not fix my issue. I added all the needed content in the proper format.

This image below is the rrbot controller launch.py; Even after arranging the controller system as you recommended. The solution in the class course will be posted with this as well was in the format I gave you to test if the system was loaded in correctly from my side. But after doing the change you recommended which is:

having the robot_state_publisher load first then the spawn entity, then joint_state_publisher then finally the robot_controller spawner nodes. I still run into the same error code that it cannot detect the controller manager. The cpp code for the rrbot controller is identical to how it was posted in the end of the unit so no problem there.



RRbot Xacro Unit 2: added content:

RRbot controller yaml

The RRbot XML file:

Current State:


Solution on the class: With the current set order of executing the controller loading and urdf robot:

Which did the spawn_entity first then the robot_state_publisher, then joint_state_publisher, then rrbot_controller node.

Let me know if you need any other content from my side. I am not sure what else to try. It seems odd that the joint_state_publisher does not load which always does with the format you recommended for the other examples without a hitch. Thank you again for your assistance!

Best,
Agarcia

Hi @Agarcia5612 ,

Please DO NOT post images / screenshots of codes.
Please post markdown formatted code-blocks with syntax highlights.
Refer here: Fenced Code Blocks and Syntax Highlighting

Here is what I informed you to do in my earlier post to you.
[The following is also an example of posting a code block using Markdown format and syntax highlighting.]

import os

from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import ExecuteProcess, IncludeLaunchDescription, RegisterEventHandler, TimerAction, LogInfo
from launch.event_handlers import OnProcessExit, OnExecutionComplete
from launch.launch_description_sources import PythonLaunchDescriptionSource
import xacro


def generate_launch_description():

    rrbot_description_path = os.path.join(
        get_package_share_directory('rrbot_unit2'))

    xacro_file = os.path.join(rrbot_description_path, 'urdf', 'rrbot.xacro')

    doc = xacro.parse(open(xacro_file))
    xacro.process_doc(doc)
    robot_description_config = doc.toxml()
    robot_description = {'robot_description': robot_description_config}

    node_robot_state_publisher = Node(
        package='robot_state_publisher',
        executable='robot_state_publisher',
        output='screen',
        parameters=[robot_description]
    )

    spawn_entity = Node(package='gazebo_ros', executable='spawn_entity.py',
                        arguments=['-topic', 'robot_description',
                                   '-entity', 'robot'],
                        output='screen')

    joint_state_broadcaster_spawner = Node(
        package="controller_manager",
        executable="spawner",
        arguments=["joint_state_broadcaster",
                   "--controller-manager", "/controller_manager"],
    )

    robot_controller_spawner = Node(
        package="controller_manager",
        executable="spawner",
        arguments=["rrbot_controller", "-c", "/controller_manager"],
    )


    return LaunchDescription([
        node_robot_state_publisher,
        spawn_entity,

        RegisterEventHandler(
            OnExecutionComplete(
                target_action=spawn_entity,
                on_completion=[
                    LogInfo(
                        msg='Spawn finished, waiting 10 seconds to start controllers.'),
                    TimerAction(
                        period=10.0,
                        actions=[joint_state_broadcaster_spawner],
                    )
                ]
            )
        ),

        RegisterEventHandler(
            event_handler=OnProcessExit(
                target_action=joint_state_broadcaster_spawner,
                on_exit=[robot_controller_spawner],
            )
        ),
    ])

So the order that you have to follow to get this working is the following:

  1. Delete the existing RRBot robot on Simulation window, if the robot is present already.
    ros2 service call /delete_entity 'gazebo_msgs/DeleteEntity' '{name: "rrbot"}'
    
  2. Stop the programs running in the webshells / terminals (press Ctrl + C in all the 4 terminals).
  3. Restart the Simulation by clicking on the first button (circular arrow) on the top right corner of the simulation window.
  4. Restart the webshells / terminals by clicking on the second button (circular arrow) on all the tabs of the terminals.
  5. Start the RRBot Spawn launch file in terminal #1.
  6. Once the robot has loaded, launch the rrbot_with_rrbot_controller.launch.py file.

This time everything should work correctly.

Regards,
Girish

Hello @girishkumar.kannan,

I followed your instructions all the way through 4 times with no success.

I did follow the identical format you have provided and it still had issues loading in the controller for the joint state broadcaster node controller and the rrbot controller.

There was a new error in terminal 1 which was that there was no ros2_control tag present in the passed urdf file which is weird since I double-checked the file directory for the rrbot and it is the desired file directory I even changed it to follow exactly where it is still did not fix this issue.

Here is my current launch file structure:

import os

from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch_ros.actions import Node
from launch.actions import ExecuteProcess, IncludeLaunchDescription, RegisterEventHandler, TimerAction, LogInfo
from launch.event_handlers import OnProcessExit, OnExecutionComplete
from launch.launch_description_sources import PythonLaunchDescriptionSource
import xacro


def generate_launch_description():

    rrbot_description_path = os.path.join(
        get_package_share_directory('ros2_control_course'))

    xacro_file = os.path.join(rrbot_description_path,'unit2','rrbot_unit2', 'urdf', 'rrbot.xacro')

    doc = xacro.parse(open(xacro_file))
    xacro.process_doc(doc)
    robot_description_config = doc.toxml()
    robot_description = {'robot_description': robot_description_config}

    node_robot_state_publisher = Node(
        package='robot_state_publisher',
        executable='robot_state_publisher',
        output='screen',
        parameters=[robot_description]
    )

    spawn_entity = Node(package='gazebo_ros', executable='spawn_entity.py',
                        arguments=['-topic', 'robot_description',
                                   '-entity', 'robot'],
                        output='screen')

    joint_state_broadcaster_spawner = Node(
        package="controller_manager",
        executable="spawner",
        arguments=["joint_state_broadcaster",
                   "--controller-manager", "/controller_manager"],
    )

    robot_controller_spawner = Node(
        package="controller_manager",
        executable="spawner",
        arguments=["rrbot_controller", "-c", "/controller_manager"],
    )


    return LaunchDescription([
        node_robot_state_publisher,
        spawn_entity,

        RegisterEventHandler(
            OnExecutionComplete(
                target_action=spawn_entity,
                on_completion=[
                    LogInfo(
                        msg='Spawn finished, waiting 10 seconds to start controllers.'),
                    TimerAction(
                        period=10.0,
                        actions=[joint_state_broadcaster_spawner],
                    )
                ]
            )
        ),

        RegisterEventHandler(
            event_handler=OnProcessExit(
                target_action=joint_state_broadcaster_spawner,
                on_exit=[robot_controller_spawner],
            )
        ),
    ])

Here is my urdf file within rrbot_unit2:

<?xml version="1.0"?>
<!-- Revolute-Revolute Manipulator -->
<robot name="rrbot" xmlns:xacro="http://www.ros.org/wiki/xacro">

  <!-- Constants for robot dimensions -->
  <xacro:property name="PI" value="3.1415926535897931"/>
  <!-- arbitrary value for mass -->
  <xacro:property name="mass" value="1"/>
  <!-- Square dimensions (widthxwidth) of beams -->
  <xacro:property name="width" value="0.1"/>
  <!-- Link 1 -->
  <xacro:property name="height1" value="2"/>
  <!-- Link 2 -->
  <xacro:property name="height2" value="1"/>
  <!-- Link 3 -->
  <xacro:property name="height3" value="1"/>
  <!-- Size of square 'camera' box -->
  <xacro:property name="camera_link" value="0.05"/>
  <!-- Space btw top of beam and the each joint -->
  <xacro:property name="axel_offset" value="0.05"/>

  <!-- Import all Gazebo-customization elements, including Gazebo colors -->
  <xacro:include filename="$(find rrbot_unit2)/urdf/rrbot.gazebo"/>
  <!-- Import Rviz colors -->
  <xacro:include filename="$(find rrbot_unit2)/urdf/materials.xacro"/>

  <!-- Used for fixing robot to Gazebo 'base_link' -->
  <link name="world"/>

  <joint name="fixed" type="fixed">
    <parent link="world"/>
    <child link="link1"/>
  </joint>

  <!-- Base Link -->
  <link name="link1">
    <collision>
      <origin xyz="0 0 ${height1/2}" rpy="0 0 0"/>
      <geometry>
        <box size="${width} ${width} ${height1}"/>
      </geometry>
    </collision>

    <visual>
      <origin xyz="0 0 ${height1/2}" rpy="0 0 0"/>
      <geometry>
        <box size="${width} ${width} ${height1}"/>
      </geometry>
      <material name="orange"/>
    </visual>

    <inertial>
      <origin xyz="0 0 ${height1/2}" rpy="0 0 0"/>
      <mass value="${mass}"/>
      <inertia ixx="${mass / 12.0 * (width*width + height1*height1)}" ixy="0.0" ixz="0.0" iyy="${mass / 12.0 * (height1*height1 + width*width)}" iyz="0.0" izz="${mass / 12.0 * (width*width + width*width)}"/>
    </inertial>
  </link>

  <joint name="joint1" type="continuous">
    <parent link="link1"/>
    <child link="link2"/>
    <origin xyz="0 ${width} ${height1 - axel_offset}" rpy="0 0 0"/>
    <axis xyz="0 1 0"/>
    <dynamics damping="0.7"/>
  </joint>

  <!-- Middle Link -->
  <link name="link2">
    <collision>
      <origin xyz="0 0 ${height2/2 - axel_offset}" rpy="0 0 0"/>
      <geometry>
        <box size="${width} ${width} ${height2}"/>
      </geometry>
    </collision>

    <visual>
      <origin xyz="0 0 ${height2/2 - axel_offset}" rpy="0 0 0"/>
      <geometry>
        <box size="${width} ${width} ${height2}"/>
      </geometry>
      <material name="black"/>
    </visual>

    <inertial>
      <origin xyz="0 0 ${height2/2 - axel_offset}" rpy="0 0 0"/>
      <mass value="${mass}"/>
      <inertia ixx="${mass / 12.0 * (width*width + height2*height2)}" ixy="0.0" ixz="0.0" iyy="${mass / 12.0 * (height2*height2 + width*width)}" iyz="0.0" izz="${mass / 12.0 * (width*width + width*width)}"/>
    </inertial>
  </link>

  <joint name="joint2" type="continuous">
    <parent link="link2"/>
    <child link="link3"/>
    <origin xyz="0 ${width} ${height2 - axel_offset*2}" rpy="0 0 0"/>
    <axis xyz="0 1 0"/>
    <dynamics damping="0.7"/>
  </joint>

  <!-- Top Link -->
  <link name="link3">
    <collision>
      <origin xyz="0 0 ${height3/2 - axel_offset}" rpy="0 0 0"/>
      <geometry>
        <box size="${width} ${width} ${height3}"/>
      </geometry>
    </collision>

    <visual>
      <origin xyz="0 0 ${height3/2 - axel_offset}" rpy="0 0 0"/>
      <geometry>
        <box size="${width} ${width} ${height3}"/>
      </geometry>
      <material name="orange"/>
    </visual>

    <inertial>
      <origin xyz="0 0 ${height3/2 - axel_offset}" rpy="0 0 0"/>
      <mass value="${mass}"/>
      <inertia ixx="${mass / 12.0 * (width*width + height3*height3)}" ixy="0.0" ixz="0.0" iyy="${mass / 12.0 * (height3*height3 + width*width)}" iyz="0.0" izz="${mass / 12.0 * (width*width + width*width)}"/>
    </inertial>
  </link>

  <!-- Hokuyo Laser 

  <joint name="hokuyo_joint" type="fixed">
    <axis xyz="0 1 0"/>
    <origin xyz="0 0 ${height3 - axel_offset/2}" rpy="0 0 0"/>
    <parent link="link3"/>
    <child link="hokuyo_link"/>
  </joint>

  <link name="hokuyo_link">
    <collision>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <geometry>
        <box size="0.1 0.1 0.1"/>
      </geometry>
    </collision>

    <visual>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <geometry>
        <mesh filename="$(find rrbot_description)/meshes/hokuyo.dae"/>
      </geometry>
    </visual>

    <inertial>
      <mass value="1e-5"/>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <inertia ixx="1e-6" ixy="0" ixz="0" iyy="1e-6" iyz="0" izz="1e-6"/>
    </inertial>
  </link>

  -->

  <joint name="camera_joint" type="fixed">
    <axis xyz="0 1 0"/>
    <origin xyz="${camera_link} 0 ${height3 - axel_offset*2}" rpy="0 0 0"/>
    <parent link="link3"/>
    <child link="camera_link"/>
  </joint>

  <!-- Camera -->
  <link name="camera_link">
    <collision>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <geometry>
        <box size="${camera_link} ${camera_link} ${camera_link}"/>
      </geometry>
    </collision>

    <visual>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <geometry>
        <box size="${camera_link} ${camera_link} ${camera_link}"/>
      </geometry>
      <material name="red"/>
    </visual>

    <inertial>
      <mass value="1e-5"/>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <inertia ixx="1e-6" ixy="0" ixz="0" iyy="1e-6" iyz="0" izz="1e-6"/>
    </inertial>
  </link>

  <!-- generate an optical frame http://www.ros.org/reps/rep-0103.html#suffix-frames
   so that ros and opencv can operate on the camera frame correctly -->
  <joint name="camera_optical_joint" type="fixed">
    <!-- these values have to be these values otherwise the gazebo camera image won't
     be aligned properly with the frame it is supposedly originating from -->
    <origin xyz="0 0 0" rpy="${-pi/2} 0 ${-pi/2}"/>
    <parent link="camera_link"/>
    <child link="camera_link_optical"/>
  </joint>

  <link name="camera_link_optical"></link>

  <!-- Gazebo's ros2_control plugin -->
  <gazebo>
    <plugin filename="libgazebo_ros2_control.so" name="gazebo_ros2_control">
      <robot_sim_type>gazebo_ros2_control/GazeboSystem</robot_sim_type>
      <parameters>$(find rrbot_controller)/config/rrbot_controllers_custom.yaml</parameters>
    </plugin>
  </gazebo>


</robot>

Also quick side note question do you know how to download the packages for the ros2_controls if you know how I can add that to my personal Ubuntu machine or ROS2 humble system to do the same examples on my own to do more independent learning? I appreciate the help and the continuous support truly. I only know how to download and colcon build the ros2_controls package in the github online rather than just downloading it into my ros2 terminal through a command line to download it correctly.

Thank you again for all the support.

Best regards,
Agarcia

Hi @Agarcia5612 ,

The error is quite informative:

[gzserver-x] [ERROR] [<timestamp>] [gazebo_ros2_control]: Error parsing 
URDF in gazebo_ros2_control plugin, plugin not active : no ros2_control tag

You have not added the <ros2_control>...</ros2_control> section in your URDF file!

  <ros2_control name="MyRobotSystem" type="system">
    <hardware>
      <plugin>gazebo_ros2_control/GazeboSystem</plugin>
    </hardware>
    <joint name="joint1">
      <command_interface name="position">
        <param name="min">-6.28</param>
        <param name="max">6.28</param>
      </command_interface>
      <state_interface name="position"/>
      <state_interface name="velocity"/>
      <state_interface name="effort"/>
    </joint>
    <joint name="joint2">
      <command_interface name="position">
        <param name="min">-6.28</param>
        <param name="max">6.28</param>
      </command_interface>
      <state_interface name="position"/>
      <state_interface name="velocity"/>
      <state_interface name="effort"/>
    </joint>
  </ros2_control>

Refer to this website: Getting Started — ROS2_Control: Humble Mar 2024 documentation

To install ROS2 Control Framework for ROS2 Humble Hawksbill on Ubuntu 22.04 Jammy Jellyfish:

sudo apt install -y ros-humble-ros2-control
sudo apt install -y ros-humble-ros2-controllers

This should solve your problem.

A tip for you for the future:
Try to take some notes on the common steps that are required, so you can check things yourself if you have made any mistake. That way, you can cross-check with your notes to see if you have missed any step when you get any errors during compilation or during execution.

Regards,
Girish

Hello @girishkumar.kannan,

Thank you that was the solution to this issue! Now I have a different error I believe is how I set up my rrbot controller. The error dictates that there is an issue with my XML file and Macro not matching when making a personal controller which I do not think I will do soon but I want to understand how these controllers were setup. I will add my XML file and dependencies I checked with the ones within the unit but all matched up so far. I already copy pasted the cpp code provided for the rrbot_controller.cpp so do not need to worry about that.

It did load the joint_state_broadcaster well!

Current Cmake list file content

cmake_minimum_required(VERSION 3.8)
project(rrbot_controller)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(control_msgs REQUIRED)
find_package(controller_interface REQUIRED)
find_package(hardware_interface REQUIRED)
find_package(pluginlib REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_lifecycle REQUIRED)
find_package(realtime_tools REQUIRED)
find_package(example_interfaces REQUIRED)

add_library(
  rrbot_controller
  SHARED
  src/rrbot_controller.cpp
)
target_include_directories(
  rrbot_controller
  PUBLIC
  $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
  $<INSTALL_INTERFACE:include>
)
ament_target_dependencies(
  rrbot_controller
  control_msgs
  controller_interface
  hardware_interface
  pluginlib
  rclcpp
  rclcpp_lifecycle
  realtime_tools
)
# prevent pluginlib from using boost
target_compile_definitions(rrbot_controller PUBLIC "PLUGINLIB__DISABLE_BOOST_FUNCTIONS")

pluginlib_export_plugin_description_file(
  controller_interface rrbot_controller.xml)

install(
  TARGETS
  rrbot_controller
  RUNTIME DESTINATION bin
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
)

install(
  DIRECTORY include/
  DESTINATION include
)

ament_export_include_directories(
  include
)
ament_export_libraries(
  rrbot_controller
)
ament_export_dependencies(
  control_msgs
  controller_interface
  hardware_interface
  pluginlib
  rclcpp
  rclcpp_lifecycle
  realtime_tools
)

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # uncomment the line when a copyright and license is not present in all source files
  #set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # uncomment the line when this package is not in a git repo
  #set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

install(
  DIRECTORY
    config
  DESTINATION
    share/${PROJECT_NAME}/
)
ament_package()

Package xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>rrbot_controller</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="user@todo.todo">user</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <depend>control_msgs</depend>
  <depend>controller_interface</depend>
  <depend>hardware_interface</depend>
  <depend>pluginlib</depend>
  <depend>rclcpp</depend>
  <depend>rclcpp_lifecycle</depend>
  <depend>realtime_tools</depend>
  <depend>example_interfaces</depend>

  <test_depend>ament_cmake_gmock</test_depend>
  <test_depend>controller_manager</test_depend>
  <test_depend>hardware_interface</test_depend>
  <test_depend>ros2_control_test_assets</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

RRbot controller XML file

<library path="rrbot_controller">
  <class name="rrbot_controller/RRBotController"
         type="rrbot_controller::RRBotController" base_class_type="controller_interface::ControllerInterface">
  <description>
    RRBotController ros2_control controller.
  </description>
  </class>
</library>

Thank you again for the assistance in how to download the ros2 controls I will use them for my moveit package build thank you so much. I will take notes of the aspects to take into consideration when building the robot: currently it’s been ros2 controls download, ros2 control yaml, ros control plugin hardware for each joint within urdf, gazebo plugin ros2_control within urdf, and the execution launch for the spawning of the robot with that finishing first then loading the controllers individually with a corresponding node.

Hi @Agarcia5612 ,

You need to stop posting errors here directly after you see them.
Try to understand the error first.
The error clearly states that your plugin has not been registered using the PLUGINLIB_EXPORT_CLASS. Did you add this line of code into your cpp file at the bottom?

There are some things that you need to check here:

  1. Check if you have registered the plugin using the pluginlib_export_class.
  2. Check if you are properly exporting the plugin in your CMakeLists.txt file.
  3. Check if you have added the plugin export in the package.xml file under <export>...</export> tag.
  4. Check if your plugin definition xml file is placed inside the package parent folder and has proper references to the library names.

MOST IMPORTANT: Take notes of the process and follow the course instructions!
Understand the errors and do some research before posting every error!
Try to back track your own process. Everything is not copy-paste situation.
How will you apply these to your own project if you are not following the steps correctly?

Regards,
Girish

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.