Open-source project
naturerobots/mesh_navigation avatar
naturerobots/mesh_navigation

MeshNav: navigating uneven terrain on a layered triangle mesh

The Mesh Navigation Stack: Efficient Mobile Robot Navigation in Uneven Terrain

913 stars109 forksC++BSD-3-Clause

At a glance

What is it?
The Mesh Navigation bundle is a ROS 2 stack for robot navigation on 2D manifolds represented in 3D as triangle meshes, where terrain properties such as steepness, roughness and clearance are computed by pluggable layers and combined into a traversability cost. It plugs into Move Base Flex as a set of planners and controllers, so the path planning interface stays the generic one.
Who is it for?
Adopt mesh_navigation when your robot operates on terrain that a flat occupancy grid cannot represent, since cost layers for steepness, roughness, ridges and clearance are the reason this stack exists and the 3D mesh is what lets them be computed. Do not adopt it for flat indoor environments where a standard grid planner is simpler and better supported, and do not skip Move Base Flex, since the plugin architecture, the action interface and the planner naming all assume it.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 10 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why a triangle mesh instead of a grid

The Mesh Navigation bundle, MeshNav for short, provides software for efficient robot navigation on 2D manifolds which are represented in 3D as triangle meshes. The point of that representation is that it lets you compute terrain properties directly on the surface the robot drives on.

A flat occupancy grid, which is what the classic ROS navigation stack assumes, can record where an obstacle is but it cannot easily record how steep the ground is or how rough it is. On a triangle mesh, both are geometric properties of the triangles themselves, so they can be computed and used as cost.

The stated goal is safe navigation in complex outdoor environments using a modularly extensible layered mesh map, where layers are loaded as plugins representing specific geometric or semantic metrics of the terrain. That is what lets obstacles in those environments be folded into path and motion planning.

The project is written in C++, is licensed BSD-3-Clause, and its documentation is published as Jazzy docs with a tutorials section. The topics attached to the repository name the mechanism directly: mesh, 3d-path-planning, pathplanning, control, locomotion, navigation and ros.

Cost layers are plugins that score every triangle

Mesh layers are plugins that compute cost or feature values for each triangle or vertex in the mesh. Each layer can represent a different geometric or semantic characteristic of the environment, and the implementation ships a set of them.

The four terrain property layers are HeightDiff, Roughness, Steepness and Ridge. HeightDiff measures elevation difference, which is what lets the planner know a slope is a step rather than a ramp. Roughness captures surface texture. Steepness is the gradeability of the surface. Ridge detects the linear terrain features that a wheeled robot can straddle but that a legged robot cannot.

The second group is closer to what a grid map does. Clearance measures distance to obstacles. Inflation expands that distance so the planner keeps a margin. Border marks the boundary of the mesh. Obstacle marks occupied regions.

The composition mechanism is the dependency graph. The layered approach allows combining multiple cost factors, for example steepness, roughness and obstacles, in a dependency graph structure to create a traversability assessment. That is the design idea that makes the stack extensible: a new kind of terrain knowledge is a new plugin, not a change to the planner.

The mesh_layers/ directory in the repository holds these implementations, and the docs include a tutorial page dedicated to the cost layers.

Planners and controllers that read the mesh

The planners and controllers are the part that turns a cost mesh into motion, and they are described as specifically designed to work with mesh maps, leveraging the 3D mesh structure to compute paths and control commands that respect the terrain geometry.

There are two global planners. Dijkstra lives in dijkstra_mesh_planner/DijkstraMeshPlanner, and the Continuous Vector Field Planner lives in cvp_mesh_planner/CVPMeshPlanner. Both are said to compute globally optimal paths across the mesh surface, taking into account the accumulated costs from all active mesh layers.

The controllers are the Vector Field Controller in mesh_controller/MeshController and MeshMPPI, which lives in a separate repository and provides DiffDriveMPC and BicycleMPC. The controllers generate velocity commands to follow the planned path while reacting to local obstacles and terrain features.

That the MPPI controller is a separate project is worth noting. MeshMPPI lives with the uos organisation rather than inside mesh_navigation, which tells you the local control part of the stack is developed alongside the map part rather than inside it, and you pull it in rather than getting it from this repository.

The mesh_map/ and mbf_mesh_core/ and mbf_mesh_nav/ directories hold the map implementation and the Move Base Flex integration, and the mbf_mesh_nav package is what exposes the plugins through the shared action interface.

Move Base Flex is the interface contract

MeshNav inherits the generic navigation interfaces from Move Base Flex, which is described as providing a universal, map agnostic ROS action interface for path planning, motion control and recovery behaviors.

This is the architectural decision that makes MeshNav usable in an existing ROS stack. Because the planner and controller are exposed as MBF plugins behind a standard action interface, the rest of your system does not need to know that the underlying map is a mesh. That flexibility is what the project credits for making MeshNav extensible and interoperable with other navigation approaches.

Move Base Flex is a separate repository, naturerobots/move_base_flex, and the header links it alongside mesh_tools, which is the companion package for mesh handling.

The plugin system is also the extension point for your own work. MeshNav provides a plugin system so that you can write your own plugins for mesh layers and mesh based planning and control, and the project already ships several implementations you can use out of the box. In practice this means a research group that needs a cost function nobody has written, for example one specific to a crop type or a specific gait, writes it as a layer and plugs it in.

One thing to be aware of: the global planner and controller identifiers in the repository carry the prefix of their own package, so the naming in a launch file is tied to which package a plugin came from.

Building it in a ROS 2 workspace

The installation needs a working ROS 2 installation, and the project targets humble and jazzy at the moment. The build is a standard colcon workflow in a ROS 2 workspace.

First you clone the source into the workspace source directory.

bash
git clone [email protected]:naturerobots/mesh_navigation.git

Then the dependencies come in two flavours. Source dependencies are fetched with vcs import using the source_dependencies.yaml file that lives at the repository root, and packaged dependencies are installed with rosdep.

The command is `vcs import --input mesh_navigation/source_dependencies.yaml`.

The rosdep invocation is `rosdep install --from-paths . --ignore-src -r -y`.

Then the build runs from the workspace root.

bash
colcon build --packages-up-to mesh_navigation

Using --packages-up-to rather than a plain build matters here, because the source dependencies include the companion repositories and you want their artifacts built in the right order.

The repository has CI workflows for both Jazzy and Humble, which is a good sign for a project that has to support two ROS distributions at once, since the badge shows both are built.

Start with the tutorials and the virtual worlds

The recommended entry point for new users is the mesh_navigation_tutorials, described as a ready to use mesh navigation stack including simulated environments, RViz setup and configuration files.

That is a deliberate design decision about how the project wants to be evaluated. The tutorials also ship a collection of virtual worlds that work even without a robot or powerful hardware, so the whole planning and control loop can be exercised in simulation first.

The tutorials are the recommended starting point rather than the source tree, and for a stack with this many interacting plugins that is the sane order. You learn the plugin configuration, the cost layer setup and the RViz visualisation on a world you control, and only then move to real terrain.

The research framing is also visible in the repository. There is a section asking people to reference specific papers when using the navigation stack in scientific work, which means there is published methodology behind the default configurations, and the documentation site carries the tutorials, the cost layer explanation and a planner and controller page.

The project sits with Nature Robots, the same group that maintains Move Base Flex and mesh_tools, so the three projects are meant to be used together rather than independently.

Editorial conclusion

Adopt mesh_navigation when your robot operates on terrain that a flat occupancy grid cannot represent, since cost layers for steepness, roughness, ridges and clearance are the reason this stack exists and the 3D mesh is what lets them be computed. Do not adopt it for flat indoor environments where a standard grid planner is simpler and better supported, and do not skip Move Base Flex, since the plugin architecture, the action interface and the planner naming all assume it. Verify first that your ROS 2 distribution is humble or jazzy, that you have read the plugin interface before writing your own layer, and that you start from the tutorial stack with its simulated environments rather than from a real robot.

Frequently asked questions

How do I build mesh_navigation for ROS 2?

Clone it into your workspace source directory, fetch source dependencies with vcs import --input mesh_navigation/source_dependencies.yaml, install packaged dependencies with rosdep install --from-paths . --ignore-src -r -y, then run colcon build --packages-up-to mesh_navigation from the workspace root. The project targets the humble and jazzy distributions.

What are mesh cost layers in mesh_navigation?

They are plugins that compute cost or feature values for each triangle or vertex in the mesh. The shipped layers cover HeightDiff, Roughness, Steepness and Ridge for terrain properties, plus Clearance, Inflation, Border and Obstacle, and multiple layers combine in a dependency graph to produce a traversability assessment.

Which planners and controllers does mesh_navigation provide?

Two global planners, dijkstra_mesh_planner/DijkstraMeshPlanner and cvp_mesh_planner/CVPMeshPlanner, both computing globally optimal paths over the accumulated layer costs, and two local controllers, mesh_controller/MeshController and MeshMPPI with DiffDriveMPC and BicycleMPC, the latter developed in a separate repository.

Do I need Move Base Flex to use mesh_navigation?

Yes, the design assumes it. MeshNav inherits the generic navigation interfaces from Move Base Flex, which provides the map agnostic ROS action interface for path planning, motion control and recovery behaviors, and MeshNav is exposed as a set of plugins behind that interface.

Official sources

  1. License: BSD-3-Clause
  2. naturerobots/mesh_navigation on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/naturerobots-mesh-navigation.svg)](https://hysenlabs.com/projects/naturerobots-mesh-navigation)

Was this useful?