Noob trying To learn how To do a gazebo Car sim

Hi everyone,

I’m new to Gazebo and currently using ROS2 Humble. I already have a car modelled in URDF, and I’d like to learn how to set up a simulation with it in Gazebo.

My goal is to place the car in a Gazebo world where the track is based on a PNG image I have. I’d appreciate any guidance on how to load this PNG as the environment or terrain in the simulation, and how to correctly position my car within it.

Additionally, I have some control algorithms already implemented, and I’d like to know how I can integrate them with the simulation to start testing and controlling the car within this setup.

Any help or pointers would be greatly appreciated!

Thanks in advance!

Hello @Duarte_Antonio_Diama

Check the launch examples within this repository. It includes the procedure to launch a URDF or xacro file.

ros2_control is a library to implement controls for robotics. In addition, it includes a lot of off-the-shelf. Check if your algorithm has already been made in its documentation.

If you want to describe your robot properties in more detail (like friction and damping), I would suggest using SDF directly instead of URDF.

Regarding the simulation world, it must be declared in a SDF file. I would suggest using an example world and modifying the elements inside to include yours. Here you have the documentation of the geometry part of a model, which has elements image and heightmap. I personally haven’t tried them, but they should transform your flat image into a 3D model. The trickiest aspect is URI referencing IMHO. Beyond that, it should be easy to create a model of your environment.

If I got it wrong and you need a planar world but with the PNG file printed on top, my usual go-to is creating a rectangle in a CAD software, adding the image on top and exporting it as an OBJ file. Then I add it to the SDF file as a mesh.

Do you have previous experience with URDF, gazebo classic or ros2 launch files?

Help with Controlling Joints of ROS 2 Car Model

Dear Ignition Gazebo / ROS 2 Community,

I’m currently working on a small ROS 2 (Humble) project where I spawn a four‑wheeled car model in Ignition Gazebo and control it via ros2_control with a diff_drive_controller. Everything builds and launches correctly, but I’m not sure how to publish joint commands or velocities for the wheels directly. Could someone advise me on the best practice for commanding the individual wheel joints (either via ApplyJointEffort or through a ROS 2 controller)?

Project Structure


carro_ws/
└── src/
    └── carro_tutorial_yotube_copy/
        ├── CMakeLists.txt
        ├── package.xml
        ├── setup.py
        ├── ros2_controllers.yaml
        ├── launch/
        │   └── spawn_car.launch.py
        ├── worlds/
        │   └── empty_with_commands.sdf
        ├── urdf/
        │   ├── my_robot_com_mesh_1.urdf
        │   ├── my_robot.urdf
        │   ├── tentativa_gazebo_2.urdf
        │   └── tentativa_gazebo.urdf
        └── resource/
            └── carro_tutorial_yotube_copy
  

Key Files

ros2_controllers.yaml


controller_manager:
  ros__parameters:
    update_rate: 100
    joint_state_broadcaster:
      type: joint_state_broadcaster/JointStateBroadcaster
    diff_drive_controller:
      type: diff_drive_controller/DiffDriveController
      left_wheel_names:  [ base_back_left_wheel_joint, base_front_left_wheel_joint ]
      right_wheel_names: [ base_back_right_wheel_joint, base_front_right_wheel_joint ]
      wheel_separation: 0.51
      wheel_radius:     0.10
      cmd_vel_timeout:  0.25
  

launch/spawn_car.launch.py


#!/usr/bin/env python3
import os

from launch import LaunchDescription
from launch.actions import TimerAction, IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from ament_index_python.packages import get_package_share_directory
from launch_ros.actions import Node

def generate_launch_description():
pkg_share = get_package_share_directory(‘carro_tutorial_yotube_copy’)

gz_launch = IncludeLaunchDescription(
    PythonLaunchDescriptionSource(
        os.path.join(
            get_package_share_directory('ros_gz_sim'),
            'launch', 'gz_sim.launch.py'
        )
    ),
    launch_arguments={'gz_args': os.path.join(pkg_share, 'worlds', 'empty_with_commands.sdf')}.items()
)

# Publish URDF for ros2_control
urdf_file = os.path.join(pkg_share, 'urdf', 'my_robot_com_mesh_1.urdf')
with open(urdf_file, 'r') as inf:
    robot_desc = inf.read()
rsp_node = Node(
    package='robot_state_publisher',
    executable='robot_state_publisher',
    output='screen',
    parameters=[{'robot_description': robot_desc}]
)

# Start controller_manager
ros2_control_node = Node(
    package='controller_manager',
    executable='ros2_control_node',
    parameters=[os.path.join(pkg_share, 'ros2_controllers.yaml')],
    output='screen'
)

# Spawn the car
spawn_node = Node(
    package='ros_gz_sim',
    executable='create',
    name='spawn_car',
    output='screen',
    arguments=[
        '--world', 'empty',
        '--file', urdf_file,
        '--name', 'meu_carro',
        '--x', '0.0', '--y', '0.0', '--z', '0.4'
    ]
)
delayed_spawn = TimerAction(period=5.0, actions=[spawn_node])

return LaunchDescription([
    gz_launch,
    rsp_node,
    ros2_control_node,
    delayed_spawn
])

Questions

  • Is it better to use the /diff_drive_controller/cmd_vel topic, or call ApplyJointEffort services directly for each wheel joint?
  • If using ApplyJointEffort, how do I correctly configure and call it from ROS 2 so that Ignition Gazebo applies torque to my joints?
  • Any tips on tuning the diff_drive_controller parameters (wheel separation, radius, etc.) for realistic behavior?

Thank you for your assistance!
Best regards,
Duarte Diamantino

Hello Duarte,

There is a couple of questions,and your answers would help us to understand what you want to do.

  1. Have you been able to move the robot using the diff-drive controller? Or at least an example case?
  2. Why you want to control each wheel separately? Are you planning to implement your own controller?

Answering your questions:

  1. Diff-drive allows to control joint velocities, not torque. In addition, your command is forward velocity and yaw rate. If your real hardware only allows torque commands or if you want to control each wheel speed separately, then don’t use diff-drive. (Maybe this example is useful for you).
  2. ros2_control is independent of gazebo. Even if you use the plugin to interact with the simulation, the interface is still in ros2. Try to execute the diff-drive example.
  3. Most parameters in diff-drive are directly related to your URDF model. If you declare left_wheel_names, right_wheel_names, wheel_separation and wheel_radius, it should be a good start point. When it is working and only if needed, check each parameter to fine-tune the controller.

Regards,
Diego Cubillo

PS: I don’t know if the information in my first answer was helpful to you. It took a bit of time answering, and I would like some appreciation.