Ros2_control issues

Hi everybody,

i’m working on a 4 wheel autonomous robot simulation with ROS and Gazebo.
Currently it operates with the diff-drive plugin but i’m planning on switching to an ackerman steering approach. Therefore im trying to setup ros2_control, but i got quiet some problems with it:

My setup:
Ubuntu 20.04
Ros Foxy
Gazebo 11.11.0
installed ros2_control package via sudo apt install ros-foxy-gazebo-ros2-control
installed gazebo_ros2_control package via sudo apt install ros-foxy-gazebo-ros2-control

Inside my URDF File i configured ros2_control as follows:

  <!-- Position Config -->
  <ros2_control name="GazeboSystem" type="system">
    <hardware>
      <plugin>gazebo_ros2_control/GazeboSystem</plugin>
      <!-- <plugin>test_system</plugin> -->
    </hardware> 
    <joint name="front_right_steer_joint">
      <command_interface name="position">
        <param name="min">-0.45</param>
        <param name="max">0.45</param>
      </command_interface>
      <state_interface name="position"/>
      <state_interface name="velocity"/>
      <state_interface name="effort"/>
    </joint>
    <joint name="front_left_steer_joint">
      <command_interface name="position">
        <param name="min">-0.45</param>
        <param name="max">0.45</param>
      </command_interface>
      <state_interface name="position"/>
      <state_interface name="velocity"/>
      <state_interface name="effort"/>
    </joint>
  </ros2_control>

I also added the gazebo_ros2_control plugin to the URDF file:

  <gazebo>
    <plugin filename="libgazebo-ros2_control.so" name="gazebo_ros2_control">
      <parameters>$(find tunnel_bot)/config/steering_controller_position.yaml</parameters>
    </plugin>
  </gazebo>

And thats the used config file steering_controller_position.yaml:

controller_manager:
  ros__parameters:
    update_rate: 1  # Hz

    joint_trajectory_controller:
      type: joint_trajectory_controller/JointTrajectoryController

    joint_state_broadcaster:
      type: joint_state_broadcaster/JointStateBroadcaster

joint_trajectory_controller:
  ros__parameters:
    joints:
      - front_right_steer_joint
      - front_left_steer_joint
    interface_name: position
    command_interfaces:
      - position
    state_interfaces:
      - position
      - velocity

Now lets get into the issue:
When using the ros2_control hardware plugin gazebo_ros2_control/GazeboSystem im getting the following error:

[ros2_control_node-1] terminate called after throwing an instance of 'pluginlib::LibraryLoadException'
[ros2_control_node-1]   what():  According to the loaded plugin descriptions the class gazebo_ros2_control/GazeboSystem with base class type hardware_interface::SystemInterface does not exist. Declared types are  fake_components/GenericSystem test_hardware_components/TestSystemCommandModes test_hardware_components/TestTwoJointSystem test_system

what finally leads to:

[ERROR] [ros2_control_node-1]: process has died [pid 135528, exit code -6, cmd '/opt/ros/foxy/lib/controller_manager/ros2_control_node --ros-args --params-file /tmp/launch_params_3n96b75a --params-file /home/ima-untow/dev_ws/install/tunnel_bot/share/tunnel_bot/config/steering_controller_position.yaml'].

but when i search for the gazebo_ros2_control package i find inside /opt/ros/foxy/share/gazebo_ros2_control/gazebo_hardware_plugins.xml this:

<library path="gazebo_hardware_plugins">
  <class
    name="gazebo_ros2_control/GazeboSystem"
    type="gazebo_ros2_control::GazeboSystem"
    base_class_type="gazebo_ros2_control::GazeboSystemInterface">
    <description>
      GazeboPositionJoint
    </description>
  </class>
</library>

which in my eyes indicates that the plugin indeed is available.

If i use the test_system plugin istead:

  <ros2_control name="GazeboSystem" type="system">
    <hardware>
      <!-- <plugin>gazebo_ros2_control/GazeboSystem</plugin> -->
      <plugin>test_system</plugin>
    </hardware> 
    ...(same as above)...
  </ros2_control>

i get the following error:

[ros2_control_node-1] terminate called after throwing an instance of 'std::runtime_error'
[ros2_control_node-1]   what():  Wrong state or command interface configuration.
[ros2_control_node-1] missing state interfaces:
[ros2_control_node-1] ' front_right_steer_joint/effort '	' front_left_steer_joint/effort '	
[ros2_control_node-1] missing command interfaces:
[ros2_control_node-1] ' front_right_steer_joint/position '	' front_left_steer_joint/position '

So at this point i’m totally confused, because in my opinion the interfaces aren’t missing. Dont get me wrong, im trying to use the gazebo_ros2_control/GazeboSystem but thought it may be relevant that the output changes when using the test_system.

Can anyone help me out? Any hint is appreciated.
Thanks alot in advance.

P.S. If any further documentation or log-files are needed just say so - i’m quiet new to this.

Hey! Great question. This is also the first example of the inevitable issue where this is really a question that would be better suited to ROS answers so I’d want to encourage people to post questions there first, and then if they find an answer elsewhere (e.g. here) to go back and answer their own post.

That being said, I’d still like to help and I think I might have a solution (this is tied into the stuff for the video I’m currently working on!).

I think the problem is simply that when you added the libgazebo_ros2_control.so plugin, you have a hyphen after gazebo where there should be an underscore.
As far as I can tell, the actual interface plugin (which you managed to find) is not “visible” by default, but loading the other plugin makes it available, but that plugin is not being loaded correctly due to the wrong name.

So try fixing that and let us know how it goes, if it’s still not working we can keep looking :slight_smile:

Edit: Also, you probably know this but you will want to use the DiffDriveController rather than the JointTrajectoryController that you’ve mentioned.

1 Like

Hi Josh,
I’m speechless right now… thats such a dumb mistake… I tried fixing it for days.
You helped a lot, thank you so much!

I’m looking forward to your ros2_control video. Keep up the good work!
Greetings from Germany :slight_smile:

1 Like

Awesome! Good luck with the rest of the robot! (and feel free to post in the projects category if you’d like to show it off to others :slight_smile: )

1 Like

Hi Josh thanks a lot for the videos, They helped me a lot to understand ROS2 and how to build a differential drive bot. I am working on a 4 WD and have been following your tutorials until " [Using ros2_control to drive our robot (off the edge of the bench...)](https://www.youtube.com/watch?v=4VVrTCnxvSw&t=601s)" video. I am facing some trouble after changing to ros2_control, The issue is that my robot is not moving either left or right in gazebo but it seems to move in Rviz as expected. I have searched all the online resources but did not find anything that helps.
here is the link to my repo GitHub - BooraKaushik/autobot
Video of what is happening, IMG_5920.mov - Google Drive
as you can see it is turning fine in rviz but not in gazebo.

I would really appreciate any help.
Thanks,
Kaushik Boora

Hello @JoshNewans and @martoliod. I am currently trying to make my own 4 wheel autonomous robot following the Articulated Robotics series.

My setup is using Ubuntu-MATE 22.04 and ROS Humble. Is there a version of the ROS_Arduino_Bridge for 4 motors? Or should I be looking to use something else?

I have a Raspberry Pi 4 connected to an Arduino Mega that controls my 4 motors. If anyone has any advice please let me know.

i’m working on a 2 wheel autonomous robot simulation with ROS2 and Gazebo. when never I launch this file gazebo sever crashing error Therefore im trying to setup ros2_control, but i got quiet some problems with it:

My setup: Ubuntu 22.04 Ros humble Gazebo 11.10.2

ros2 launch autonomous_bot launch_sim.launch.py 
[INFO] [launch]: All log files can be found below /home/rushabh/.ros/log/2024-04-10-10-20-53-087448-rushabh-Aspire-A515-57G-24269
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [robot_state_publisher-1]: process started with pid [24270]
[INFO] [gzserver-2]: process started with pid [24272]
[INFO] [gzclient-3]: process started with pid [24274]
[INFO] [spawn_entity.py-4]: process started with pid [24276]
[robot_state_publisher-1] [INFO] [1712724653.565116469] [robot_state_publisher]: got segment base_footprint
[robot_state_publisher-1] [INFO] [1712724653.565180780] [robot_state_publisher]: got segment base_link
[robot_state_publisher-1] [INFO] [1712724653.565187384] [robot_state_publisher]: got segment caster_wheel
[robot_state_publisher-1] [INFO] [1712724653.565191307] [robot_state_publisher]: got segment chassis
[robot_state_publisher-1] [INFO] [1712724653.565194777] [robot_state_publisher]: got segment laser_frame
[robot_state_publisher-1] [INFO] [1712724653.565198448] [robot_state_publisher]: got segment left_wheel
[robot_state_publisher-1] [INFO] [1712724653.565201901] [robot_state_publisher]: got segment right_wheel
[spawn_entity.py-4] [INFO] [1712724653.897650338] [spawn_entity]: Spawn Entity started
[spawn_entity.py-4] [INFO] [1712724653.897867387] [spawn_entity]: Loading entity published on topic robot_description
[spawn_entity.py-4] /opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/qos.py:307: UserWarning: DurabilityPolicy.RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL is deprecated. Use DurabilityPolicy.TRANSIENT_LOCAL instead.
[spawn_entity.py-4]   warnings.warn(
[spawn_entity.py-4] [INFO] [1712724653.899170320] [spawn_entity]: Waiting for entity xml on robot_description
[spawn_entity.py-4] [INFO] [1712724653.901625135] [spawn_entity]: Waiting for service /spawn_entity, timeout = 30
[spawn_entity.py-4] [INFO] [1712724653.901805336] [spawn_entity]: Waiting for service /spawn_entity
[spawn_entity.py-4] [INFO] [1712724654.406948601] [spawn_entity]: Calling service /spawn_entity
[spawn_entity.py-4] [INFO] [1712724654.503504374] [spawn_entity]: Spawn status: SpawnEntity: Successfully spawned entity [my_bot]
[gzserver-2] [WARN] [1712724654.505842505] [rcl]: Found remap rule '~/out:=scan'. This syntax is deprecated. Use '--ros-args --remap ~/out:=scan' instead.
[gzserver-2] [WARN] [1712724654.507346550] [rcl]: Found remap rule '~/out:=scan'. This syntax is deprecated. Use '--ros-args --remap ~/out:=scan' instead.
[gzserver-2] [INFO] [1712724654.620310544] [gazebo_ros2_control]: Loading gazebo_ros2_control plugin
[gzserver-2] [INFO] [1712724654.621628001] [gazebo_ros2_control]: Starting gazebo_ros2_control plugin in namespace: /
[gzserver-2] [INFO] [1712724654.621737794] [gazebo_ros2_control]: Starting gazebo_ros2_control plugin in ros 2 node: gazebo_ros2_control
[gzserver-2] [INFO] [1712724654.622666022] [gazebo_ros2_control]: connected to service!! robot_state_publisher
[gzserver-2] [INFO] [1712724654.623100631] [gazebo_ros2_control]: Received urdf from param server, parsing...
[gzserver-2] [INFO] [1712724654.623122673] [gazebo_ros2_control]: Loading parameter files /home/rushabh/ros2_ws/install/autonomous_bot/share/autonomous_bot/config/my_controller.yaml
[gzserver-2] [INFO] [1712724654.630469268] [gazebo_ros2_control]: Loading joint: left_wheel_joint
[gzserver-2] [INFO] [1712724654.630495525] [gazebo_ros2_control]: 	State:
[gzserver-2] [INFO] [1712724654.630511420] [gazebo_ros2_control]: 		 velocity
[gzserver-2] [INFO] [1712724654.630516726] [gazebo_ros2_control]: 		 position
[gzserver-2] [INFO] [1712724654.630521067] [gazebo_ros2_control]: 	Command:
[gzserver-2] [INFO] [1712724654.630537652] [gazebo_ros2_control]: 		 velocity
[gzserver-2] [INFO] [1712724654.630544866] [gazebo_ros2_control]: Loading joint: right_wheel_joint
[gzserver-2] [INFO] [1712724654.630549345] [gazebo_ros2_control]: 	State:
[gzserver-2] [INFO] [1712724654.630553345] [gazebo_ros2_control]: 		 velocity
[gzserver-2] [INFO] [1712724654.630557432] [gazebo_ros2_control]: 		 position
[gzserver-2] [INFO] [1712724654.630561172] [gazebo_ros2_control]: 	Command:
[gzserver-2] [INFO] [1712724654.630566595] [gazebo_ros2_control]: 		 velocity
[gzserver-2] [INFO] [1712724654.630588565] [resource_manager]: Initialize hardware 'GazeboSystem' 
[gzserver-2] [INFO] [1712724654.630656757] [resource_manager]: Successful initialization of hardware 'GazeboSystem'
[gzserver-2] [INFO] [1712724654.630698827] [resource_manager]: 'configure' hardware 'GazeboSystem' 
[gzserver-2] [INFO] [1712724654.630703790] [resource_manager]: Successful 'configure' of hardware 'GazeboSystem'
[gzserver-2] [INFO] [1712724654.630707221] [resource_manager]: 'activate' hardware 'GazeboSystem' 
[gzserver-2] [INFO] [1712724654.630710405] [resource_manager]: Successful 'activate' of hardware 'GazeboSystem'
[gzserver-2] [INFO] [1712724654.630769214] [gazebo_ros2_control]: Loading controller_manager
[INFO] [spawn_entity.py-4]: process has finished cleanly [pid 24276]
[ERROR] [gzserver-2]: process has died [pid 24272, exit code -11, cmd 'gzserver -slibgazebo_ros_init.so -slibgazebo_ros_factory.so -slibgazebo_ros_force_system.so'].
[ERROR] [gzclient-3]: process has died [pid 24274, exit code 255, cmd 'gzclient'].

robot.xarco

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

        <ros2_control name="GazeboSystem" type="system">
            <hardware>
                <plugin>gazebo_ros2_control/GazeboSystem</plugin>
            </hardware>
            <joint name="left_wheel_joint">
                <command_interface name="velocity">
                    <param name="min">-10</param>
                    <param name="max">10</param>
                </command_interface>
                <state_interface name="velocity"/>
                <state_interface name="position"/>
            </joint>
            <joint name="right_wheel_joint">
                <command_interface name="velocity">
                    <param name="min">-10</param>
                    <param name="max">10</param>
                </command_interface>
                <state_interface name="velocity"/>
                <state_interface name="position"/>
            </joint>
        </ros2_control>
         <gazebo>
        <plugin name="gazebo_ros2_control" filename="libgazebo_ros2_control.so">
            <parameters>$(find autonomous_bot)/config/my_controller.yaml</parameters>
        </plugin>
    </gazebo>
</robot>
my_controller.yaml

controller_manager:
  ros__parameters:
    
    
    update_rate: 30.0
    use_sim_time: true


    diff_cont:
      type: diff_drive_controller/DiffDriveController

    joint_board:
      type: joint_state_broadcaster/JointStateBroadcaster

diff_cont:
  ros__parameters:

     publish_rate: 50.0

     base_frame_id: base link

     left_wheel_names: ['left_wheel_joint']
     right_wheel_names: ['right_wheel_joint']
     wheel_separation: 0.35
     wheel_radius: 0.05

     use_stamped_vel: false

hi i create a custom_hardware_interface using with our tutorial

here is my files one by one

#include “…/include/kevell_hardware_interface/kevell_hardware_interface.hpp”
#include <hardware_interface/types/hardware_interface_type_values.hpp>

hardware_interface::CallbackReturn KevellHardware::on_init(const hardware_interface::HardwareInfo &info) {
RCLCPP_INFO(rclcpp::get_logger(“KevellHardware”), “Initializing hardware…”);

// Initialize serial communication
try {
    serial_conn.setPort("/dev/ttyUSB0");
    serial_conn.setBaudrate(115200);
    serial_conn.open();
    RCLCPP_ERROR(rclcpp::get_logger("KevellHardware"), "open a serial port successfully...");
} catch (const serial::IOException &e) {
    RCLCPP_ERROR(rclcpp::get_logger("KevellHardware"), "Unable to open serial port: %s", e.what());
    return hardware_interface::CallbackReturn::ERROR;
}

if (!serial_conn.isOpen()) {
    RCLCPP_ERROR(rclcpp::get_logger("KevellHardware"), "Serial port not open.");
    return hardware_interface::CallbackReturn::ERROR;
}

  for (const hardware_interface::ComponentInfo & joint : info_.joints)

{
// DiffBotSystem has exactly two states and one command interface on each joint
if (joint.command_interfaces.size() != 1)
{
RCLCPP_FATAL(
rclcpp::get_logger(“DiffDriveArduinoHardware”),
“Joint ‘%s’ has %zu command interfaces found. 1 expected.”, joint.name.c_str(),
joint.command_interfaces.size());
return hardware_interface::CallbackReturn::ERROR;
}

if (joint.command_interfaces[0].name != hardware_interface::HW_IF_VELOCITY)
{
  RCLCPP_FATAL(
    rclcpp::get_logger("DiffDriveArduinoHardware"),
    "Joint '%s' have %s command interfaces found. '%s' expected.", joint.name.c_str(),
    joint.command_interfaces[0].name.c_str(), hardware_interface::HW_IF_VELOCITY);
  return hardware_interface::CallbackReturn::ERROR;
}

if (joint.state_interfaces.size() != 2)
{
  RCLCPP_FATAL(
    rclcpp::get_logger("DiffDriveArduinoHardware"),
    "Joint '%s' has %zu state interface. 2 expected.", joint.name.c_str(),
    joint.state_interfaces.size());
  return hardware_interface::CallbackReturn::ERROR;
}

if (joint.state_interfaces[0].name != hardware_interface::HW_IF_POSITION)
{
  RCLCPP_FATAL(
    rclcpp::get_logger("DiffDriveArduinoHardware"),
    "Joint '%s' have '%s' as first state interface. '%s' expected.", joint.name.c_str(),
    joint.state_interfaces[0].name.c_str(), hardware_interface::HW_IF_POSITION);
  return hardware_interface::CallbackReturn::ERROR;
}

if (joint.state_interfaces[1].name != hardware_interface::HW_IF_VELOCITY)
{
  RCLCPP_FATAL(
    rclcpp::get_logger("DiffDriveArduinoHardware"),
    "Joint '%s' have '%s' as second state interface. '%s' expected.", joint.name.c_str(),
    joint.state_interfaces[1].name.c_str(), hardware_interface::HW_IF_VELOCITY);
  return hardware_interface::CallbackReturn::ERROR;
}

}

RCLCPP_INFO(rclcpp::get_logger("KevellHardware"), "Hardware initialized successfully.");
return hardware_interface::CallbackReturn::SUCCESS;

}

hardware_interface::CallbackReturn KevellHardware::on_activate(const rclcpp_lifecycle::State &) {
RCLCPP_INFO(rclcpp::get_logger(“KevellHardware”), “Activating hardware…”);
return hardware_interface::CallbackReturn::SUCCESS;
}

hardware_interface::CallbackReturn KevellHardware::on_deactivate(const rclcpp_lifecycle::State &) {
RCLCPP_INFO(rclcpp::get_logger(“KevellHardware”), “Deactivating hardware…”);
return hardware_interface::CallbackReturn::SUCCESS;
}

std::vector<hardware_interface::StateInterface> KevellHardware::export_state_interfaces() {
RCLCPP_INFO(rclcpp::get_logger(“KevellHardware”), “Exporting state interfaces…”);
std::vector<hardware_interface::StateInterface> state_interfaces;

state_interfaces.emplace_back(hardware_interface::StateInterface("left_wheel_joint", hardware_interface::HW_IF_POSITION, &position_states[0]));
state_interfaces.emplace_back(hardware_interface::StateInterface("left_wheel_joint", hardware_interface::HW_IF_VELOCITY, &velocity_states[0]));
state_interfaces.emplace_back(hardware_interface::StateInterface("right_wheel_joint", hardware_interface::HW_IF_POSITION, &position_states[1]));
state_interfaces.emplace_back(hardware_interface::StateInterface("right_wheel_joint", hardware_interface::HW_IF_VELOCITY, &velocity_states[1]));

return state_interfaces;

}

std::vector<hardware_interface::CommandInterface> KevellHardware::export_command_interfaces() {
RCLCPP_INFO(rclcpp::get_logger(“KevellHardware”), “Exporting command interfaces…”);
std::vector<hardware_interface::CommandInterface> command_interfaces;

command_interfaces.emplace_back(hardware_interface::CommandInterface("left_wheel_joint", hardware_interface::HW_IF_VELOCITY, &velocity_commands[0]));
command_interfaces.emplace_back(hardware_interface::CommandInterface("right_wheel_joint", hardware_interface::HW_IF_VELOCITY, &velocity_commands[1]));

return command_interfaces;

}

hardware_interface::return_type KevellHardware::read(const rclcpp::Time &, const rclcpp::Duration &) {
if (!serial_conn.isOpen()) {
RCLCPP_ERROR(rclcpp::get_logger(“KevellHardware”), “Serial connection lost!”);
return hardware_interface::return_type::ERROR;
}

std::string response;
try {
    serial_conn.write("READ\n");
    response = serial_conn.readline();
} catch (const serial::IOException &e) {
    RCLCPP_ERROR(rclcpp::get_logger("KevellHardware"), "Serial read error: %s", e.what());
    return hardware_interface::return_type::ERROR;
}

// Example parsing: "ENC 500 480"
int left_encoder, right_encoder;
if (sscanf(response.c_str(), "ENC %d %d", &left_encoder, &right_encoder) == 2) {
    position_states[0] = (left_encoder / ticks_per_revolution) * 2 * M_PI;
    position_states[1] = (right_encoder / ticks_per_revolution) * 2 * M_PI;
    velocity_states[0] = (position_states[0] - left_encoder_prev) / 0.1;
    velocity_states[1] = (position_states[1] - right_encoder_prev) / 0.1;

    left_encoder_prev = left_encoder;
    right_encoder_prev = right_encoder;
} else {
    RCLCPP_ERROR(rclcpp::get_logger("KevellHardware"), "Invalid encoder data received!");
    return hardware_interface::return_type::ERROR;
}

return hardware_interface::return_type::OK;

}

hardware_interface::return_type KevellHardware::write(const rclcpp::Time &, const rclcpp::Duration &) {
if (!serial_conn.isOpen()) {
RCLCPP_ERROR(rclcpp::get_logger(“KevellHardware”), “Serial connection lost!”);
return hardware_interface::return_type::ERROR;
}

char command[50];
snprintf(command, sizeof(command), "CMD %.2f %.2f\n", velocity_commands[0], velocity_commands[1]);

try {
    serial_conn.write(command);
} catch (const serial::IOException &e) {
    RCLCPP_ERROR(rclcpp::get_logger("KevellHardware"), "Serial write error: %s", e.what());
    return hardware_interface::return_type::ERROR;
}

return hardware_interface::return_type::OK;

}
#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS(KevellHardware, hardware_interface::SystemInterface)

and launch file

import os
import launch
import launch_ros.actions
from launch.substitutions import Command, FindExecutable, PathJoinSubstitution
from launch_ros.substitutions import FindPackageShare
from ament_index_python.packages import get_package_share_directory

def generate_launch_description():

robot_description_content = Command(
    [
        PathJoinSubstitution([FindExecutable(name="xacro")]),
        " ",
        PathJoinSubstitution(
            [FindPackageShare("kevell_hardware_interface"), "urdf", "robot_urdf.xacro"]
        ),
    ]
)
robot_description = {"robot_description": robot_description_content}
kevell_hardware_config = os.path.join(
    get_package_share_directory('kevell_hardware_interface'), 'config', 'kevell_controllers.yaml'
)

return launch.LaunchDescription([
    launch_ros.actions.Node(
        package='controller_manager',
        executable='ros2_control_node',
        parameters=[robot_description,kevell_hardware_config],
        output='screen'
    ),
    launch_ros.actions.Node(
        package='robot_state_publisher',
        executable='robot_state_publisher',
        parameters=[robot_description],
        output='screen'
    ),    
    launch_ros.actions.Node(
        package='controller_manager',
        executable='spawner',
        arguments=["joint_state_broadcaster", "--controller-manager", "/controller_manager"],
        output='screen'
    ),
    launch_ros.actions.Node(
        package='controller_manager',
        executable='spawner',
        arguments=["diffbot_base_controller", "--controller-manager", "/controller_manager"],
        output='screen'
    )
])

and the config file is

controller_manager:
ros__parameters:
update_rate: 10 # Hz

diffbot_base_controller:
  type: diff_drive_controller/DiffDriveController
  #left_wheel_names: ["left_wheel_joint"]
  #right_wheel_names: ["right_wheel_joint"]
  #command_interfaces: 
    #- velocity
  #state_interfaces: 
    #- position
    #- velocity

joint_state_broadcaster:
  type: joint_state_broadcaster/JointStateBroadcaster
  joints: ["left_wheel_joint", "right_wheel_joint"]

diffbot_base_controller:
ros__parameters:
publish_rate: 50.0
left_wheel_names: [“left_wheel_joint”]
right_wheel_names: [“right_wheel_joint”]
wheels_per_side: 1
wheel_separation: 0.3
wheel_radius: 0.05
base_frame_id: base_link
use_stamped_vel: false

linear.x.has_velocity_limits: false
linear.x.has_acceleration_limits: false
linear.x.has_jerk_limits: false
linear.x.max_velocity: 1.0  # Changed from 0.0 to avoid divide-by-zero errors
linear.x.min_velocity: -1.0  # Allow backward motion
linear.x.max_acceleration: 1.0
linear.x.min_acceleration: -1.0
linear.x.max_jerk: 0.5
linear.x.min_jerk: -0.5

angular.z.has_velocity_limits: false
angular.z.has_acceleration_limits: false
angular.z.has_jerk_limits: false
angular.z.max_velocity: 1.0
angular.z.min_velocity: -1.0
angular.z.max_acceleration: 1.0
angular.z.min_acceleration: -1.0
angular.z.max_jerk: 0.5
angular.z.min_jerk: -0.5

but i got a error is below

kevell@kevell-All-Series:~/hardware$ ros2 launch kevell_hardware_interface control_launch.py
[INFO] [launch]: All log files can be found below /home/kevell/.ros/log/2025-02-28-19-03-32-798911-kevell-All-Series-19436
[INFO] [launch]: Default logging verbosity is set to INFO
[INFO] [ros2_control_node-1]: process started with pid [19439]
[INFO] [robot_state_publisher-2]: process started with pid [19441]
[INFO] [spawner-3]: process started with pid [19443]
[INFO] [spawner-4]: process started with pid [19445]
[ros2_control_node-1] [WARN] [1740749613.110076083] [controller_manager]: [Deprecated] Passing the robot description parameter directly to the control_manager node is deprecated. Use ‘~/robot_description’ topic from ‘robot_state_publisher’ instead.
[ros2_control_node-1] [INFO] [1740749613.110290349] [resource_manager]: Loading hardware ‘KevellHardware’
[robot_state_publisher-2] Warning: link ‘chassis’ material ‘white’ undefined.
[robot_state_publisher-2] at line 84 in ./urdf_parser/src/model.cpp
[robot_state_publisher-2] Warning: link ‘chassis’ material ‘white’ undefined.
[robot_state_publisher-2] at line 84 in ./urdf_parser/src/model.cpp
[robot_state_publisher-2] Warning: link ‘left_wheel’ material ‘blue’ undefined.
[robot_state_publisher-2] at line 84 in ./urdf_parser/src/model.cpp
[robot_state_publisher-2] Warning: link ‘left_wheel’ material ‘blue’ undefined.
[robot_state_publisher-2] at line 84 in ./urdf_parser/src/model.cpp
[robot_state_publisher-2] Warning: link ‘right_wheel’ material ‘blue’ undefined.
[robot_state_publisher-2] at line 84 in ./urdf_parser/src/model.cpp
[robot_state_publisher-2] Warning: link ‘right_wheel’ material ‘blue’ undefined.
[robot_state_publisher-2] at line 84 in ./urdf_parser/src/model.cpp
[robot_state_publisher-2] [INFO] [1740749613.111400508] [robot_state_publisher]: got segment base_link
[ros2_control_node-1] [INFO] [1740749613.112011579] [resource_manager]: Initialize hardware ‘KevellHardware’
[ros2_control_node-1] [INFO] [1740749613.112055724] [KevellHardware]: Initializing hardware…
[robot_state_publisher-2] [INFO] [1740749613.112311681] [robot_state_publisher]: got segment chassis
[robot_state_publisher-2] [INFO] [1740749613.112346758] [robot_state_publisher]: got segment left_wheel
[robot_state_publisher-2] [INFO] [1740749613.112363006] [robot_state_publisher]: got segment right_wheel
[ros2_control_node-1] [ERROR] [1740749613.115097096] [KevellHardware]: open a serial port successfully…
[ros2_control_node-1] [INFO] [1740749613.115144954] [KevellHardware]: Hardware initialized successfully.
[ros2_control_node-1] [INFO] [1740749613.115166922] [resource_manager]: Successful initialization of hardware ‘KevellHardware’
[ros2_control_node-1] [INFO] [1740749613.115178039] [KevellHardware]: Exporting state interfaces…
[ros2_control_node-1] [INFO] [1740749613.115286870] [KevellHardware]: Exporting command interfaces…
[ros2_control_node-1] [INFO] [1740749613.115452671] [resource_manager]: ‘configure’ hardware ‘’
[ros2_control_node-1] [INFO] [1740749613.115467618] [resource_manager]: Successful ‘configure’ of hardware ‘’
[ros2_control_node-1] [INFO] [1740749613.115475789] [resource_manager]: ‘activate’ hardware ‘’
[ros2_control_node-1] [INFO] [1740749613.115483704] [KevellHardware]: Activating hardware…
[ros2_control_node-1] [INFO] [1740749613.115491566] [resource_manager]: Successful ‘activate’ of hardware ‘’
[ros2_control_node-1] [INFO] [1740749613.121765422] [controller_manager]: update rate is 10 Hz
[ros2_control_node-1] [WARN] [1740749613.122487251] [controller_manager]: No real-time kernel detected on this system. See [Controller Manager — ROS2_Control: Rolling Feb 2025 documentation] for details on how to enable realtime scheduling.
[ros2_control_node-1] [ERROR] [1740749613.123014530] [KevellHardware]: Invalid encoder data received!
[ros2_control_node-1] [INFO] [1740749613.410553873] [controller_manager]: Loading controller ‘joint_state_broadcaster’
[ros2_control_node-1] [INFO] [1740749613.435844232] [controller_manager]: Loading controller ‘diffbot_base_controller’
[spawner-3] [INFO] [1740749613.444040377] [spawner_joint_state_broadcaster]: Loaded joint_state_broadcaster
[ros2_control_node-1] [INFO] [1740749613.523164696] [controller_manager]: Configuring controller ‘joint_state_broadcaster’
[ros2_control_node-1] [INFO] [1740749613.523369036] [joint_state_broadcaster]: ‘joints’ or ‘interfaces’ parameter is empty. All available state interfaces will be published
[spawner-4] [INFO] [1740749613.542315886] [spawner_diffbot_base_controller]: Loaded diffbot_base_controller
[ros2_control_node-1] [INFO] [1740749613.622852558] [controller_manager]: Configuring controller ‘diffbot_base_controller’
[ros2_control_node-1] [ERROR] [1740749613.822659800] [joint_state_broadcaster]: None of requested interfaces exist. Controller will not run.
[ros2_control_node-1] [WARN] [1740749613.822701272] [joint_state_broadcaster]: Error occurred while doing error handling.
[ros2_control_node-1] [ERROR] [1740749613.822740574] [controller_manager]: After activation, controller ‘joint_state_broadcaster’ is in state ‘unconfigured’ (1), expected ‘active’ (3).
[ros2_control_node-1] [ERROR] [1740749613.923127704] [resource_manager]: Not acceptable command interfaces combination:
[ros2_control_node-1] Start interfaces:
[ros2_control_node-1] [
[ros2_control_node-1] left_wheel_joint/velocity
[ros2_control_node-1] right_wheel_joint/velocity
[ros2_control_node-1] ]
[ros2_control_node-1] Stop interfaces:
[ros2_control_node-1] [
[ros2_control_node-1] ]
[ros2_control_node-1] Not available:
[ros2_control_node-1] [
[ros2_control_node-1] left_wheel_joint/velocity
[ros2_control_node-1] right_wheel_joint/velocity
[ros2_control_node-1] ]
[ros2_control_node-1]
[ros2_control_node-1] [ERROR] [1740749613.923163006] [controller_manager]: Could not switch controllers since prepare command mode switch was rejected.
[spawner-3] [INFO] [1740749613.923917841] [spawner_joint_state_broadcaster]: Configured and activated joint_state_broadcaster
[spawner-4] [ERROR] [1740749613.924526640] [spawner_diffbot_base_controller]: Failed to activate controller
[INFO] [spawner-3]: process has finished cleanly [pid 19443]
[ERROR] [spawner-4]: process has died [pid 19445, exit code 1, cmd ‘/opt/ros/humble/lib/controller_manager/spawner diffbot_base_controller --controller-manager /controller_manager --ros-args’].
^C[WARNING] [launch]: user interrupted with ctrl-c (SIGINT)
[robot_state_publisher-2] [INFO] [1740749623.278484912] [rclcpp]: signal_handler(signum=2)
[ros2_control_node-1] [INFO] [1740749623.278484852] [rclcpp]: signal_handler(signum=2)
[INFO] [ros2_control_node-1]: process has finished cleanly [pid 19439]
[INFO] [robot_state_publisher-2]: process has finished cleanly [pid 19441]

so expertise i have mess about confusion please help for me