How to use Nav2, slam_toolbox with odom data, gps and imu sensors?
Setup details: ROS2 foxy on amd64 architecture CPU with nav2 and slam_toolbox installed
Robot is Clearpath husky with Velodyne VLP-16 lidar, IMU and GPS sensor in gazebo. Can see data on every topic
Long term Objective: Provide gps co-ordinates as goal / way points and autonomously navigate robot to the destination with the help of Nav2 stack by using slam_toolbox
Short term objective: Obtain a stable map (drift free)/ no shaking behavior (if that's possible) using slam_toolbox which updates when obstacles are removed from environment.
Below are the topics. Sometimes /odometry/local
is present, sometimes not even though the node is running through launch file. Also, ros2 node list
does not show anything which seems weird to me.
/clock
/cmd_vel
/diagnostics
/downsampled_costmap
/downsampled_costmap_updates
/e_stop
/global_costmap/costmap
/global_costmap/costmap_updates
/goal_pose
/gps/data
/gps/filtered
/husky_velocity_controller/cmd_vel_unstamped
/imu/data
/initialpose
/joint_states
/joy_teleop/cmd_vel
/map
/map_updates
/odom
/odometry/global
/odometry/gps
/parameter_events
/plan
/robot_description
/rosout
/scan
/tf
/tf_static
/twist_marker_server/cmd_vel
/velodyne_points
/waypoints
My workflow is as below.
1) Spawn the robot in gazebo, all the sensors are outputting data.
2) Run ros2 launch pointcloud_to_laserscan sample_pointcloud_to_laserscan_launch.py
to convert 3D point cloud to 2D laserscan on /scan
topic which can be used later on by slam_toolbox
3) Since the odometry information (from topic /odom
from wheel encoders) is know to have drift, its good to use EKF to fuse odometry data from other sensors (IMU and GPS). There are 4 scenarios/ combinations described down in the post and this is how I am calling the nodes in the launch file. I just comment ld.add_action(node_ekf_local)
if I don't want to run the ekf_filter_node_odom
as an example and so on.
#Used for map to base_link TF
node_ekf_global = Node(
package='robot_localization',
executable='ekf_node',
name='ekf_filter_node_map',
output='screen',
remappings=[('odometry/filtered', 'odometry/global'),
('/set_pose', '/initialpose')],
parameters=[config_husky_ekf, {'use_sim_time':True}],
)
ld.add_action(node_ekf_global)
#Used for odom to base_link TF
node_ekf_local = Node(
package='robot_localization',
executable='ekf_node',
name='ekf_filter_node_odom',
output='screen',
remappings=[('odometry/filtered', 'odometry/local'),
('/set_pose', '/initialpose')],
parameters=[config_husky_ekf, {'use_sim_time':True}],
)
ld.add_action(node_ekf_local)
start_navsat_transform_cmd = Node(
package='robot_localization',
executable='navsat_transform_node',
name='navsat_transform_node',
output='screen',
parameters=[config_husky_ekf, {'use_sim_time':True}],
remappings=[('imu', 'imu/data'),
('gps/fix', 'gps/data'),
('gps/filtered', 'gps/filtered'),
('odometry/gps', 'odometry/gps'),
('odometry/filtered', 'odometry/global')])
ld.add_action(start_navsat_transform_cmd)
Below is the content of the yaml configuration file provided by config_husky_ekf
which contains configuration for three nodes: ekf_filter_node_map (or global), ekf_filter_node_odom (or local), and navsat_transform_node (to convert gps co-ordinates to odometry data)
### ekf config file ### for odom to base_link transform
ekf_filter_node_odom:
ros__parameters:
use_sim_time: true
# The frequency, in Hz, at which the filter will output a position estimate. Note that the filter will not begin
# computation until it receives at least one message from one of the inputs. It will then run continuously at the
# frequency specified here, regardless of whether it receives more measurements. Defaults to 30 if unspecified.
frequency: 50.0
# The period, in seconds, after which we consider a sensor to have timed out. In this event, we carry out a predict
# cycle ...
Hi! I have a similar problem, so if you found any solutions in the end I would love to hear about it. Thanks!