ROS 2 Lyrical Luth · Lesson 76 of 86
Fleet management
Task queues, assignment, robot state tracking and open-source fleet tools.
Estimated time · 60–90 min
Learning goals
What you will understand
- Explain fleet management in your own words
- Use it in a small robotics example
- Verify the result instead of assuming it worked
Understand the idea first
The mental model
A fleet manager accepts tasks (move a pallet from A to B), assigns each to a robot, tracks robot state (position, battery, current task) and handles failures. Open-RMF is the ROS 2 framework for this; you can also write a simple manager yourself with a task queue, an assignment rule and a state table.
A basic assignment rule: give each new task to the idle robot with the lowest cost (distance to the pickup point, plus a penalty for low battery). Keep tasks idempotent and record every state change so a crash can resume. The robots stay autonomous; the manager only sends goals.
Guided lesson
Work through these steps
- 1.
Source the ROS 2 Lyrical environment in a fresh terminal.
- 2.
Read the fleet management example and identify what each line does.
- 3.
Build only the affected package, source the workspace overlay, and run the example.
- 4.
Inspect the result from a second terminal with the ros2 CLI or RViz2 and compare it with the expected result.
Worked example
Read it before you run it
struct Robot { std::string name; double x, y; bool idle; };
// What the manager knows about each robot.
const Robot* pick(const std::vector<Robot>& fleet, double tx, double ty) {
// Choose a robot for a task at (tx, ty).
const Robot* best = nullptr; double best_d = 1e9;
// No robot chosen yet.
for (const auto& r : fleet) {
// Look at every robot.
if (!r.idle) continue;
// Busy robots cannot take a new task.
double d = std::hypot(r.x - tx, r.y - ty);
// Distance from the robot to the task.
if (d < best_d) { best_d = d; best = &r; }
// Remember the nearest idle robot.
}
// End of the loop.
return best;
// nullptr if all are busy.
}
// End of pick.What the example is doing
- 1.The ros2 commands query the running graph; they do not prove that a node's internal behavior is correct.
- 2.Build from the workspace root, then source install/setup.bash so the shell can discover the new package.
- 3.Use a second sourced terminal to inspect nodes and interfaces while the example runs.
Watch it run · Mobile robot
See what this code does
The terminal types this lesson's practice solution and runs it. The scene shows the kind of robot behaviour that code drives. It plays by itself and loops.
Demo for Fleet management. Expected result: task -> robot_b
Practice code
Now type it yourself
Copy the starter into practice.cpp and replace every TODO with your own code. Build and run it: g++ -std=c++17 -Wall -Wextra -Wpedantic practice.cpp -o practice -pthread && ./practice
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
struct Robot {
std::string name;
double x, y;
bool idle;
};
const Robot* pick(const std::vector<Robot>& fleet, double tx, double ty) {
const Robot* best = nullptr;
double best_d = 1e9;
for (const auto& r : fleet) {
// TODO: skip busy robots; keep the idle robot with the smallest distance hypot(r.x - tx, r.y - ty)
}
return best;
}
int main() {
const std::vector<Robot> fleet{{"robot_a", 0, 0, false}, {"robot_b", 4, 0, true}, {"robot_c", 9, 9, true}};
if (const Robot* r = pick(fleet, 5, 0)) std::cout << "task -> " << r->name << '\n';
return 0;
}Expected output
task -> robot_bStuck? Show the full solution (try it yourself first)
#include <cmath>
#include <iostream>
#include <string>
#include <vector>
struct Robot {
std::string name;
double x, y;
bool idle;
};
const Robot* pick(const std::vector<Robot>& fleet, double tx, double ty) {
const Robot* best = nullptr;
double best_d = 1e9;
for (const auto& r : fleet) {
if (!r.idle) continue;
const double d = std::hypot(r.x - tx, r.y - ty);
if (d < best_d) {
best_d = d;
best = &r;
}
}
return best;
}
int main() {
const std::vector<Robot> fleet{{"robot_a", 0, 0, false}, {"robot_b", 4, 0, true}, {"robot_c", 9, 9, true}};
if (const Robot* r = pick(fleet, 5, 0)) std::cout << "task -> " << r->name << '\n';
return 0;
}Expected result
How you know it worked
- ROS_DISTRO is lyrical in every terminal used for the exercise.
- The complete package from the exercise builds and the expected graph entity appears in a second terminal.
Practical exercise
Apply the lesson
Write a fleet manager node with a task queue and the nearest-idle-robot rule, test it with three simulated robots and ten tasks, and record the assignments and how long each robot waited.
Before you continue
- ROS_DISTRO reports lyrical in every terminal you used
- The example builds and runs without errors
- You checked the result with a ros2 command, RViz2 or a test, not just by reading the code
If something goes wrong
Source /opt/ros/lyrical/setup.bash, build from the workspace root, then source install/setup.bash in that terminal.
Confirm both terminals use Lyrical, the same ROS_DOMAIN_ID, and compatible network/discovery settings.