0
$\begingroup$

I want to implement a 4 wheel robot with car like steering(having 2 front steerable wheels and 2 back drive wheels) in ros2 using ros2_control. Can you suggest me which ros2 controller should I use(with example)? Is there any example I could refer to? The ros2_control documentation is not detailed enough and their example are mostly differential drive based.

Edit:

Distro: ros2-humble

Directory Structure

race_it_ws
    /src
        /race_it
            /description
                /race_car.xacro
                /ros2_ack.xacro
                /inertial.xacro
            /config
                /controller
                    /my_controllers.yaml
            /launch
                /rsp.launch.py
            /hardware       ## NOTE: I have just copied this folder from "ros2_control_demos/example_11" AS IT IS.                

Complete source code is provided below.

Description

race_car.xacro(main urdf file)

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

<xacro:include filename="inertial.xacro"/>
<!-- <xacro:include filename="gazebo_control_dd.xacro"/> -->
<!-- <xacro:include filename="gazebo_control_steer.xacro"/> -->

    
    <xacro:property name="wheel_width" value="0.04"/>
    <xacro:property name="wheel_radius" value="0.1"/>
    
    <!-- Wheel macro -->
    <xacro:macro name="wheel" params="name"> 
        <link name="${name}">
        <visual>
            <geometry>
                <cylinder length="${wheel_width}" radius="${wheel_radius}" />
            </geometry>
            <material name="blue"/>
        </visual>
        <collision>
            <geometry>
                <cylinder length="${wheel_width}" radius="${wheel_radius}" />
            </geometry>
        </collision>
         <xacro:inertial_cylinder mass="0.1" length="${wheel_width}" radius="${wheel_radius}"/>    
        </link>
        
        <gazebo reference="${name}">
            <material>Gazebo/Blue</material>
        </gazebo>   

    </xacro:macro>



  <!-- Base Link -->
  
  <link name="base_link">
  </link>

  <!-- Chassis Link -->
  <link name="chassis_link">
    <visual>
      <geometry>
        <box size="0.5 1.0 0.2"/>
      </geometry>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <material name="blue">
        <color rgba="0 0 1 1"/>
      </material>
    </visual>

    <xacro:inertial_box mass="0.5" x="0.5" y="1.0" z="0.15"/>

  </link>
    
  <gazebo reference="chassis_link">
        <material>Gazebo/Orange</material>
  </gazebo>   

  
 <!-- Base Chassis Joint -->
  <joint name="base_chassis_joint" type="fixed">
      <parent link="base_link"/>
      <child link="chassis_link"/>
      <origin xyz="0 0 0.2" rpy="0 0 0 "/>
  </joint>    
    
  
  <!-- Front Left Wheel -->
  <xacro:wheel name="front_left_link"/>
  
  <joint name="front_left_joint" type="continuous">
        <parent link="chassis_link"/>
        <child link="front_left_link"/>
        <origin xyz="-0.3 0.5 -0.1" rpy="0 ${pi/2} 0"/>
        <axis xyz="0 0 1"/>
  </joint>
  
   <gazebo reference="front_left_link">
       <material>Gazebo/Red</material>   
       <mu1 value="0.001"/>
       <mu2 value="0.001"/>
   </gazebo>
  
  
  <!-- Front Right Wheel -->
  <xacro:wheel name="front_right_link"/>
  
  <joint name="front_right_joint" type="continuous">
        <parent link="chassis_link"/>
        <child link="front_right_link"/>
        <origin xyz="0.3 0.5 -0.1" rpy="0 ${pi/2} 0"/>
        <axis xyz="0 0 1"/>
  </joint>
  
  <gazebo reference="front_right_link">   
       <material>Gazebo/Red</material>
       <mu1 value="0.001"/>
       <mu2 value="0.001"/>
  </gazebo>
  
  
  <!-- Rear Left Wheel -->
  <xacro:wheel name="rear_left_link"/>
  
  <joint name="rear_left_joint" type="continuous">
        <parent link="chassis_link"/>
        <child link="rear_left_link"/>
        <origin xyz="-0.3 -0.5 -0.1" rpy="0 ${pi/2} 0"/>
        <axis xyz="0 0 1"/>
  </joint>
    
  <!-- Rear Right Wheel -->  
  <xacro:wheel name="rear_right_link" />
  
  <joint name="rear_right_joint" type="continuous">
        <parent link="chassis_link"/>
        <child link="rear_right_link"/>
        <origin xyz="0.3 -0.5 -0.1" rpy="0 ${pi/2} 0"/> <!-- Default value for x is "0.27" -->
        <axis xyz="0 0 1"/>
  </joint>
  
  <xacro:include filename="ros2_ack.xacro"/>
      
</robot>

ros2_ack.xacro

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="simple_car">
    <ros2_control name="carbot" type="system">
        <hardware>
            <!-- <plugin>gazebo_ros2_control/GazeboSystem</plugin> -->
            
            <plugin>ros2_control_demo_example_11/CarlikeBotSystemHardware</plugin>
            <param name="example_param_hw_start_duration_sec">0</param>
            <param name="example_param_hw_stop_duration_sec">3.0</param>
            <param name="is_simulation">1</param>
                        
        </hardware>
        
        <!-- Front Left Wheel -->        
        <joint name="front_left_joint">
            <command_interface name="position"/>
            <state_interface name="position" />
        </joint>     
      
          <!-- Front Right Wheel -->         
          <joint name="front_right_joint">
            <command_interface name="position"/>
            <state_interface name="position" />
          </joint>       
          
          <!-- Rear Left Wheel -->          
          <joint name="rear_left_joint">
              <command_interface name="velocity"/>
              <state_interface name="velocity" />
          </joint>
            
          <!-- Rear Right Wheel -->            
          <joint name="rear_right_joint">
              <command_interface name="velocity"/>
              <state_interface name="velocity" />
          </joint>      
    </ros2_control>
    
    <gazebo>
        <plugin filename="libgazebo_ros2_control.so" name="gazebo_ros2_control">
            <parameters>$(find race_it)/config/controller/my_controllers.yaml</parameters>
        </plugin>
    </gazebo>
    
</robot>

Controller Config

my_controllers.yaml

controller_manager:
  ros__parameters:
    update_rate: 30
    
    use_sim_time: true
    
    asc:
        type: ackermann_steering_controller/AckermannSteeringController       
    
    jsc:
      type: joint_state_broadcaster/JointStateBroadcaster
    
asc:
  ros__parameters:

    reference_timeout: 2.0
    front_steering: true
    open_loop: false
    velocity_rolling_window_size: 10
    position_feedback: false
    use_stamped_vel: true
    #rear_wheels_names: [rear_right_joint, rear_left_joint]
    #front_wheels_names: [front_right_joint, front_left_joint]

    rear_wheels_names: [rear_right_joint, rear_left_joint]
    front_wheels_names: [front_right_joint, front_left_joint]


    wheelbase: 1.0
    front_wheel_track: 0.55
    rear_wheel_track: 0.55
    front_wheels_radius: 0.1
    rear_wheels_radius: 0.1
    
    
#jsc:
#  ros__parameters:
#    type: joint_state_controller/JointStateController

Launch File

rsp.launch.py

import os

from ament_index_python.packages import get_package_share_directory

from launch import LaunchDescription
from launch.substitutions import LaunchConfiguration
from launch.actions import DeclareLaunchArgument
from launch_ros.actions import Node
import launch_ros

from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource


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('race_it'))
    
    #xacro_file = os.path.join(pkg_path,'description','robot.urdf.xacro')
    xacro_file = os.path.join(pkg_path,'description', 'race_car.xacro')
    
    robot_description_config = xacro.process_file(xacro_file)
    
    default_rviz_config_path = os.path.join(pkg_path, 'config/rviz/urdf_config.rviz')
    
    # 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]
    )
    
    
        
    joint_state_publisher_node = launch_ros.actions.Node(
        package='joint_state_publisher',
        executable='joint_state_publisher',
        name='joint_state_publisher'
    )
    

    rviz_node = launch_ros.actions.Node(
        package='rviz2',
        executable='rviz2',
        name='rviz2',
        output='screen',
        arguments=['-d', default_rviz_config_path],
    )

    
    gazebo = IncludeLaunchDescription(
            PythonLaunchDescriptionSource([os.path.join(
            get_package_share_directory('gazebo_ros'), 'launch', 'gazebo.launch.py')])#,
    #        launch_arguments={'world': "my_bot/worlds/obstacles.world"}.items()
    )
    
    
    spawn_entity = launch_ros.actions.Node(
        package='gazebo_ros',
        executable='spawn_entity.py',
        arguments=['-entity', '', '-topic', 'robot_description'],
        output='screen'
    )


    # Launch!
    return LaunchDescription([
        DeclareLaunchArgument(
            'use_sim_time',
            default_value='true',
            description='Use sim time if true'),

        node_robot_state_publisher,
        joint_state_publisher_node,
        rviz_node,
        gazebo,
        spawn_entity
    ])
$\endgroup$

1 Answer 1

1
$\begingroup$

ackermann_steering_controller is what you are looking for. Have a look at this PR here.

However, we have some issues with the controller, see e.g. here. Please report a new issue if it doesn't work as expected.

$\endgroup$
13
  • $\begingroup$ Questions: 1. Where can i look to get content of <ros2_control> tag for ackermann steering? I have set up the config file using the links you provided. 2. I have kept joint type of all the 4 wheels as "continuous", would it be an issue for front steering wheels? 3. Generally if we are using any ros2_controller, how do we find out which command and state interfaces are available because the documentation(like you provided above) is never enough to get things running? $\endgroup$
    – Pratham
    Jan 1 at 5:20
  • $\begingroup$ Most controllers have documentation about the interfaces, ackermann is just a wrapper around steering_controller_library where you can find the requested information. And we are still trying to improve the docs, feedback is always welcome. $\endgroup$ Jan 1 at 16:12
  • $\begingroup$ In the linked PR above you find the complete ros2_control tag. $\endgroup$ Jan 1 at 16:12
  • $\begingroup$ Thanks for replying. Now i am trying to move the robot using "ros2 run teleop_twist_keyboard teleop_twist_keyboard" but the robot is not moving. To which topic should i publish control input to(using teleop_twist_keyboard). The following topics are available after running "ros2 topic list": /asc/controller_state /asc/odometry /asc/reference /asc/tf_odometry /asc/transition_event /clock /controller_manager/robot_description /joint_states /parameter_events /performance_metrics /robot_description /rosout /tf /tf_static Here "asc" is the "ackerman_steering_controller". $\endgroup$
    – Pratham
    Jan 2 at 7:03
  • $\begingroup$ Have remapped "teleop_twist_keybard" using "ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/asc/reference". Remapped to "/asc/reference" as well as "/asc/transition_event" but the bot is still not moving. Also i have put the following plugin under "ros2_control" "hardware" tag if that might be causing any issue. "hardware> <plugin>gazebo_ros2_control/GazeboSystem</plugin> </hardware>" $\endgroup$
    – Pratham
    Jan 2 at 7:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.