Navigator.cpp
Go to the documentation of this file.
1#include "Navigator.h"
2
3#include <chrono>
4#include <cstdint>
5#include <functional>
6#include <future>
7#include <mutex>
8#include <string>
9#include <vector>
10
16
22
24{
25
26 Navigator::Navigator(const InjectedServices& services) : srv{services}
27 {
29 // these checks cannot be used when component is started in property-readout mode
30 ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
31 ARMARX_CHECK_NOT_NULL(srv.subscriber) << "Subscriber service must not be null!";
32
33 auto stopped_callback = [this](const auto& e) { stopped(StopEvent(e)); };
34
35 srv.subscriber->onGoalReached(stopped_callback);
36 srv.subscriber->onSafetyStopTriggered(stopped_callback);
37 srv.subscriber->onUserAbortTriggered(stopped_callback);
38 srv.subscriber->onInternalError(stopped_callback);
39 srv.subscriber->onGlobalPlanningFailed(stopped_callback);
40 }
41
42 void
44 {
46 moveTo(std::vector<core::Pose>{pose}, frame);
47 }
48
49 void
50 Navigator::moveTo(const std::vector<core::Pose>& waypoints, core::NavigationFrame frame)
51 {
53 ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
54 {
55 // TODO: This still leads to a race condition, if extern a stop event is generated before moveTo but arrives
56 // after the event is reset
57 std::scoped_lock const l{stoppedInfo.m};
58 stoppedInfo.event.reset();
59 }
60 forward("moveTo", [&] { srv.navigator->moveTo(waypoints, frame); });
61 }
62
63 void
65 {
67 ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
68
69 const std::vector<WaypointTarget>& path = builder.path();
70 validate(path);
71
72 {
73 // TODO: This still leads to a race condition, if extern a stop event is generated before moveTo but arrives
74 // after the event is reset
75 std::scoped_lock const l{stoppedInfo.m};
76 stoppedInfo.event.reset();
77 }
78 forward("moveTo", [&] { srv.navigator->moveTo(path, frame); });
79 }
80
81 void
82 Navigator::moveToAlternatives(const std::vector<core::TargetAlternative>& targets,
84 {
86 ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
87
88 {
89 // TODO: This still leads to a race condition, if extern a stop event is generated before moveTo but arrives
90 // after the event is reset
91 std::scoped_lock const l{stoppedInfo.m};
92 stoppedInfo.event.reset();
93 }
94 forward("moveToAlternatives",
95 [&] { srv.navigator->moveToAlternatives(targets, frame); });
96 }
97
98 void
99 Navigator::update(const std::vector<core::Pose>& waypoints, core::NavigationFrame frame)
100 {
102 ;
103 ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
104 forward("update", [&] { srv.navigator->update(waypoints, frame); });
105 }
106
107 void
109 {
111 ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
112
113 {
114 // TODO: This still leads to a race condition, if extern a stop event is generated before moveTo but arrives
115 // after the event is reset
116 std::scoped_lock const l{stoppedInfo.m};
117 stoppedInfo.event.reset();
118 }
119 forward("moveTowards", [&] { srv.navigator->moveTowards(direction, frame); });
120 }
121
122 void
124 const std::optional<std::string>& providerName)
125 {
127 ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
128
129 {
130 // TODO: This still leads to a race condition, if extern a stop event is generated before moveTo but arrives
131 // after the event is reset
132 std::scoped_lock const l{stoppedInfo.m};
133 stoppedInfo.event.reset();
134 }
135 forward("moveToLocation",
136 [&] { srv.navigator->moveToLocation(location, providerName); });
137 }
138
139 void
140 Navigator::setVelocityFactor(float velocityFactor)
141 {
143 ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
144 srv.navigator->setVelocityFactor(velocityFactor);
145 }
146
147 void
149 {
151 ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
152 srv.navigator->pause();
153 }
154
155 void
157 {
159 ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
160 srv.navigator->resume();
161 }
162
163 void
165 {
167 ARMARX_CHECK_NOT_NULL(srv.navigator) << "Navigator service must not be null!";
168 forward("stop", [&] { srv.navigator->stop(); });
169 }
170
171 void
172 Navigator::onGoalReached(const std::function<void(void)>& callback)
173 {
175 onGoalReached([&callback](const core::GoalReachedEvent&) { callback(); });
176 }
177
178 void
179 Navigator::onGoalReached(const std::function<void(const core::GoalReachedEvent&)>& callback)
180 {
181 }
182
183 void
184 Navigator::onWaypointReached(const std::function<void(int)>& callback)
185 {
186 }
187
189 Navigator::waitForStop(const std::int64_t timeoutMs)
190 {
192
193 std::future<void> future = std::async(
194 std::launch::async,
195 [&]()
196 {
197 std::unique_lock l{stoppedInfo.m};
198 stoppedInfo.cv.wait(l, [&i = stoppedInfo] { return i.event.has_value(); });
199 });
200
201
202 if (timeoutMs > 0)
203 {
204 ARMARX_VERBOSE << "future.wait()";
205 auto status = future.wait_for(std::chrono::milliseconds(timeoutMs));
206 ARMARX_VERBOSE << "done";
207
208 switch (status)
209 {
210 case std::future_status::ready:
211 ARMARX_INFO << "waitForStop: terminated on goal reached";
212 break;
213 case std::future_status::timeout:
214 ARMARX_INFO << "waitForStop: terminated due to timeout";
215 ARMARX_INFO << "Stopping robot due to timeout";
216 stop();
217
218 throw LocalException("Navigator::waitForStop: timeout");
219 break;
220 case std::future_status::deferred:
221 ARMARX_INFO << "waitForStop: deferred";
222 break;
223 }
224 }
225 else
226 {
227 ARMARX_VERBOSE << "future.wait()";
228 future.wait();
229 ARMARX_VERBOSE << "done";
230 }
231
232 // only due to timeout, stoppedInfo.event should be nullopt
233 ARMARX_CHECK(stoppedInfo.event.has_value());
234
235 StopEvent e = stoppedInfo.event.value();
236 stoppedInfo.event.reset();
237
238 return e;
239 }
240
241 void
242 Navigator::forward(const char* what, const std::function<void()>& call)
243 {
244 try
245 {
246 call();
247 }
248 catch (const std::exception& e)
249 {
250 // Without a server there will be no stop event; unblock waitForStop() locally.
251 ARMARX_WARNING << "Navigator call `" << what << "` failed: " << e.what();
252 stopped(StopEvent(core::InternalErrorEvent{
253 {armarx::Clock::Now()}, core::Pose::Identity(), std::string(what) + ": " + e.what()}));
254 }
255 }
256
257 void
258 Navigator::stopped(const StopEvent& e)
259 {
261 {
262 std::scoped_lock l{stoppedInfo.m};
263 stoppedInfo.event = e;
264 }
265 stoppedInfo.cv.notify_all();
266 }
267
268} // namespace armarx::navigation::client
static DateTime Now()
Current time on the virtual clock.
Definition Clock.cpp:93
void setVelocityFactor(float velocityFactor)
void update(const std::vector< core::Pose > &waypoints, core::NavigationFrame frame)
Definition Navigator.cpp:99
void moveToLocation(const std::string &location, const std::optional< std::string > &providerName)
Navigator(const InjectedServices &services)
Definition Navigator.cpp:26
void moveTo(const core::Pose &pose, core::NavigationFrame frame)
Definition Navigator.cpp:43
void moveToAlternatives(const std::vector< core::TargetAlternative > &targets, core::NavigationFrame frame)
Definition Navigator.cpp:82
StopEvent waitForStop(std::int64_t timeoutMs=-1)
void moveTowards(const core::Direction &direction, core::NavigationFrame frame)
void onGoalReached(const std::function< void(void)> &callback)
void onWaypointReached(const std::function< void(int)> &callback)
const WaypointTargets & path() const
Brief description of class targets.
Definition targets.h:39
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:179
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:191
#define ARMARX_VERBOSE
The logging level for verbose information.
Definition Logging.h:185
This file is part of ArmarX.
void validate(const std::vector< WaypointTarget > &path)
Eigen::Vector3f Direction
Definition basic_types.h:39
Eigen::Isometry3f Pose
Definition basic_types.h:31
This file is part of ArmarX.
Definition constants.cpp:4
Event describing that the targeted goal was successfully reached.
Definition events.h:53
Event describing the occurance of an internal unhandled error.
Definition events.h:105
#define ARMARX_TRACE
Definition trace.h:75