EasyFleet
A simple-by-default framework for multi-robot, multi-capability fleets built on ROS 2
Loading...
Searching...
No Matches
mission_helpers.hpp
1// Copyright 2026 Intelligent Robotics Lab
2//
3// This file is part of the project EasyFleet
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#ifndef EASYFLEET_MISSION_MANAGER__MISSION_HELPERS_HPP_
17#define EASYFLEET_MISSION_MANAGER__MISSION_HELPERS_HPP_
18
19#include <algorithm>
20#include <chrono>
21#include <functional>
22#include <optional>
23#include <sstream>
24#include <string>
25#include <thread>
26#include <vector>
27
28#include "easyfleet_interfaces/action/manipulation.hpp"
29#include "easyfleet_interfaces/action/navigation.hpp"
30#include "easyfleet_interfaces/action/perception.hpp"
31#include "geometry_msgs/msg/pose_stamped.hpp"
32#include "rclcpp/rclcpp.hpp"
33
34#include "easyfleet_mission_manager/ansi.hpp"
35#include "easyfleet_mission_manager/capability_info.hpp"
36#include "easyfleet_mission_manager/output.hpp"
37#include "easyfleet_mission_manager/throttle.hpp"
38
39// Shared by every mission script (main_alone.cpp, main_collaboration.cpp,
40// ...): the easyfleet_interfaces action types the mock capabilities speak,
41// how to build a demo goal and a feedback printer for each of them, and
42// small terminal/discovery helpers. Kept here instead of duplicated
43// per-mission so all scripts stay in sync as capabilities evolve.
44namespace easyfleet_mission_manager
45{
46
47using Navigation = easyfleet_interfaces::action::Navigation;
48using Manipulation = easyfleet_interfaces::action::Manipulation;
49using Perception = easyfleet_interfaces::action::Perception;
50
53constexpr std::chrono::seconds kRunTimeout(10);
54
58inline std::thread spin_in_background(rclcpp::Executor & executor)
59{
60 std::thread thread([&executor] {executor.spin();});
61 while (!executor.is_spinning()) {
62 std::this_thread::yield();
63 }
64 return thread;
65}
66
68inline void print_section(const std::string & title)
69{
70 std::ostringstream out;
71 out << "\n" << ansi::bold << ansi::blue << "== " << title << " ==" << ansi::reset;
72 safe_print(out.str());
73}
74
77inline void print_step(const std::string & text)
78{
79 safe_print(std::string(" ") + ansi::dim + text + ansi::reset);
80}
81
87inline std::optional<std::reference_wrapper<const CapabilityInfo>> find_robot_capability(
88 const std::vector<CapabilityInfo> & capabilities,
89 const std::string & robot, const std::string & capability)
90{
91 auto it = std::find_if(
92 capabilities.begin(), capabilities.end(),
93 [&](const CapabilityInfo & info) {
94 return info.robot == robot && info.capability == capability && info.active;
95 });
96 if (it == capabilities.end()) {
97 return std::nullopt;
98 }
99 return std::cref(*it);
100}
101
102inline Navigation::Goal make_navigation_goal()
103{
104 Navigation::Goal goal;
105 goal.target_pose.header.frame_id = "map";
106 goal.target_pose.pose.position.x = 2.0;
107 goal.target_pose.pose.position.y = 1.0;
108 goal.target_pose.pose.orientation.w = 1.0;
109 return goal;
110}
111
119inline Navigation::Goal make_navigation_goal(const std::string & waypoint_id)
120{
121 Navigation::Goal goal;
122 goal.parameters_json = R"({"goal_id": ")" + waypoint_id + R"("})";
123 return goal;
124}
125
130inline std::function<void(const Navigation::Feedback & )> make_navigation_feedback_printer(
131 const std::string & label)
132{
133 Throttle throttle(std::chrono::milliseconds(500));
134 return [throttle, label](const Navigation::Feedback & feedback) {
135 if (!throttle.ready()) {
136 return;
137 }
138 std::ostringstream out;
139 out << " " << ansi::dim << "[" << label << "] " << ansi::reset
140 << "distance_remaining=" << feedback.distance_remaining << "m, "
141 << "elapsed=" << feedback.navigation_time.sec << "s, "
142 << "recoveries=" << feedback.number_of_recoveries;
143 safe_print(out.str());
144 };
145}
146
147inline Manipulation::Goal make_manipulation_goal()
148{
149 Manipulation::Goal goal;
150 goal.mode = Manipulation::Goal::MODE_JOINT_TARGET;
151 goal.joint_target.name = {"joint1"};
152 goal.joint_target.position = {1.0};
153 return goal;
154}
155
159inline Manipulation::Goal make_manipulation_goal(const geometry_msgs::msg::PoseStamped & pose)
160{
161 Manipulation::Goal goal;
162 goal.mode = Manipulation::Goal::MODE_POSE_TARGET;
163 goal.pose_target = pose;
164 return goal;
165}
166
167inline std::function<void(const Manipulation::Feedback & )> make_manipulation_feedback_printer(
168 const std::string & label)
169{
170 Throttle throttle(std::chrono::milliseconds(500));
171 return [throttle, label](const Manipulation::Feedback & feedback) {
172 if (!throttle.ready()) {
173 return;
174 }
175 std::ostringstream out;
176 out << " " << ansi::dim << "[" << label << "] " << ansi::reset
177 << "state=" << feedback.state;
178 safe_print(out.str());
179 };
180}
181
182inline Perception::Goal make_perception_goal()
183{
184 Perception::Goal goal;
185 goal.object_classes.push_back("gato");
186 return goal;
187}
188
191inline Perception::Goal make_perception_goal(const std::vector<std::string> & object_classes)
192{
193 Perception::Goal goal;
194 goal.object_classes = object_classes;
195 return goal;
196}
197
198inline std::function<void(const Perception::Feedback & )> make_perception_feedback_printer(
199 const std::string & label)
200{
201 Throttle throttle(std::chrono::milliseconds(500));
202 return [throttle, label](const Perception::Feedback & feedback) {
203 if (!throttle.ready()) {
204 return;
205 }
206 std::ostringstream out;
207 out << " " << ansi::dim << "[" << label << "] " << ansi::reset
208 << feedback.detections_3d.detections.size() << " cat(s) detected (3D + 2D)";
209 safe_print(out.str());
210 };
211}
212
213} // namespace easyfleet_mission_manager
214
215#endif // EASYFLEET_MISSION_MANAGER__MISSION_HELPERS_HPP_
Value-semantics rate limiter: copies (e.g.
Definition throttle.hpp:30
Everything known about one running capability instance, gathered from its /capabilities (easyfleet_in...
Definition capability_info.hpp:33