Build a simulated two-wheeled ROS robot
1. Make sure you have installed Rviz
2. Generate and build the ROS function package
2.1 Generate a catkin workspace
$ mkdir -p ~/catkin_ws/src
$ cd ~/catkin_ws/src
$ catkin_init_workspace
compile workspace
$ cd ~/catkin_ws/
$ catkin_make
load source file
$ source ~/catkin_ws/devel/setup.bash
Add commands to the .bashrc file
$ echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc
In order to determine whether the source file is loaded, query the workspace that the ROS environment is using with the following command
$ echo $ROS_PACKAGE_PATH
The corresponding output should be:
home/username/catkin_ws/src:/opt/ros/noetic/share
2.2 I missed one and am too lazy to change it
2.3 Constructing a URDF for a differentially driven robot
URDF is a file with a specially defined XML format, which is specially used to describe the abstract model of the robot component level.
Generate a /urdf directory in the ros_robotics function package directory:
$ cd ~/catkin_ws/src/robotics
$ mkdir urdf
$ cd urdf
2.3.1 Create the robot base
The first component of the robot is the base box with a length, width and height of 0.5, 0.5, and 0.25, respectively.
The new file dd_robot.urdf is saved in the urdf folder.
<<?xml version='1.0'?>
<robot name="dd_robot">
<!--Base Link-->
<link name="base_link">
<visual>
<origin xyz="0 0 0 " rpy="0 0 0" />
<geometry>
<box size="0.5 0.5 0.25" />
</geometry>
</visual>
</link>
</robot>
2.3.2 Using roslaunch
roslaunch: It can simplify the process of starting multiple ROS nodes; simplify the process of parameter server setting.
When using it, you need to start the node manager through the roscore command
roslaunch syntax structure
$ roslaunch <package_name> <file.launch>
Create a new folder lacunch in the ros_robotics function package, and then create a new ddrobot_rviz.launch file
<launch>
<!-- value passed by command line input-->
<arg name="model"/>
<arg name="gui" default="False"/>
<!-- set these parameters on Parameter Server-->
<param name="robot_description"
textfile="$(find ros_robotics)/urdf/$(arg model)"/>
<param name="use_gui" value="$(arg gui)"/>
<!-- Start 3 nodes: joint_state_publisher,
robot_state_publisher and
rviz -->
<node name="joint_state_publisher"
pkg="joint_state_publisher"
type="joint_state_publisher"/>
<node name="robot_state_publisher"
pkg="robot_state_publisher"
type="robot_state_publisher"/>
<node name="rviz" pkg="rviz" type="rviz"
args="-d $(find ros_robotics)/urdf.rviz"
required="true"/>
</launch>
Enter the following command to view the robot model
$ roslaunch ros_robotics ddrobot_rviz.launch model:=dd_robot.urdf
If the following error occurs, RLException: [ddrobot_rviz.launch] is neither a launch file in package [launch] nor is [launch] a launch file name The
traceback for the exception was written to the log file
Solution: Change devel/setup. bash added to the system
source ./devel/setup.bash
Add Robotmodel and TF in displays, and change FIxed frame to base_link.
2.3.3 Adding wheels
Continue to add in the previous code
<?xml version='1.0'?>
<robot name="dd_robot">
<!--Base Link-->
<link name="base_link">
<visual>
<origin xyz="0 0 0 " rpy="0 0 0" />
<geometry>
<box size="0.5 0.5 0.25" />
</geometry>
</visual>
</link>
<!-- Right Wheel-->
<link name="right_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0 " />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</visual>
</link>
<joint name="joint_right_wheel" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="0 -0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
<!-- Left Wheel-->
<link name="left_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0" />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</visual>
</link>
<joint name="joint_left_wheel" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0 0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
</robot>
run
2.3.4 Adding colors
For the convenience of viewing
, change the above code
<?xml version='1.0'?>
<robot name="dd_robot">
<!--Base Link-->
<link name="base_link">
<visual>
<origin xyz="0 0 0 " rpy="0 0 0" />
<geometry>
<box size="0.5 0.5 0.25" />
</geometry>
<material name="blue">
<color rgba="0 0.5 1 1"/>
</material>
</visual>
</link>
<!-- Right Wheel-->
<link name="right_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0 " />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
</link>
<joint name="joint_right_wheel" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="0 -0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
<!-- Left Wheel-->
<link name="left_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0" />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
</link>
<joint name="joint_left_wheel" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0 0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
</robot>
Keep running, our car is out
2.3.5 Add casters
Add small casters to balance the cart
Add code in base_link
<!--Caster-->
<visual name="caster">
<origin xyz="0.2 0 -0.125" rpy="0 0 0"/>
<geometry>
<sphere radius="0.05"/>
</geometry>
</visual>
2.3.6 Add collision attribute
Add the collision attribute to make the car detect and recognize the boundary of the object.
Also add the <collision> attribute to the <link> element
Complete code
<?xml version='1.0'?>
<robot name="dd_robot">
<!--Base Link-->
<link name="base_link">
<visual>
<origin xyz="0 0 0 " rpy="0 0 0" />
<geometry>
<box size="0.5 0.5 0.25" />
</geometry>
<material name="blue">
<color rgba="0 0.5 1 1"/>
</material>
</visual>
<!--Base collision-->
<collision>
<origin xyz="0 0 0 " rpy="0 0 0 "/>
<geometry>
<box size="0.5 0.5 0.25"/>
</geometry>
</collision>
<!--Caster-->
<visual name="caster">
<origin xyz="0.2 0 -0.125" rpy="0 0 0"/>
<geometry>
<sphere radius="0.05"/>
</geometry>
</visual>
<!--caster collision -->
<collision>
<origin xyz="0.2 0 -0.125" rpy="0 0 0 "/>
<geometry>
<sphere radius="0.05"/>
</geometry>
</collision>
</link>
<!-- Right Wheel-->
<link name="right_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0 " />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
<!--right wheel collision -->
<collision>
<origin xyz="0 0 0" rpy="1.570795 0 0 "/>
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</collision>
</link>
<joint name="joint_right_wheel" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="0 -0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
<!-- Left Wheel-->
<link name="left_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0" />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
<!--left wheel collision -->
<collision>
<origin xyz="0 0 0" rpy="1.570795 0 0 "/>
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</collision>
</link>
<joint name="joint_left_wheel" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0 0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
</robot>
2.3.7 Moving Wheels
Next, we control the joint components of the wheel through the GUI pop-up window.
Add gui to the command field, as follows:
$ roslaunch ros_robotics ddrobot_rviz.launch model:=dd_robot.urdf gui:=True
If you find that you open Rviz, you find that there is no GUI window. Use the following method
- Download joint_state_publisher_gui
$ sudo apt-get install ros-noetic-joint-state-publisher-gui
- Will the launch file insidejoint_state_publisherchanged tojoint_state_publisher_gui
- Re-run the command, and the GUI window will appear
2.3.8 Add physical attributes
Physical properties: Including inertia <inertia>, 3*3 matrix; mass <mass>, unit kg
can be started in the Gazebo engine
Need to add <inertial> tag in <link>
The specific code is longer
<?xml version='1.0'?>
<robot name="dd_robot">
<!--Base Link-->
<link name="base_link">
<visual>
<origin xyz="0 0 0 " rpy="0 0 0" />
<geometry>
<box size="0.5 0.5 0.25" />
</geometry>
<material name="blue">
<color rgba="0 0.5 1 1"/>
</material>
</visual>
<!--Base collision-->
<collision>
<origin xyz="0 0 0 " rpy="0 0 0 "/>
<geometry>
<box size="0.5 0.5 0.25"/>
</geometry>
</collision>
<inertial>
<mass value="5"/>
<inertia ixx="0.13" ixy="0.0" ixz="0.0" iyy="0.21" iyz="0.0" izz="0.13"/>
</inertial>
<!--Caster-->
<visual name="caster">
<origin xyz="0.2 0 -0.125" rpy="0 0 0"/>
<geometry>
<sphere radius="0.05"/>
</geometry>
</visual>
<!--caster collision -->
<collision>
<origin xyz="0.2 0 -0.125" rpy="0 0 0 "/>
<geometry>
<sphere radius="0.05"/>
</geometry>
</collision>
<inertial>
<mass value="0.5"/>
<inertia ixx="0.0001" ixy="0.0" ixz="0.0" iyy="0.0001" iyz="0.0" izz="0.0001"/>
</inertial>
</link>
<!-- Right Wheel-->
<link name="right_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0 " />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
<!--right wheel collision -->
<collision>
<origin xyz="0 0 0" rpy="1.570795 0 0 "/>
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</collision>
<inertial>
<mass value="0.5"/>
<inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.005" iyz="0.0" izz="0.005"/>
</inertial>
</link>
<joint name="joint_right_wheel" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="0 -0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
<!-- Left Wheel-->
<link name="left_wheel">
<visual>
<origin xyz="0 0 0" rpy="1.570795 0 0" />
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
<material name="black">
<color rgba="0.05 0.05 0.05 1"/>
</material>
</visual>
<!--left wheel collision -->
<collision>
<origin xyz="0 0 0" rpy="1.570795 0 0 "/>
<geometry>
<cylinder length="0.1" radius="0.2"/>
</geometry>
</collision>
<inertial>
<mass value="0.5"/>
<inertia ixx="0.01" ixy="0.0" ixz="0.0" iyy="0.005" iyz="0.0" izz="0.005"/>
</inertial>
</link>
<joint name="joint_left_wheel" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0 0.30 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
</robot>
We can use the check_urdf tool to check the grammar
$ check_urdf dd_robot.urdf
2.4 Gazebo
2.4.1 Install Gazebo
Open Gazebo
$ gazebo
2.4.2 Start Gazebo using roslaunch
$ roslaunch gazebo_ros empty_world.launch
2.4.3 Change color
<gazebo reference="base_link">
material>Gazebo/Blue</material>
<pose>0 0 3 0 0 0</pose>
</gazebo>
2.4.4 Model Validation
Check if there is a problem with the code
$ gzsdf -p dd_robot.gazebo
If this is a problem, replace the following
$ gz sdf -p dd_robot.gazebo
2.4.5 View URDF in Gazebo
Generate ddrobot_gazebo.launch using XML
<launch>
<!-- We resume the logic in gazebo_ros package empty_world.launch, -->
<!-- changing only the name of the world to be launched -->
<include file="$(find gazebo_ros)/launch/empty_world.launch">
<arg name="world_name" value="$(find ros_robotics)/worlds/ddrobot.world"/>
<arg name="paused" default="false"/>
<arg name="use_sim_time" default="true"/>
<arg name="gui" default="true"/>
<arg name="headless" default="false"/>
<arg name="debug" default="false"/>
</include>
<!-- Spawn dd_robot into Gazebo -->
<node name="spawn_urdf" pkg="gazebo_ros" type="spawn_model" output="screen"
args="-file $(find ros_robotics)/urdf/dd_robot.gazebo -urdf -model ddrobot" />
</launch>
2.4.6 Create a new environment
Create a new folder worlds in the function package
and create a new file ddrobot.world
<?xml version="1.0" ?>
<sdf version="1.4">
<world name="default">
<include>
<uri>model://ground_plane</uri>
</include>
<include>
<uri>model://sun</uri>
</include>
<include>
<uri>model://construction_cone</uri>
<name>construction_cone</name>
<pose>-3.0 0 0 0 0 0</pose>
</include>
<include>
<uri>model://construction_cone</uri>
<name>construction_cone</name>
<pose>3.0 0 0 0 0 0</pose>
</include>
</world>
</sdf>
References: ROS Robot Development Practical Case Analysis (Second Edition)