linorobot2: a full Nav2 stack for a robot you can build from parts
Autonomous mobile robots (2WD, 4WD, Mecanum Drive)
At a glance
- What is it?
- linorobot2 is a ROS 2 package that takes a robot from bare hardware to autonomous navigation, with Nav2, SLAM Toolbox and robot_localization already wired together for 2WD, 4WD and Mecanum bases. Its most unusual tool is a GUI that turns a floor plan photograph into a Gazebo world, so you can rehearse your real hallway before you drive the real robot.
- Who is it for?
- linorobot2 fits a developer or student who wants a working autonomous navigation stack rather than an empty ROS 2 workspace, and it fits a hardware team that wants to validate a URDF and a map in simulation before cutting metal. It does not fit a robot with a kinematic model the package does not cover, since the supported bases are 2WD, 4WD and Mecanum, and it does not fit someone who needs the same code to run on a ROS 1 system.
- Can I use it commercially?
- Yes. Apache-2.0 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 17 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
From bare hardware to a navigating robot, with the middle already written
linorobot2 is a ROS2 package that takes your robot from bare hardware to fully autonomous navigation. The README is explicit about who it is for: you might be building a physical robot from accessible parts, simulating in Gazebo, learning Nav2, or prototyping new hardware, and linorobot2 gives you a complete, working foundation with Nav2, SLAM Toolbox and robot_localization already wired together.
That phrase, already wired together, is the entire value. A ROS 2 navigation stack is a large number of nodes, topics, transforms and parameters that have to agree with each other, and the first time most people assemble one they spend their time on configuration rather than on the behaviour they actually wanted to build. Here the Nav2 configuration, the SLAM Toolbox setup and the robot_localization EKF are supplied and documented, and the supported base configurations are 2WD, 4WD and Mecanum drive.
The documentation is at linorobot.github.io/linorobot2, and the repository also contains ROBOT_INSTALLATION.md, a docs directory and a mkdocs.yml, so the project is maintained as a documented product rather than as a bag of launch files.
For a reader evaluating it, the interesting question is not whether it can navigate. It obviously can, given that it ships Nav2. The question is whether the assumptions it makes about the robot match yours, and the answer is partly in the base configurations, partly in the sensor list, and partly in the fact that it targets ROS 2 Jazzy and the newer Lyrical distribution.
The same YAML files run the real robot and the simulation
The pre-integration is not just a set of launch files, it is a shared configuration, and that is the design decision with the most consequences.
The README states that the same YAML files are used by both the physical robot and the Gazebo simulation, so tuning in simulation transfers directly to hardware. The launch files are identical for physical and simulated robots, and the simulated commands are the same commands with sim:=true added.
This is a stronger claim than it first appears. Simulation and hardware normally diverge. The simulation has no motor noise, no wheel slip, no sensor dropouts, and the parameters that make a robot behave well in simulation are frequently the ones that make it oscillate on the floor. A project that shares the configuration does not remove that gap, but it removes a class of bug where the simulation and the robot disagree because somebody edited one YAML file and not the other.
The robot model is a templated URDF with a 2D lidar, an RGBD depth camera and an IMU already included and positioned. Changing the robot's dimensions or the sensor mounting positions is a matter of editing one properties file, and the README adds that the URDF is a solid starting point for a more detailed model: add your CAD meshes and the rest of the stack continues to work. That is the prototyping path in concrete form, validate the kinematics in Gazebo before cutting any parts.
The result is that the stack can be developed and tested without physical hardware, including path planners, state machines and perception pipelines, in what the README calls a consistent, reproducible environment.
image_to_gazebo turns a floor plan into a Gazebo world
The two tools in linorobot2_gazebo are the most distinctive part of the project, and one of them is unlike anything else in the ROS ecosystem.
image_to_gazebo is a GUI tool that takes any floor plan image, PNG, JPG, BMP and so on, lets you calibrate its real-world scale and set the coordinate origin interactively, and then generates a complete Gazebo world consisting of a 3D wall mesh, a model SDF and a world SDF. The workflow is: load your image, calibrate the scale by clicking two known points, set the coordinate origin, and click Generate. The tool writes the STL mesh, the model SDF and the world SDF to the package's models/ and worlds/ directories.
The point is stated plainly: both tools produce a Gazebo world that matches the geometry your lidar sees in the real environment, so you can develop and test your Nav2 application in simulation with the obstacle layout accurate, then deploy to the physical robot without surprises.
The other tool, create_worlds_from_maps, is a batch command line tool that converts all the SLAM maps in linorobot2_navigation/maps/ into Gazebo worlds in one command. That closes a loop that is otherwise awkward. You drive the robot once to build a map, and then you can regenerate the simulation world from that map rather than redrawing the floor plan by hand.
The floor plan route and the map route serve different situations. The image tool is for the case where you have a drawing, or a photograph of a whiteboard sketch, and want a world before the robot exists. The map tool is for the case where you have already mapped the building and want to reproduce the truth rather than the drawing.
The sensor list is long, and the install script does the remapping
Hardware compatibility is where robotics projects usually fall short, and this one takes it seriously.
linorobot2 supports a broad range of 2D lidars and RGBD depth cameras out of the box, and the install script sets up the correct driver and topic remappings automatically. The selected supported lidars are RPLIDAR A1, A2, A3, S1, S2, S3 and C1, LD06, LD19, STL27L, YDLIDAR, XV11, Intel RealSense used as a lidar, and ZED used as a lidar. The supported depth cameras are Intel RealSense D435 and D435i, the ZED family with ZED, ZED2, ZED2i and ZED Mini, and the OAK-D family with OAK-D, OAK-D Lite and OAK-D Pro.
The detail that matters is the remapping. A lidar on a different mount or a different model publishes its scans on a different topic, and every Nav2 and SLAM Toolbox parameter that refers to a topic then has to be adjusted by hand. Doing that automatically in the install script is the difference between a package you can try in an afternoon and one you spend a weekend configuring.
The full list lives in the Sensors documentation, docs/05_sensors.md, and the README is careful to point there rather than pretending the selection shown is exhaustive. For a reader, that file is the first thing to check, because the sensor you already own is the one that decides whether this project is usable for you.
The base platforms matter just as much. With 2WD, 4WD and Mecanum supported out of the box, the package covers differential drive, four wheel drive and omnidirectional mecanum platforms, which is most of what a hobby or research robot turns out to be.
The microcontroller joins the graph as a ROS 2 node
The hardware documentation lives in a separate repository, linorobot2_hardware, and it covers motor driver configuration and micro-ROS firmware for Teensy and compatible boards.
The mechanism is what makes the stack coherent. The firmware publishes odometry and IMU data over micro-ROS, so the microcontroller integrates as a ROS 2 node. In other words, the robot's wheel encoders and its inertial measurement unit are not bridged into ROS by a script on the robot computer; they are published by the microcontroller itself over a protocol designed for this, and the robot computer sees them as ordinary topics.
That is why the quickstart tells you to wait for the micro-ROS agent to print session established before continuing. Until the agent has a session with the microcontroller, there is no odometry, and a navigation stack with no odometry is a navigation stack that will not move.
The repository has a dedicated script for this part of the workflow, update_microros.bash, alongside install.bash and install_linorobot2.bash, which reflects the three distinct jobs in getting a robot running: install the software, install the robot stack, and update the firmware on the microcontroller.
The separation between the two repositories is also a maintenance decision rather than an accident. The firmware changes when the board changes, the ROS packages change when the distribution changes, and a robot owner needs to be able to update one without rebuilding the other.
Three terminals, and a map file at the end
The quickstart is written as a sequence, and it is worth following literally the first time, because the order encodes a dependency.
On the robot computer, the first terminal boots the stack with ros2 launch linorobot2_bringup bringup.launch.py, and you wait for the micro-ROS agent to print session established. The second terminal creates a map with ros2 launch linorobot2_navigation slam.launch.py, and the third drives the robot with ros2 run teleop_twist_keyboard teleop_twist_keyboard, which is the point at which the map is actually built, by driving.
Saving the map is a separate command, and it is run from the maps directory:
cd linorobot2/linorobot2_navigation/maps
ros2 run nav2_map_server map_saver_cli -f <map_name> --ros-args -p save_map_timeout:=10000.Then navigation replaces SLAM, with the map passed in as a parameter: ros2 launch linorobot2_navigation navigation.launch.py map:=<path_to_map>/<map_name>.yaml.
From the host machine, at any point, the linorobot2_viz package provides the same two launch files for visualisation, slam.launch.py during mapping and navigation.launch.py during navigation, which is what lets you watch a robot on a desk from another machine on the same network.
The simulated path is shorter and is the same commands with one argument added. You start Gazebo with ros2 launch linorobot2_gazebo gazebo.launch.py, and then run SLAM or navigation with sim:=true, for example ros2 launch linorobot2_navigation slam.launch.py sim:=true. Learning the whole navigation stack in simulation, on a laptop, before the robot exists is the cheapest possible first step, and the identical launch files are what makes the later transfer a copy and paste rather than a rewrite.
Apache-2.0, one branch per ROS 2 distribution
The licence is Apache-2.0, with the LICENSE file at the root of the repository, which is a permissive choice for a project that most users will run rather than modify.
The branch structure is the other operational fact. The README's build status table lists two ROS 2 distributions, Jazzy on the jazzy branch and Lyrical on the lyrical branch, each with its own GitHub Actions build badge for the build.yml workflow, and the default branch of the repository is jazzy. So the project is maintained per distribution, and a user on a different distro is not running a stale copy of the same code but a different branch built for their version.
The package layout is conventional ROS 2 and worth reading as a map. There is linorobot2_base, which holds the base packages, linorobot2_bringup for the startup launch files, linorobot2_description for the robot model and the properties file, linorobot2_gazebo for the simulation world and the two conversion tools, and linorobot2_navigation for the Nav2 and SLAM configuration and the maps directory. A docker directory sits alongside them, and the docker directory is there for containerised development.
There are no GitHub releases, so the version history is the commit history on the branch you are on, and the last push to the repository was on 2026-10-06. For a robotics project, that is a sensible arrangement: the artefacts people need are the launch files and the configuration, they are versioned with the distribution branch, and the documentation is published separately from the code at linorobot.github.io/linorobot2.
Editorial conclusion
linorobot2 fits a developer or student who wants a working autonomous navigation stack rather than an empty ROS 2 workspace, and it fits a hardware team that wants to validate a URDF and a map in simulation before cutting metal. It does not fit a robot with a kinematic model the package does not cover, since the supported bases are 2WD, 4WD and Mecanum, and it does not fit someone who needs the same code to run on a ROS 1 system. Before you start, pick the branch for your distribution, jazzy or lyrical, and check the sensor list in docs/05_sensors.md, because the driver setup for your lidar or depth camera is what the install script has to get right.
Frequently asked questions
What is linorobot2?
It is a ROS 2 package that takes a robot from bare hardware to fully autonomous navigation, with Nav2, SLAM Toolbox and robot_localization already wired together, and with 2WD, 4WD and Mecanum drive base configurations supported.
Can I use the same configuration for simulation and a real robot?
Yes. The README states that the same YAML files are used by both the physical robot and the Gazebo simulation, so tuning in simulation transfers directly to hardware, and the launch files are identical apart from the sim:=true argument.
What does image_to_gazebo do?
It is a GUI tool that takes a floor plan image, lets you calibrate its real-world scale by clicking two known points, set the coordinate origin and then generate a complete Gazebo world consisting of a 3D wall mesh, a model SDF and a world SDF, written to the package's models/ and worlds/ directories.
Which sensors does linorobot2 support?
A broad range of 2D lidars and RGBD depth cameras, including RPLIDAR A1 through C1, LD06, LD19, STL27L, YDLIDAR, XV11, RealSense and ZED used as lidars, and RealSense D435 and D435i, the ZED family and the OAK-D family as depth cameras. The install script sets up the correct driver and topic remappings automatically, and the full list is in docs/05_sensors.md.
How does the microcontroller connect to the ROS 2 system?
The micro-ROS firmware for Teensy and compatible boards publishes odometry and IMU data over micro-ROS, so the microcontroller integrates as a ROS 2 node. The quickstart tells you to wait for the micro-ROS agent to print session established before continuing.
Official sources
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.
[](https://hysenlabs.com/projects/linorobot-linorobot2)Was this useful?