If you have gotten to this point of the ROS guide this is the end to the Nav2 section.

Here is a brief overview of what is needed to set up the Nav2 stack

  • create URDF
  • create custom joint_state_pub node to publish odom=>base_link tf and /cmd_vel
  • set up sim environment
  • add lidar Node
  • add Slam Node for map=>odom tf
  • run nav2 bringup

Further guides

Some extra features you could add to Nav2 are listed here. These are just some extra things I found useful for Robomasters specifically

  • tuning robot footprint

    • Robot footprint is the 2D representation of the robot nav2 uses for collision avoidance. It can be tuned to better fit the robot
  • keep out zones

    • obstacles that wont be picked up by the lidar can still be avoided by specifying “keep out” zones.
    • Bumps to avoid in the Robomasters 2025 field:

    image.png

  • lidar ignore zone

    • If your robot blocks off certain parts of the Lidar’s scan it can show up in your map. To avoid this ROS has a laser_filters package where you can ignore parts of the Lidar scan.
    example setup for ROS2 (the yaml config file stays the same from the guide):
          lidar_filter_yaml = os.path.join(pkg_share, 'config', 'lidar_filter.yaml')
    
    		...
    
        lidar_filter = Node(
                package='laser_filters',
                executable='scan_to_scan_filter_chain',
                # name='laser_filters',
                output='screen',
                emulate_tty=True,
                # remappings=[
                #     # Remap the default '/chatter' topic to '/conversation'
                #     ('/scan', '/scan_raw'),
                #     ('/scan_filtered', '/scan'),
                # ],
                parameters=[lidar_filter_yaml])
      
  • behavior trees

    • Nav2 has a custom system to describe “robot behavior” such as what to do if suck or when to go to which goal. It can be though of as an advanced state machine.
    • It is recommend in Robomasters to use the behavior trees for sentry decision making
  • real sense node

    • It is common to have real sense nodes in Robomasters. If you do use one there is a ROS2 node for it where you can specify all the parameters.

Configuring for holinomic drive

For our team’s Nav2 setup specifically we set our robot to be omnidirectional or a holinomic drive instead of diff drive. This requires lots of changes in the nav2 params so I will do my best to list them here. These are just the params that I found worked for jazzy.

Here is another guide that goes over some of the nav2 parameters if lost

  • amcl
    • robot_model_type set to"nav2_amcl::OmniMotionModel”
  • controller_server
    • ros__parameters
      • min_y_velocity_threshold set to 0.001
    • general_goal_checker
      • yaw_goal_tolerance set to 0.50
    • FollowPath
      • ay_min set to -3.0

      • vy_min set to -0.35

      • wz_max set to 1.9

      • motion_model set to "Omni”

      • critics add "TwirlingCritic" to the array

      • GoalAngleCritic

        • enabled set to false
      • Add this under PathAngleCritic with the same number of tabs

            TwirlingCritic:
            enabled: true
            twirling_cost_power: 1
            twirling_cost_weight: 10.0
          
  • behavior_server
    • ros__parameters
      • max_rotational_vel set to 0.0
      • min_rotational_vel set to 0.0
  • velocity_smoother
    • ros__parameters
      • max_velocity set to [0.5, 0.5, 2.0]
      • min_velocity set to [-0.5, -0.5, -2.0]
      • max_accel set to [2.5, 2.5, 3.2]
      • max_decel set to [-2.5, -2.5, -3.2]

behavior tree replacement:

official behavior tree guide

There is a spin critic in the default behavior tree so to get rid of it you have to provide your own behavior tree:

in the config folder make this file my_nav_to_pose_bt.xml

note this is just a template to just get holinomic drive to work it is recommend you make your own.

  <root main_tree_to_execute="MainTree">
  <BehaviorTree ID="MainTree">
    <RecoveryNode number_of_retries="6" name="NavigateRecovery">
      <PipelineSequence name="NavigateWithReplanning">
        <RateController hz="1.0">
          <RecoveryNode number_of_retries="1" name="ComputePathToPose">
            <ComputePathToPose goal="{goal}" path="{path}" planner_id="GridBased"/>
            <ClearEntireCostmap name="ClearGlobalCostmap-Context" service_name="global_costmap/clear_entirely_global_costmap"/>
          </RecoveryNode>
        </RateController>
        <RecoveryNode number_of_retries="1" name="FollowPath">
          <FollowPath path="{path}" controller_id="FollowPath"/>
          <ClearEntireCostmap name="ClearLocalCostmap-Context" service_name="local_costmap/clear_entirely_local_costmap"/>
        </RecoveryNode>
      </PipelineSequence>
      <ReactiveFallback name="RecoveryFallback">
        <GoalUpdated/>
        <SequenceStar name="RecoveryActions">
          <ClearEntireCostmap name="ClearLocalCostmap-Subtree" service_name="local_costmap/clear_entirely_local_costmap"/>
          <ClearEntireCostmap name="ClearGlobalCostmap-Subtree" service_name="global_costmap/clear_entirely_global_costmap"/>
          <Wait wait_duration="5"/>
        </SequenceStar>
      </ReactiveFallback>
    </RecoveryNode>
  </BehaviorTree>
</root>
  

Then in the launch file add this

      bt_xml = os.path.join(pkg_share, 'config', 'my_nav_to_pose_bt.xml')
    
    ...
    
    nav2_bringup_node = IncludeLaunchDescription(
        PythonLaunchDescriptionSource([
            FindPackageShare("nav2_bringup"), '/launch', '/navigation_launch.py']),
        launch_arguments={
            'params_file': nav2_yaml,
            'use_sim_time': LaunchConfiguration('use_sim_time')
            'default_bt_xml_filename': bt_xml
        }.items()
    )
  

architectural decisions

Why all in one node?

ideally you are suppose to represent the hardware/resources better by having be physical nodes however for Robomasters many things are latency sensitive and having message pass though the ROS middleware had too much latency. Granted this was just though our limited testing was without fine tuning ROS for our specific application. However for the Robomaster’s robotics completion teams just need a dead simple working framework that works well enough for competition. Genraly robomasters clubs don’t have lots of time to fine tune and configure ROS perfectly so arcitecthing the whole robot under the my_node is jank but works for our specific situation. This guide is ment to give teams a bare bones working Nav2 stack where teams can later on extend and re architect the whole design.

Further Nav2 stuff to look at


common bugs:

  [bt_navigator-11] [ERROR] [1752642430.128585554] [transformPoseInTargetFrame]: Extrapolation Error looking up target frame: Lookup would require extrapolation into the future.  Requested time 1752642429.927490 but the latest data is at time 3.800000, when looking up transform from frame [base_link] to frame [map]
  

not using sim time

for got to set map frame

idk talk about this (mention how this is a cleaner version):