Skip to content

Topological YAML Format

Marc Hanheide edited this page Oct 15, 2026 · 2 revisions

Topological Map Format (.tmap2.yaml / .tmap3.yaml)

Topological maps are YAML files. This page describes the current ROS 2 format; the authoritative definition is the JSON schema config/tmap-schema.yaml (draft-07, additionalProperties: true almost everywhere, so extra application specific keys are allowed). Validate a map with:

ros2 run topological_navigation validate_map.py my_map.tmap2.yaml
# or, without ROS 2
python3 topological_navigation/topological_navigation/validate_map.py my_map.tmap2.yaml

Both extensions (.tmap2.yaml and .tmap3.yaml) use this structure. The tmap3 variant is what convert_tmap.py produces from legacy maps: nodes carry nav_frame, transformation uses topo_frame_id, snake_case action names are used, and the definitions and actions sections are normally kept in a sidecar file (see below).

Top-level structure

meta:
  last_updated: 07-15-2026_13-26-26    # required, MM-DD-YYYY_HH-MM-SS
  origin: {latitude: 53.268, longitude: -0.524, altitude: 0}   # optional GPS origin
metric_map: my_farm                    # required
name: my_farm                          # required
pointset: my_farm                      # required
navigation_config_file: topological_navigation_config.yaml     # optional sidecar

transformation:                        # published by map_manager2 as a static TF
  topo_frame_id: my_farm               # child frame of the node poses
  parent: map                          # parent TF frame
  rotation: {w: 1.0, x: 0.0, y: 0.0, z: 0.0}
  translation: {x: 0.0, y: 0.0, z: 0.0}

definitions: {}                        # reusable values, e.g. behaviour trees
actions: {}                            # named edge actions
nodes: []                              # required

Required by the schema: meta (with meta.last_updated), metric_map, name, nodes and pointset. transformation, definitions and actions are needed in practice for navigation (the former for the TF and the latter two for goal building, either inline or via the sidecar).

Nodes

nodes:
  - meta:                              # required: map, node, pointset
      map: my_farm
      node: RowEntry_A1
      pointset: my_farm
      tag: [node_semantic::indoor]     # optional extra meta
    node:
      name: RowEntry_A1                # required
      nav_frame: '${transformation.topo_frame_id}'
      pose:
        position: {x: 10.5, y: 5.2, z: 0.0}
        orientation: {w: 0.707, x: 0.0, y: 0.0, z: 0.707}
      properties:                      # optional, freeform
        xy_goal_tolerance: 0.3
        yaw_goal_tolerance: 0.1
      verts:                           # influence zone polygon, relative to the node pose
        - {x: -0.5, y: -0.5}
        - {x: 0.5, y: -0.5}
        - {x: 0.5, y: 0.5}
        - {x: -0.5, y: 0.5}
      edges: []                        # required: outgoing edges
Field Description
meta.map, meta.node, meta.pointset Required. Further meta keys are allowed.
node.name Unique node name, used as the GotoNode target.
node.edges Required list of outgoing edges (may be empty).
node.pose Position and orientation in the node frame (nav_frame or the topo_frame_id frame).
node.nav_frame Frame used for the goal poses. A ${transformation.<key>} reference is resolved against the map.
node.verts Influence zone polygon vertices relative to the node pose. The robot is at the node while inside the polygon. An empty list means no zone.
node.properties Freeform dictionary, see Properties.
node.localise_by_topic Optional JSON string for topic based localisation, see the topological_navigation README.

Edges

edges:
  - edge_id: RowEntry_A1_RowEnd_A1     # required, unique
    node: RowEnd_A1                    # required, destination node name
    action: row_traversal              # key into the 'actions' section
    properties:                        # optional
      max_speed: 0.5
      boundary_left: 0.4
      boundary_right: 0.6
Field Description
edge_id Required. By convention <origin>_<destination>.
node Required. Name of the destination node.
action Name of an entry in actions.
properties Optional freeform dictionary, see Properties.

Actions and definitions

actions maps an action name to the way an edge using it is executed. definitions holds named values, typically Nav2 behaviour tree XML, that goal templates can reference.

definitions:
  default_bt: |
    <root main_tree_to_execute="MainTree">
      <BehaviorTree ID="MainTree">
        <PipelineSequence name="NavigateWithReplanning">
          <ComputePathToPose goal="{goal}" path="{path}" planner_id="GridBased"/>
          <FollowPath path="{path}" controller_id="FollowPath"/>
        </PipelineSequence>
      </BehaviorTree>
    </root>

actions:
  navigate_to_pose:
    composable: false                              # consecutive edges are not merged
    action_type: nav2_msgs.action.NavigateToPose   # dotted Python import path
    action_server: /navigate_to_pose
    action_goal_template:
      pose:
        header:
          frame_id: '${node.nav_frame}'
        pose: '${node.pose}'
      behavior_tree: '${definitions.default_bt}'

  row_traversal:
    composable: true                               # consecutive row_traversal edges become one goal
    action_type: nav2_msgs.action.NavigateThroughPoses
    action_server: /navigate_through_poses
    ros_parameters:                                # edge property -> goal checker parameter
      max_speed: FollowPath.max_robot_speed
    set_ros_params:                                # constants set while the segment runs
      collision_monitor:
        FootprintApproach.enabled: false
    action_goal_template:
      poses:
        - header:
            frame_id: '${node.nav_frame}'
          pose: '${node.pose}'
      behavior_tree: '${definitions.row_traversal_bt}'
Key Description
action_type Required. Dotted Python path of the ROS action type.
action_server Required. Name of the action server. One client is created per unique (action_type, action_server) pair.
action_goal_template Required. Goal structure; ${node.<attr>}, ${transformation.<key>} and ${definitions.<name>} are substituted.
composable Whether consecutive edges with this action are merged into one goal (the template is then repeated per node in poses).
ros_parameters Optional. Maps an edge property name to a parameter of the goal checker node.
set_ros_params Optional. Constant ROS parameters applied during the segment and restored afterwards.

The default action configuration is in config/topological_navigation_config.yaml and defines navigate_to_pose, navigate_to_poses, navigate_through_poses, goal_align and row_traversal. See doc/NAVIGATION2.md and doc/SET_ROS_PARAMS.md for details, including how edge properties are merged within a segment.

Sidecar configuration file

definitions and actions may live in a separate YAML file (schema: config/navigation-config-schema.yaml, both sections required, no other top-level keys). Reference it from the map with navigation_config_file, or pass --navigation-config-file to map_manager2.py (the launch file argument is navigation_config_file). Relative paths are resolved against the map file. Only definitions and actions are imported and sections that exist inline in the map take precedence.

Properties

Both nodes and edges accept an optional properties dictionary of arbitrary keys. Read them defensively, since none are mandatory.

Level Property Used by
node xy_goal_tolerance, yaw_goal_tolerance Pushed to the Nav2 goal checker while heading to the node
node roboflow.enabled Highlighted in the web app
node semantics, zone, any namespaced dictionary Application specific
edge boundary_left, boundary_right Corridor half-widths (m) used for the boundary polygon and route map
edge set_ros_params Per-edge override of the action's set_ros_params
edge any key listed in the action's ros_parameters (for example max_speed) Forwarded to the mapped ROS parameter

Namespacing (for example roboflow: {enabled: true, confidence: 0.7}) is recommended to avoid clashes between applications.

Legacy fields

Older (ROS 1 era) maps used parent_frame, restrictions_planning, restrictions_runtime, action_type, fluid_navigation, fail_policy, config, top_vel and goal with $node.pose style references. These are not used by the ROS 2 navigation server. Use convert_tmap.py to migrate such maps.

Related tools

Tool Purpose
map_analyser.py analyse / check Schema, orphaned nodes, disconnected sub-maps, zone overlaps, statistics
map_analyser.py svg / minify / merge Render, compress with YAML anchors, merge maps
map_recorder.py / manual_topomapping.py Create maps while driving
topological_map_visualiser.py Edit node positions in RViz and save the map

Clone this wiki locally