The odometry system provides a locally accurate estimate of a robot’s pose and velocity based on its motion. The odometry information can be obtained from various sources such as IMU, LIDAR, RADAR, VIO, and wheel encoders.
Gazebo is a 3D simulator that allows us to observe how our virtual robot will function in a simulated environment.
Install Gazebo 3D simulator by command [sudo apt install ros-jazzy-ros-gz]
Add Inertial Measurement Unit (IMU) sensor, a Gazebo Plugins to a SDF (Simulation Description Format)
The full code/description of Inertial Measurement Unit (IMU) sensor look like
<joint name='imu_joint' type='fixed'>
<parent>base_link</parent>
<child>imu_link</child>
<pose relative_to="base_link">0.0 0.0 0.01 0 0 0</pose>
</joint>
<link name='imu_link'>
<pose relative_to="imu_joint"/>
<visual name="imu_link_visual">
<geometry>
<box><size>
0.1 0.1 0.1
</size></box>
</geometry>
</visual>
<collision name="imu_link_collision">
<geometry>
<box><size>
0.1 0.1 0.1
</size></box>
</geometry>
</collision>
<xacro:box_inertia m="0.1" w="0.1" d="0.1" h="0.1"/>
<sensor name="imu_sensor" type="imu">
<always_on>true</always_on>
<update_rate>100</update_rate>
<visualize>true</visualize>
<topic>demo/imu</topic>
<gz_frame_id>imu_link</gz_frame_id>
<imu>
<angular_velocity>
<x>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>2e-4</stddev>
<bias_mean>0.0000075</bias_mean>
<bias_stddev>0.0000008</bias_stddev>
</noise>
</x>
<y>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>2e-4</stddev>
<bias_mean>0.0000075</bias_mean>
<bias_stddev>0.0000008</bias_stddev>
</noise>
</y>
<z>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>2e-4</stddev>
<bias_mean>0.0000075</bias_mean>
<bias_stddev>0.0000008</bias_stddev>
</noise>
</z>
</angular_velocity>
<linear_acceleration>
<x>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>1.7e-2</stddev>
<bias_mean>0.1</bias_mean>
<bias_stddev>0.001</bias_stddev>
</noise>
</x>
<y>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>1.7e-2</stddev>
<bias_mean>0.1</bias_mean>
<bias_stddev>0.001</bias_stddev>
</noise>
</y>
<z>
<noise type="gaussian">
<mean>0.0</mean>
<stddev>1.7e-2</stddev>
<bias_mean>0.1</bias_mean>
<bias_stddev>0.001</bias_stddev>
</noise>
</z>
</linear_acceleration>
</imu>
</sensor>
</link>
Add DiffDrive plugin and JointStatePublisher plugin
Set the friction of the caster wheel to near zero by modifying the caster link
Change <collision name="front_caster_collision"> ... </collision> of <link name="front_caster">
to
<collision name="front_caster_collision"> <geometry> <sphere> <radius>${(wheel_radius+wheel_zoff-(base_height/2))}</radius> </sphere> </geometry> <surface><friction><ode> <mu>0.001</mu> <mu2>0.001</mu2> </ode></friction></surface> </collision> From<collision name="front_caster_collision"> <geometry> <sphere> <radius>${(wheel_radius+wheel_zoff-(base_height/2))}</radius> </sphere> </geometry> </collision>
ROS<->Gazebo Bridge: translate Gazebo topics into ROS topics and vice-versa There is a bridge included in the ros_gz_bridge package which allows us to translate Gazebo topics into ROS topics and vice-versa. We need to launch the bridge with a configuration which tells it about what topics we want to bridge ROS to Gazebo (vice-versa) Bridge configuration fileAdd bridge_config_path variable to launch file
Make a Gazebo world
Add thomas_world.sdf into a created folder world
Add [config world] into install (DIRECTORY ...) section of CMakeLists.txt
Add world_path variable into launch file, display.launch.py
Launch and Build Files We will now edit our launch file, display.launch.py, to spawn thomas_bot in Gazebo. Since the JointStatePublisher plugin will now publish the joint_states, we can remove everything related to the joint state publisher by deleting / commenting the following lines inside the generate_launch_description():
Remove the relative joint_state_publisher from return LaunchDescription([]):
Remove or do comment exec_depend tags of joint_state_publisher and joint_state_publisher_gui on package.xml
Add use_sim_time to robot_state_publisher_node inside def generate_launch_description
Declare the use_sim_time argument in LaunchDescription([])
To launch Gazebo and spawn sam_bot in Gazebo, need to add GzServer, RosGzBridge nodes and spawn_entity
Add ExecuteProcess(), gz_server, ros_gz_bridge and spawn_entity to LaunchDescription() into display.launch.py
Add ros_gz_bridge and ros_gz_sim exec_depend tags into package.xmlBuild, Run and Verification Run our package to check if the /demo/imu and /demo/odom topics are active in the system. Navigate to the root of the project and execute the following lines: colcon build . install/setup.bash ros2 launch thomas_bot_description display.launch.py Error - GzServer is not definedImport RosGzBridge and GzServer into display.launch.py
Error - IncludeLaunchDescription is not defined
Error -PythonLaunchDescriptionSource is not definedImport IncludeLaunchDescription and PythonLaunchDescriptionSource
Error - gz_spawn_model_launch_source is not defined Add or declare gz_spawn_model_launch_source gz_spawn_model_launch_source = os.path.join(ros_gz_sim_share, "launch", "gz_spawn_model.launch.py")Error - ros_gz_sim_share is not defined
Add or declare ros_gz_sim_share ros_gz_sim_share = get_package_share_directory('ros_gz_sim')
Error - get_package_share_directory is not defined
Import get_package_share_diroectory from ament_index_python.packages import get_package_share_directory
Error - ExecuteProcess is not defined
Import ExecuteProcess
Error - thomas_world.sdf is empty
The content of thomas_world.sdf
<sdf version='1.7'> <world name='thomas_world'> <physics name="1ms" type="ignored"> <max_step_size>0.001</max_step_size> <real_time_factor>1.0</real_time_factor> </physics> <plugin filename="gz-sim-physics-system" name="gz::sim::systems::Physics"> </plugin> <plugin filename="gz-sim-user-commands-system" name="gz::sim::systems::UserCommands"> </plugin> <plugin filename="gz-sim-scene-broadcaster-system" name="gz::sim::systems::SceneBroadcaster"> </plugin> <plugin filename="gz-sim-imu-system" name="gz::sim::systems::Imu"> </plugin> <plugin filename="gz-sim-sensors-system" name="gz::sim::systems::Sensors"> <render_engine>ogre2</render_engine> </plugin> <light name='sun' type='directional'> <cast_shadows>1</cast_shadows> <pose>0 0 10 0 -0 0</pose> <diffuse>0.8 0.8 0.8 1</diffuse> <specular>0.2 0.2 0.2 1</specular> <attenuation> <range>1000</range> <constant>0.9</constant> <linear>0.01</linear> <quadratic>0.001</quadratic> </attenuation> <direction>-0.5 0.1 -0.9</direction> <spot> <inner_angle>0</inner_angle> <outer_angle>0</outer_angle> <falloff>0</falloff> </spot> </light> <model name='ground_plane'> <static>1</static> <link name='link'> <collision name='collision'> <geometry> <plane> <normal>0 0 1</normal> <size>100 100</size> </plane> </geometry> <surface> <friction> <ode> <mu>100</mu> <mu2>50</mu2> </ode> <torsional> <ode/> </torsional> </friction> <contact> <ode/> </contact> <bounce/> </surface> <max_contacts>10</max_contacts> </collision> <visual name='visual'> <cast_shadows>0</cast_shadows> <geometry> <plane> <normal>0 0 1</normal> <size>100 100</size> </plane> </geometry> <material> <script> <uri>file://media/materials/scripts/gazebo.material</uri> <name>Gazebo/Grey</name> </script> </material> </visual> <self_collide>0</self_collide> <enable_wind>0</enable_wind> <kinematic>0</kinematic> </link> </model> <gravity>0 0 -9.8</gravity> <magnetic_field>6e-06 2.3e-05 -4.2e-05</magnetic_field> <atmosphere type='adiabatic'/> <physics type='ode'> <max_step_size>0.001</max_step_size> <real_time_factor>1</real_time_factor> <real_time_update_rate>1000</real_time_update_rate> </physics> <scene> <ambient>0.4 0.4 0.4 1</ambient> <background>0.7 0.7 0.7 1</background> <shadows>1</shadows> </scene> <wind/> <spherical_coordinates> <surface_model>EARTH_WGS84</surface_model> <latitude_deg>0</latitude_deg> <longitude_deg>0</longitude_deg> <elevation>0</elevation> <heading_deg>0</heading_deg> </spherical_coordinates> <model name='unit_box'> <pose>1.51271 -0.181418 0.5 0 -0 0</pose> <link name='link'> <inertial> <mass>1</mass> <inertia> <ixx>0.166667</ixx> <ixy>0</ixy> <ixz>0</ixz> <iyy>0.166667</iyy> <iyz>0</iyz> <izz>0.166667</izz> </inertia> <pose>0 0 0 0 -0 0</pose> </inertial> <collision name='collision'> <geometry> <box> <size>1 1 1</size> </box> </geometry> <max_contacts>10</max_contacts> <surface> <contact> <ode/> </contact> <bounce/> <friction> <torsional> <ode/> </torsional> <ode/> </friction> </surface> </collision> <visual name='visual'> <geometry> <box> <size>1 1 1</size> </box> </geometry> <material> <script> <name>Gazebo/Grey</name> <uri>file://media/materials/scripts/gazebo.material</uri> </script> </material> </visual> <self_collide>0</self_collide> <enable_wind>0</enable_wind> <kinematic>0</kinematic> </link> </model> <model name='unit_sphere'> <pose>-1.89496 2.36764 0.5 0 -0 0</pose> <link name='link'> <inertial> <mass>1</mass> <inertia> <ixx>0.1</ixx> <ixy>0</ixy> <ixz>0</ixz> <iyy>0.1</iyy> <iyz>0</iyz> <izz>0.1</izz> </inertia> <pose>0 0 0 0 -0 0</pose> </inertial> <collision name='collision'> <geometry> <sphere> <radius>0.5</radius> </sphere> </geometry> <max_contacts>10</max_contacts> <surface> <contact> <ode/> </contact> <bounce/> <friction> <torsional> <ode/> </torsional> <ode/> </friction> </surface> </collision> <visual name='visual'> <geometry> <sphere> <radius>0.5</radius> </sphere> </geometry> <material> <script> <name>Gazebo/Grey</name> <uri>file://media/materials/scripts/gazebo.material</uri> </script> </material> </visual> <self_collide>0</self_collide> <enable_wind>0</enable_wind> <kinematic>0</kinematic> </link> </model> <state world_name='default'> <sim_time>0 0</sim_time> <real_time>0 0</real_time> <wall_time>1626668720 808592627</wall_time> <iterations>0</iterations> <model name='ground_plane'> <pose>0 0 0 0 -0 0</pose> <scale>1 1 1</scale> <link name='link'> <pose>0 0 0 0 -0 0</pose> <velocity>0 0 0 0 -0 0</velocity> <acceleration>0 0 0 0 -0 0</acceleration> <wrench>0 0 0 0 -0 0</wrench> </link> </model> <model name='unit_box'> <pose>1.51272 -0.181418 0.499995 0 1e-05 0</pose> <scale>1 1 1</scale> <link name='link'> <pose>1.51272 -0.181418 0.499995 0 1e-05 0</pose> <velocity>0 0 0 0 -0 0</velocity> <acceleration>0.010615 -0.006191 -9.78231 0.012424 0.021225 1.8e-05</acceleration> <wrench>0.010615 -0.006191 -9.78231 0 -0 0</wrench> </link> </model> <model name='unit_sphere'> <pose>-0.725833 1.36206 0.5 0 -0 0</pose> <scale>1 1 1</scale> <link name='link'> <pose>-0.944955 1.09802 0.5 0 -0 0</pose> <velocity>0 0 0 0 -0 0</velocity> <acceleration>0 0 0 0 -0 0</acceleration> <wrench>0 0 0 0 -0 0</wrench> </link> </model> <light name='sun'> <pose>0 0 10 0 -0 0</pose> </light> </state> <gui fullscreen='0'> <camera name='user_camera'> <pose>3.17226 -5.10401 6.58845 0 0.739643 2.19219</pose> <view_controller>orbit</view_controller> <projection_type>perspective</projection_type> </camera> </gui> </world> </sdf> Loading thomas_world.sdf file is OK
Gazebo launch OK and we got a 3D model of thomas_botClip about building and running Build by command: colcon build. install/setup.bash
Launch robot by: ros2 launch sam_bot_description display.launch.py
Moving our robot by command ros2 run teleop_twist_keyboard teleop_twist_keyboard --ros-args -p stamped:=true --remap cmd_vel:=/demo/cmd_vel
Generative AI, Robot Operating System (ROS 2), Computer Vision, Natural Language Processing service, Generative AI Chatbot, Machine Learning, Mobile App, Web App? Yes, I do provide!
Call me: (+84) 0854147015
WhatsApp: +601151992689
Viber: +84854147015https://amatasiam.web.app
Email: ThomasTrungVo@Gmail.Com
Facebook: https://www.facebook.com/voduytrung
X: https://x.com/ThomasTrung
No comments:
Post a Comment