|
EasyFleet
A simple-by-default framework for multi-robot, multi-capability fleets built on ROS 2
|
Everything talking to a fleet from a mission-control process actually needs, regardless of what decides when to command which robot: the ROS node and background-spinning executor every RobotHandle rides on, one shared capability discovery pass, the registry of added robots, and the automatic status markers RobotHandle::run_capability() publishes. More...
#include <fleet_session.hpp>
Public Member Functions | |
| void | add_robot (RobotHandle &robot) |
| Adds robot to this session, attaching it so it can be discovered and commanded. | |
| const std::vector< std::reference_wrapper< RobotHandle > > & | robots () const noexcept |
| Every robot added so far, in add_robot() order – for code that needs to enumerate the fleet rather than command one robot it already knows the name of (e.g. | |
| std::optional< std::reference_wrapper< RobotHandle > > | find_robot (const std::string &name) const noexcept |
| Looks up a robot added so far by RobotHandle::name(). | |
| void | discover_capabilities (std::chrono::milliseconds window=std::chrono::milliseconds(2500)) |
| Runs exactly one discovery scan (see today's easyfleet_mission_manager::discover_capabilities(), which this wraps) and fans the results out to every added RobotHandle's own has_capability()/run_capability()/etc. | |
| void | spin_some () |
| One non-blocking spin of the underlying executor's queued work – call this in a while (robot.is_capability_running(...)) loop the way the sketch this design started from does, instead of blocking. | |
| void | spin_for (std::chrono::milliseconds duration) |
| Blocks for exactly duration, still spinning underneath (equivalent to a bounded spin_some() loop) – for phases with a deliberate, fixed-length window rather than a "wait for completion" one (e.g. | |
| rclcpp::Node::SharedPtr | node () const noexcept |
| Underlying node, for anything not yet covered by RobotHandle (matches today's escape hatch of reaching for node.get() directly). | |
| void | shutdown () |
| Cancels the executor, joins its background thread, and calls rclcpp::shutdown() – the mission-side mirror of easyfleet_core::Deployment::run()'s teardown. | |
Friends | |
| class | RobotHandle |
Everything talking to a fleet from a mission-control process actually needs, regardless of what decides when to command which robot: the ROS node and background-spinning executor every RobotHandle rides on, one shared capability discovery pass, the registry of added robots, and the automatic status markers RobotHandle::run_capability() publishes.
SimpleController – a plain mission script driving robots by hand – is the simplest possible thing built on top of a FleetSession, but it's deliberately not the only thing that can be: a FleetSession has no notion of "how a mission decides what to do next", only "how to talk to the robots once something has decided". That's what makes it the right thing for other controller flavors to build on too – e.g. an LLMController that, from inside its own spin_some(), asks a model what to do next and calls run_capability() accordingly; or a PlanSys2Controller whose PDDL action implementations reach into the fleet through robots()/find_robot() to actually move things. Each such controller owns a FleetSession by composition (a plain member, not a base class to inherit from and override) and adds whatever domain-specific decision logic it needs around it – matching how the rest of this codebase favors composition/mixins (ActionServerBase, Capability<T>) over runtime-polymorphic base classes. A user is free to write their own controller the same way, with no support needed from this class beyond what's public here.
Usage (this is genuinely all SimpleController itself does):
| void add_robot | ( | RobotHandle & | robot | ) |
Adds robot to this session, attaching it so it can be discovered and commanded.
| robot | Must outlive this FleetSession. |
| void discover_capabilities | ( | std::chrono::milliseconds | window = std::chrono::milliseconds(2500) | ) |
Runs exactly one discovery scan (see today's easyfleet_mission_manager::discover_capabilities(), which this wraps) and fans the results out to every added RobotHandle's own has_capability()/run_capability()/etc.
– never a redundant per-robot re-scan, unlike calling RobotHandle::discover_capabilities() independently on each robot would be.
| window | How long to listen before returning, same meaning as today's discover_capabilities() window parameter. |
|
noexcept |
Looks up a robot added so far by RobotHandle::name().
| name | Name to look up, as passed to RobotHandle's constructor. |
|
noexcept |
Underlying node, for anything not yet covered by RobotHandle (matches today's escape hatch of reaching for node.get() directly).
|
noexcept |
Every robot added so far, in add_robot() order – for code that needs to enumerate the fleet rather than command one robot it already knows the name of (e.g.
building an LLM prompt describing every robot, or a PDDL problem instance).
| void spin_for | ( | std::chrono::milliseconds | duration | ) |
Blocks for exactly duration, still spinning underneath (equivalent to a bounded spin_some() loop) – for phases with a deliberate, fixed-length window rather than a "wait for completion" one (e.g.
"10 seconds into this goal, redirect it elsewhere regardless of progress").
| duration | How long to block for. |