I've been building a 4 wheel differential drive robot (all 4 wheels have motors) and I've noticed that when I control the robot, in Gazebo it barely turns while in RViz it turns a lot more. This causes a lot of desync and I've been trying to solve it for quite some time now.
I'm working on a VM, VMWare Workstation 16 running Ubuntu 22.04.3 LTS. I have ROS2 Iron and I'm using ros2_control for moving the robot. For now, I'm using RViz2 and Gazebo to simulate the robot (I don't know which version of Gazebo I have, it auto-installed based on my ROS2 version).
You can find all the code here https://github.com/ClauPan/Vox/tree/main/src
Here is my urdf for the robot structure (the numbers for the different parameters are based on the dimensions of my real robot, which I plan to use this code for):
<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro">
<xacro:include filename="colors.xacro"/>
<!-- BASE LINK -->
<link name="base_link"></link>
<!-- BASE FOOTPRINT LINK -->
<joint name="base_footprint_joint" type="fixed">
<parent link="base_link"/>
<child link="base_footprint"/>
<origin xyz="0 0 0" rpy="0 0 0"/>
</joint>
<link name="base_footprint"></link>
<!-- CHASSIS LINK -->
<joint name="chassis_joint" type="fixed">
<parent link="base_link"/>
<child link="chassis"/>
<origin xyz="-0.105 0 0"/>
</joint>
<link name="chassis">
<parent link="chassis_joint"/>
<visual>
<geometry>
<box size="0.21 0.135 0.0475"/>
</geometry>
<material name="white"/>
</visual>
<collision>
<geometry>
<box size="0.21 0.135 0.0475"/>
</geometry>
</collision>
<inertial>
<origin xyz="0 0 0" rpy="0 0 0"/>
<mass value="0.67"/>
<inertia
ixx="${(1/12) * 0.67 * (0.135*0.135+0.0475*0.0475)}" ixy="0.0" ixz="0.0"
iyy="${(1/12) * 0.67 * (0.21*0.21+0.0475*0.0475)}" iyz="0.0"
izz="${(1/12) * 0.67 * (0.21*0.21+0.135*0.135)}"
/>
</inertial>
</link>
<gazebo reference="chassis">
<material>Gazebo/White</material>
</gazebo>
<joint name="front_left_wheel_joint" type="continuous">
<parent link="chassis"/>
<child link="front_left_wheel"/>
<origin xyz="-0.08 0.1145 0" rpy="-${pi/2} 0 0"/>
<axis xyz="0 0 1"/>
</joint>
<link name="front_left_wheel">
<visual>
<geometry>
<cylinder radius="0.06" length="0.06"/>
</geometry>
<material name="blue"/>
</visual>
<collision>
<geometry>
<!-- <cylinder radius="0.06" length="0.06"/> -->
<sphere radius="0.06"/>
</geometry>
</collision>
<inertial>
<origin xyz="0 0 0" rpy="0 0 0"/>
<mass value="0.17"/>
<inertia
ixx="${(1/12) * 0.17 * (3*0.06*0.06 + 0.06*0.06)}" ixy="0.0" ixz="0.0"
iyy="${(1/12) * 0.17 * (3*0.06*0.06 + 0.06*0.06)}" iyz="0.0"
izz="${(1/12) * 0.17 * (0.06*0.06)}"
/>
</inertial>
</link>
<gazebo reference="front_left_wheel">
<material>Gazebo/Blue</material>
</gazebo>
<joint name="front_right_wheel_joint" type="continuous">
<parent link="chassis"/>
<child link="front_right_wheel"/>
<origin xyz="-0.08 -0.1145 0" rpy="${pi/2} 0 0"/>
<axis xyz="0 0 -1"/>
</joint>
<link name="front_right_wheel">
<visual>
<geometry>
<cylinder radius="0.06" length="0.06"/>
</geometry>
<material name="blue"/>
</visual>
<collision>
<geometry>
<!-- <cylinder radius="0.06" length="0.06"/> -->
<sphere radius="0.06"/>
</geometry>
</collision>
<inertial>
<origin xyz="0 0 0" rpy="0 0 0"/>
<mass value="0.17"/>
<inertia
ixx="${(1/12) * 0.17 * (3*0.06*0.06 + 0.06*0.06)}" ixy="0.0" ixz="0.0"
iyy="${(1/12) * 0.17 * (3*0.06*0.06 + 0.06*0.06)}" iyz="0.0"
izz="${(1/12) * 0.17 * (0.06*0.06)}"
/>
</inertial>
</link>
<gazebo reference="front_right_wheel">
<material>Gazebo/Blue</material>
</gazebo>
<joint name="back_left_wheel_joint" type="continuous">
<parent link="chassis"/>
<child link="back_left_wheel"/>
<origin xyz="0.08 0.1145 0" rpy="-${pi/2} 0 0"/>
<axis xyz="0 0 1"/>
</joint>
<link name="back_left_wheel">
<visual>
<geometry>
<cylinder radius="0.06" length="0.06"/>
</geometry>
<material name="blue"/>
</visual>
<collision>
<geometry>
<!-- <cylinder radius="0.06" length="0.06"/> -->
<sphere radius="0.06"/>
</geometry>
</collision>
<inertial>
<origin xyz="0 0 0" rpy="0 0 0"/>
<mass value="0.17"/>
<inertia
ixx="${(1/12) * 0.17 * (3*0.06*0.06 + 0.06*0.06)}" ixy="0.0" ixz="0.0"
iyy="${(1/12) * 0.17 * (3*0.06*0.06 + 0.06*0.06)}" iyz="0.0"
izz="${(1/12) * 0.17 * (0.06*0.06)}"
/>
</inertial>
</link>
<gazebo reference="back_left_wheel">
<material>Gazebo/Blue</material>
</gazebo>
<joint name="back_right_wheel_joint" type="continuous">
<parent link="chassis"/>
<child link="back_right_wheel"/>
<origin xyz="0.08 -0.1145 0" rpy="${pi/2} 0 0"/>
<axis xyz="0 0 -1"/>
</joint>
<link name="back_right_wheel">
<visual>
<geometry>
<cylinder radius="0.06" length="0.06"/>
</geometry>
<material name="blue"/>
</visual>
<collision>
<geometry>
<!-- <cylinder radius="0.06" length="0.06"/> -->
<sphere radius="0.06"/>
</geometry>
</collision>
<inertial>
<origin xyz="0 0 0" rpy="0 0 0"/>
<mass value="0.17"/>
<inertia
ixx="${(1/12) * 0.17 * (3*0.06*0.06 + 0.06*0.06)}" ixy="0.0" ixz="0.0"
iyy="${(1/12) * 0.17 * (3*0.06*0.06 + 0.06*0.06)}" iyz="0.0"
izz="${(1/12) * 0.17 * (0.06*0.06)}"
/>
</inertial>
</link>
<gazebo reference="back_right_wheel">
<material>Gazebo/Blue</material>
</gazebo>
</robot>
This is the urdf for my ros2_control:
<?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="front_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>
<state_interface name="position"></state_interface>
</joint>
<joint name="back_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>
<state_interface name="position"></state_interface>
</joint>
<joint name="front_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>
<state_interface name="position"></state_interface>
</joint>
<joint name="back_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>
<state_interface name="position"></state_interface>
</joint>
</ros2_control>
<gazebo>
<plugin name="gazebo_ros2_control" filename="libgazebo_ros2_control.so">
<parameters>$(find vox)/config/my_controllers.yaml</parameters>
</plugin>
</gazebo>
</robot>
This is my .yaml file for the controller:
controller_manager:
ros__parameters:
update_rate: 30
use_sim_time: true
diff_cont:
type: diff_drive_controller/DiffDriveController
joint_broad:
type: joint_state_broadcaster/JointStateBroadcaster
diff_cont:
ros__parameters:
publish_rate: 50.0
base_frame_id: base_link
left_wheel_names: ['front_left_wheel_joint', 'back_left_wheel_joint']
right_wheel_names: ['front_right_wheel_joint', 'back_right_wheel_joint']
wheel_separation: 0.229
wheel_radius: 0.06
use_stamped_vel: false
open_loop: true
# wheels_per_side: 2
# wheel_separation_multiplier: 0.08
# left_wheel_radius_multiplier: x
# right_wheel_radius_multiplier: x
# odom_frame_id: odom
pose_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.01]
twist_covariance_diagonal: [0.001, 0.001, 0.001, 0.001, 0.001, 0.01]
# open_loop: x
# enable_odom_tf: x
# cmd_vel_timeout: x
# publis_limited_velocity: x
# velocity_roling_window_size: x
# linear.x.has_velocity_limits: true
# linear.x.has_acceleration_limits: true
# linear.x.has_jerk_limits: false
# linear.x.max_velocity: 1
# linear.x.min_velocity: NAN
# linear.x.max_acceleration: 3
# linear.x.min_acceleration: NAN
# linear.x.max_jerk: NAN
# linear.x.min_jerk: NAN
# angular.z.has_velocity_limits: true
# angular.z.has_acceleration_limits: true
# angular.z.has_jerk_limits: false
# angular.z.max_velocity: 1
# angular.z.min_velocity: NAN
# angular.z.max_acceleration: 3
# angular.z.min_acceleration: NAN
# angular.z.max_jerk: NAN
# angular.z.min_jerk: NAN
# joint_broad:
# ros_parameters:
And this is my launch file:
import os
from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import IncludeLaunchDescription
from launch.launch_description_sources import PythonLaunchDescriptionSource
from launch_ros.actions import Node
def generate_launch_description():
package_name = "vox"
rsp = IncludeLaunchDescription(
PythonLaunchDescriptionSource([
os.path.join(get_package_share_directory(package_name), "launch", "rsp.launch.py")
]),
launch_arguments={"use_sim_time": "true", "use_ros2_control": "true"}.items()
)
gazebo_params_file = os.path.join(get_package_share_directory(package_name), "config", "gazebo_params.yaml")
gazebo = IncludeLaunchDescription(
PythonLaunchDescriptionSource([
os.path.join(get_package_share_directory("gazebo_ros"), "launch", "gazebo.launch.py")
]),
launch_arguments={'extra_gazebo_args': '--ros-args --param-files' + gazebo_params_file}.items()
)
spawn_entity = Node(
package="gazebo_ros", executable="spawn_entity.py",
arguments=["-topic", "robot_description", "-entity", "vox"],
output="screen"
)
diff_drive_spawner = Node(
package="controller_manager",
executable="spawner",
arguments=["diff_cont"],
)
joint_broad_spawner = Node(
package="controller_manager",
executable="spawner",
arguments=["joint_broad"],
)
return LaunchDescription([
rsp,
gazebo,
spawn_entity,
diff_drive_spawner,
joint_broad_spawner
])
The way I start everything up is by running the following commands:
Terminal 1:
source install/setup.bash
ros2 launch vox launch_sim.launch.py
Terminal 2:
ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -r /cmd_vel:=/diff_cont/cmd_vel_unstamped
Terminal 3:
rviz2
After pressing "l" once, which is "turn right", the RViz2 representation turned a lot more then the Gazebo one.
I haven't noticed this very much until I started implementing SLAM into the project. This difference in turn messes up mapping a lot.
I would appreciate any and all suggestions to fix this drift between RViz2 and Gazebo. If you need anything else from my side, I'll post them ASAP.