Differential drive robot is perhaps the most common type of robot. A differential drive system navigates by controlling the velocities of all the participating wheels to achieve a common navigation goal. This entire book uses KBot – a simple two-wheeled differential drive robot – as an example to explore various ROS concepts.
Let’s start our journey by describing the basic physical, visual and collision properties of KBot. In its simplest form, a differential drive robot will have a base plate, two main wheels and a caster wheel for support. The main wheels – left & right wheels – are the ones to be actuated. So, their velocities determine where and how fast the robot is moving.
Chapter-02 Source Code
For your reference, download full source code for this chapter here
Chapter-01 : Introduction
Chatpter-03 : Simple Navigation with Differential Drive Plugin
Source Code Prep
Begin the proceedings by creating a ROS package named kbot_description
.
1 2 3 4 | $ mkdir -p chapter-02/src/kbot_description $ cd chapter-02/src/kbot_description $ mkdir launch urdf config |
Base URDF
ROS way of describing a robot is by specifying its properties in URDF (Universal Robot Description Format) files. URDF supports XML and xacro (XML macro) languages. Xacro code is easier to implement, maintain and has better readability.
Create a new robot description file urdf/kbot.xacro
and paste below contents.
1 2 3 4 5 6 7 8 9 10 11 12 | <?xml version="1.0"?> <robot> <xmlns:xacro="http://www.ros.org/wiki/xacro" name="kbot"> <xacro:property name="base_width" value="0.16"/> <xacro:property name="base_len" value="0.16"/> <xacro:property name="wheel_radius" value="0.035"/> <xacro:property name="base_wheel_gap" value="0.007"/> <xacro:property name="wheel_separation" value="0.15"/> <xacro:property name="wheel_joint_offset" value="0.02"/> </robot> |
We are defining some properties of KBot like base plate dimensions, wheel sepration distance, base plate to wheel distances. Then, add below code between <robot>
and </robot>
tags.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <xacro:macro name="box_inertia" params="m w h d"> <inertial> <mass value="${m}"/> <inertia ixx="${m / 12.0 * (d*d + h*h)}" ixy="0.0" ixz="0.0" iyy="${m / 12.0 * (w*w + h*h)}" iyz="0.0" izz="${m / 12.0 * (w*w + d*d)}"/> </inertial> </xacro:macro> <link name="base_footprint"> <xacro:box_inertia m="20" w="0.001" h="0.001" d="0.001"/> <visual> <origin xyz="0 0 0" rpy="0 0 0" /> <geometry> <box size="0.001 0.001 0.001" /> </geometry> </visual> </link> <link name="base_link"> <xacro:box_inertia m="10" w="${base_len}" h="${base_width}" d="0.01"/> <visual> <geometry> <box size="${base_len} ${base_width} 0.01"/> </geometry> </visual> <collision> <geometry> <box size="${base_len} ${base_width} 0.01"/> </geometry> </collision> </link> <joint name="base_link_joint" type="fixed"> <origin xyz="0 0 ${wheel_radius + 0.005}" rpy="0 0 0" /> <parent link="base_footprint"/> <child link="base_link" /> </joint> |
Above code creates two links: base_footprint
& base_link
and a joint base_link_joint
connecting base link to base footprint. Base footprint is modelled as a tiny box with heavy mass. This represents the center of the robot. Where as base link is modelled as a sheet (a box with negligible height) to which rest of the KBot components are going to be attached.
For most links in the robot visual, collision and inertial properties are defined (using respective tags). <visual>
property determines how the link is visuazlized in tools like rviz and Gazebo. <collision>
property influences collision behavior of the physics simulation in Gazebo. <inertial>
tag defines inertia of the link in 3 dimensional space.
box_inertia
is a macro that defines inertia for any box-shaped link. Inertia formulae (ixx, iyy, izz so on) change with the shape of the object and can be obtained by Googling. Later in the chapter, we will define sphere_inertia
and cylinder_inertia
macros for spherical and cylinder shaped links.
The next step is to attach main wheels to KBot.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <xacro:macro name="cylinder_inertia" params="m r h"> <inertial> <mass value="${m}"/> <inertia ixx="${m*(3*r*r+h*h)/12}" ixy = "0" ixz = "0" iyy="${m*(3*r*r+h*h)/12}" iyz = "0" izz="${m*r*r/2}"/> </inertial> </xacro:macro> <xacro:macro name="wheel" params="prefix reflect"> <link name="${prefix}_wheel"> <visual> <origin xyz="0 0 0" rpy="${pi/2} 0 0"/> <geometry> <cylinder radius="${wheel_radius}" length="0.005"/> </geometry> </visual> <collision> <origin xyz="0 0 0" rpy="${pi/2} 0 0"/> <geometry> <cylinder radius="${wheel_radius}" length="0.005"/> </geometry> </collision> <xacro:cylinder_inertia m="10" r="${wheel_radius}" h="0.005"/> </link> <joint name="${prefix}_wheel_joint" type="continuous"> <axis xyz="0 1 0" rpy="0 0 0" /> <parent link="base_link"/> <child link="${prefix}_wheel"/> <origin xyz="${wheel_joint_offset} ${((base_width/2)+base_wheel_gap)*reflect} -0.005" rpy="0 0 0"/> </joint> </xacro:macro> <xacro:wheel prefix="left" reflect="1"/> <xacro:wheel prefix="right" reflect="-1"/> |
wheel
macro creates a wheel link and a joint to connect it the base link. Then, we use this macro to create a link and a joint for each wheel – left_wheel
, left_wheel_joint
, right_wheel
& right_wheel_joint
. Note that a parameter reflect
is used to place wheels on either side of base link. Also, the property wheel_joint_offset
determines how far from base plate the wheels are (horizontal offset).
Add a spherical caster at the center and rear end of the robot. The geometry of the caster wheel is entirely up to you.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <xacro:macro name="sphere_inertia" params="m r"> <inertial> <mass value="${m}"/> <inertia ixx="${2.0*m*(r*r)/5.0}" ixy="0.0" ixz="0.0" iyy="${2.0*m*(r*r)/5.0}" iyz="0.0" izz="${2.0*m*(r*r)/5.0}"/> </inertial> </xacro:macro> <link name="caster_wheel"> <visual> <origin xyz="0 0 0" rpy="0 0 0"/> <geometry> <sphere radius="${caster_wheel_radius}"/> </geometry> </visual> <collision> <origin xyz="0 0 0" rpy="0 0 0"/> <geometry> <sphere radius="${caster_wheel_radius}"/> </geometry> </collision> <xacro:sphere_inertia m="5" r="${caster_wheel_radius}"/> </link> <joint name="caster_wheel_joint" type="continuous"> <axis xyz="0 1 0" rpy="0 0 0" /> <parent link="base_link"/> <child link="caster_wheel"/> <origin xyz="${caster_wheel_joint_offset} 0 -${caster_wheel_radius+0.005}" rpy="0 0 0"/> </joint> |
Above snippet creates a caster wheel link caster_wheel
and a joint caster_wheel_joint
that connects it to the base link.
Now, the basic structure of KBot is ready. In the next sections we will use rviz to check how our robot looks like.
Visualizing with Rviz
Let’s make kbot_description
a ROS package by running below commands.
1 2 3 | $ cd chapter-02/src/ $ catkin_create_pkg kbot_description |
package.xml
and CMake_lists.txt
files will be created in kbot_description/
directory.
Create a launch file launch/kbot_base_rviz.launch
to read the URDF (xacro) file created in the earlier section and to launch rviz.
1 2 3 4 5 6 7 8 9 10 11 12 | <launch> <param name="robot_description" command="$(find xacro)/xacro --inorder $(find kbot_description)/urdf/kbot.xacro"/> <node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher"/> <node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher"/> <node name="rviz" pkg="rviz" type="rviz" required="true"/> </launch> |
The launch file uses xacro
utility to pase the URDF and capture it in a parameter robot_description
of the parameter server. Three nodes are launched. robot_state_publisher
, joint_state_publisher
ensure that proper transformations between various links (link frames) are published. rviz
node, of course, launches rviz.
Compile the package, add it to ROS search path and use roslaunch command to invoke rviz.
1 2 3 4 5 | $ cd chapter-02/ $ catkin_make $ source devel/setup.sh $ roslaunch kbot_description kbot_base_rviz.launch |
The last command opens rviz GUI. You won’t see the robot model and perhaps even some errors. To fix that, change value of Global Options -> Fixed Frame from map to base_link. Click on Add in Displays pane and add a Robot Model.

At this point, the robot has the basic components (base, wheels, caster). Optionally, you can add colors to URDF links for better visualization.
1 2 3 4 5 6 7 8 9 10 11 12 13 | <material name="blue"> <color rgba="0 0 0.8 1"/> </material> <material name="black"> <color rgba="0 0 0 1"/> </material> <material name="white"> <color rgba="1 1 1 1"/> </material> <material name="red"> <color rgba="0.8 0.0 0.0 1.0"/> </material> |
Then, color the links by add adding a <material name="red"/>
(red as example) tag under <visual>
.

Preparing Gazebo for Simulation
Gazebo is a physics-based real-world robotics simulator. It is the de-facto simulator for most ROS robots. Gazebo allows roboticists to rapidly test algorithms, run test regressions, do field trials, train AI models etc. Gazebo has several pre-built models required to build most kinds of robots and environments (worlds). Gazebo also has a large collection of models contributed by its vibrant community.
For seamless integration between ROS & Gazebo, install gazebo_ros
packages on your host system (if you haven’t done so). Gazebo supports visualization of URDF-based robot models. In this section, we will see how to invoke Gazebo and visualize KBot in the simulator (as well as in rviz).
Copy kbot_description/launch/kbot_base_rviz.launch
to kbot_description/launch/kbot_base_rviz_gazebo.launch
and add below lines to the new file.
1 2 3 4 5 6 7 8 9 10 11 12 | <include file="$(find gazebo_ros)/launch/empty_world.launch"> <arg name="debug" value="false" /> <arg name="gui" value="true" /> <arg name="paused" value="false"/> <arg name="use_sim_time" value="false"/> <arg name="headless" value="false"/> <arg name="verbose" value="true"/> </include> <!--Launch Gazebo Simulator--> <node name="spawn_model" pkg="gazebo_ros" type="spawn_model" args="-urdf -param robot_description -model kbot -verbose" output="screen"/> |
It is customary to load a world file along with a robot model. An empty world robot environment model is included with some Gazebo parameters. Then KBot model is spawned in Gazebo using spawn_model
node of gazebo_ros
package. Note that the URDF robot description parameters is passed as an argument to the Gazebo instance.
1 2 | $ roslaunch kbot_description kbot_base_rviz_gazebo.launch |
The robot model should look the same in both rviz and Gazebo.
