PlatformControllerExecutor.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <filesystem>
5#include <utility>
6
13
19#include <armarx/navigation/platform_controller/aron/PlatformLocalTrajectoryControllerConfig.aron.generated.h>
22
24{
25
27 ControllerComponentPlugin& controllerComponentPlugin,
28 const Properties& properties,
29 const EmergencyStopInterface* emergencyStop) :
30 controllerPlugin_(controllerComponentPlugin),
31 properties_(properties),
32 emergencyStop_(emergencyStop)
33 {
35
36 if (properties_.rtUnitDynamicallyLoadLibraries)
37 {
38 ARMARX_WARNING
39 << "Dynamic loading of the controller library is deactivated (and this "
40 "is also desired). If loading the controllers is failing subsequently, "
41 "make sure that the RobotUnit's property `LoadLibraries` contains "
42 "`armarx_navigation:armarx_navigation_platform_controller`.";
43 }
44
45 // make default configs available to the memory
46 ARMARX_INFO << "Loading default configs";
47 {
48 // const std::filesystem::path configBasePath =
49 // PackagePath("armarx_navigation", "controller_config").toSystemPath();
50
51 ARMARX_TRACE;
52 // armarx::control::memory::config::parseAndStoreDefaultConfigs<
53 // armarx::navigation::common::ControllerType::PlatformTrajectory>(
54 // "" /*configBasePath*/, controllerComponentPlugin.configMemoryWriter());
55
56 ARMARX_TRACE;
57 }
58
59 // initialize controller
60 ARMARX_INFO << "Initializing local trajectory controller";
61 {
62 ARMARX_TRACE;
63 auto builder = controllerPlugin_.createControllerBuilder<
64 armarx::navigation::common::ControllerType::PlatformLocalTrajectory>();
65
66 ARMARX_TRACE;
67
68 const armarx::PackagePath configPath = [&]() -> armarx::PackagePath
69 {
70 const armarx::PackagePath baseConfigPath(
71 "armarx_navigation", "controller_config/PlatformTrajectory/default.json");
72
73 ARMARX_CHECK(std::filesystem::exists(baseConfigPath.toSystemPath()))
74 << baseConfigPath;
75
76 const armarx::PackagePath robotSpecificConfigPath(
77 "armarx_navigation",
78 "controller_config/PlatformTrajectory/" + properties_.robotName +
79 "default.json");
80
81 if (std::filesystem::exists(robotSpecificConfigPath.toSystemPath()))
82 {
83 return robotSpecificConfigPath;
84 }
85
86 return baseConfigPath;
87 }();
88
89 auto ctrlWrapper = builder.withNodeSet("PlatformPlanning")
90 .withConfig(configPath.toSystemPath())
91 .create();
92
94 ARMARX_CHECK_NOT_NULL(ctrlWrapper);
95 localTrajCtrl_ = std::move(ctrlWrapper);
96 localTrajCtrlInitialConfig_ = localTrajCtrl_->config;
97 }
98
100
101 ARMARX_INFO << "Initializing global trajectory controller";
102 {
104 auto builder = controllerPlugin_.createControllerBuilder<
106
108
109 builder.withNodeSet("PlatformPlanning");
110
111
112 // prefer robot-specific config if available
113 const armarx::PackagePath robotSpecificConfigPath(
114 "armarx_navigation",
115 "controller_config/GlobalTrajectory/" + properties.robotName + ".json");
116
117 if (std::filesystem::exists(robotSpecificConfigPath.toSystemPath()))
118 {
119 ARMARX_INFO << "Using robot specific config: " << robotSpecificConfigPath;
120 builder.withConfig(robotSpecificConfigPath.toSystemPath());
121 }
122 else // fallback: use default config
123 {
124 const armarx::PackagePath configPath(
125 "armarx_navigation", "controller_config/GlobalTrajectory/default.json");
126 builder.withConfig(configPath.toSystemPath());
127 }
128
129 auto ctrlWrapper = builder.create();
130
132 ARMARX_CHECK_NOT_NULL(ctrlWrapper);
133 globalTrajCtrl_ = std::move(ctrlWrapper);
134 globalTrajCtrlInitialConfig_ = globalTrajCtrl_->config;
135 }
136
138
140 ARMARX_CHECK_NOT_NULL(localTrajCtrl_);
141 ARMARX_VERBOSE << "PlatformControllerExecutor: init done.";
142 }
143
144 PlatformControllerExecutor::~PlatformControllerExecutor() = default;
145
146 void
148 const bool activateController)
149 {
150 ARMARX_VERBOSE << "Received trajectory for execution with " << trajectory.points().size()
151 << " points";
152
153 toAron(localTrajCtrl_->config.targets.trajectory, trajectory);
154
155 // sends the updated config to the controller and stores it in the memory
156 localTrajCtrl_->updateConfig();
157
158 if (activateController and not localTrajCtrl_->ctrl()->isControllerActive())
159 {
160 ARMARX_INFO << "Start local trajectory controller";
161
162 localTrajCtrl_->activate();
163 }
164 }
165
166 void
168 const bool activateController)
169 {
170 ARMARX_VERBOSE << "Received trajectory for execution with " << trajectory.points().size()
171 << " points";
172
173 toAron(globalTrajCtrl_->config.targets.trajectory, trajectory);
174
175 ARMARX_INFO << "Sending trajectory with "
176 << globalTrajCtrl_->config.targets.trajectory.points.size()
177 << " to controller.";
178
179 // sends the updated config to the controller and stores it in the memory
180 globalTrajCtrl_->updateConfig();
181
182 if (activateController and not globalTrajCtrl_->ctrl()->isControllerActive())
183 {
184 globalTrajCtrl_->activate();
185 }
186 }
187
188 void
190 {
191 ARMARX_INFO << "Start";
192 switch (controllerType)
193 {
195 if (globalTrajCtrl_ and not globalTrajCtrl_->ctrl()->isControllerActive())
196 {
197 globalTrajCtrl_->activate();
198 }
199 break;
201 if (localTrajCtrl_ and not localTrajCtrl_->ctrl()->isControllerActive())
202 {
203 localTrajCtrl_->activate();
204 }
205 break;
207 ARMARX_INFO << "No controller selected.";
208 break;
209 }
210 }
211
212 void
214 {
215 // While the emergency stop is engaged the RobotUnit keeps our controller deactivated. We
216 // run at the replanning rate, so without this we would see "inactive", activate, and
217 // repeat -- fighting the safety system for the whole duration of the stop.
218 if (emergencyStop_ != nullptr and emergencyStop_->isActive())
219 {
220 if (not emergencyStopWasActive_)
221 {
222 emergencyStopWasActive_ = true;
223 emergencyStopReleased_ = false;
224
225 // The RobotUnit has already deactivated our controller, but the *request*
226 // survives, and its "force switch to reactivate old" path resurrects the
227 // controller -- with the trajectory it was holding -- the moment the stop
228 // releases. The robot then stands where that profile assigns cruise speed, so
229 // the commanded twist steps from zero and the device ramp answers at its own
230 // maximum, far above the acceleration the trajectory was parametrized for.
231 // Withdrawing the request here leaves nothing to resurrect.
232 ARMARX_IMPORTANT << "The emergency stop was engaged. Withdrawing the trajectory "
233 "controller request so it is not resurrected on release.";
234 withdrawControllerRequests();
235 }
236
238 << "The emergency stop is engaged. Not activating the trajectory "
239 "controller.";
240 return;
241 }
242
243 if (emergencyStopWasActive_)
244 {
245 // Report the falling edge once. The navigator re-anchors the trajectory at the
246 // robot's current pose before we are asked to activate again.
247 emergencyStopWasActive_ = false;
248 emergencyStopReleased_ = true;
249
250 ARMARX_IMPORTANT << "The emergency stop was released.";
251 }
252
253 switch (controllerType)
254 {
256 if (globalTrajCtrl_)
257 {
258 if (not globalTrajCtrl_->ctrl()->isControllerActive())
259 {
261 << "The global trajectory controller is not active but "
262 "should be. Activating now.";
263 globalTrajCtrl_->activate();
264 }
265 }
266 break;
268 if (localTrajCtrl_)
269 {
270 if (not localTrajCtrl_->ctrl()->isControllerActive())
271 {
273 << "The local trajectory controller is not active but "
274 "should be. Activating now.";
275 localTrajCtrl_->activate();
276 }
277 }
278 break;
280 ARMARX_INFO << "No controller selected.";
281 break;
282 }
283 }
284
285 bool
287 {
288 const bool released = emergencyStopReleased_;
289 emergencyStopReleased_ = false;
290
291 return released;
292 }
293
294 void
295 PlatformControllerExecutor::withdrawControllerRequests()
296 {
297 // Deliberately no `isControllerActive()` guard -- see the declaration. `deactivate()`
298 // withdraws the request, which is what matters here; whether the controller is currently
299 // running is not the question.
300 if (localTrajCtrl_ and localTrajCtrl_->ctrl())
301 {
302 localTrajCtrl_->deactivate();
303 }
304
305 if (globalTrajCtrl_ and globalTrajCtrl_->ctrl())
306 {
307 globalTrajCtrl_->deactivate();
308 }
309 }
310
311 void
313 try
314 {
315 if (globalTrajCtrl_ == nullptr)
316 {
317 return;
318 }
319
320 // The controller ignores this unless its own `diagnostics.enabled` is set, so there is
321 // nothing to check here -- and nothing to pay when diagnostics are off beyond one config
322 // update per navigation request.
323 globalTrajCtrl_->config.diagnostics.dumpRequest += 1;
324 globalTrajCtrl_->updateConfig();
325 }
326 catch (const std::exception& e)
327 {
328 // A debugging aid must never be able to fail a navigation request.
329 ARMARX_WARNING << "Could not request the execution diagnostics dump: " << e.what();
330 }
331
332 void
334 {
335 lastActiveController_ = ControllerType::None;
336
337 ARMARX_INFO << "Stopping local trajectory controller (if available and active)";
338 if (localTrajCtrl_ && localTrajCtrl_->ctrl() &&
339 localTrajCtrl_->ctrl()->isControllerActive())
340 {
341 ARMARX_INFO << "Stopping local trajectory controller.";
342 localTrajCtrl_->deactivate();
343 lastActiveController_ = ControllerType::LocalTrajectory;
344 }
345 else
346 {
347 ARMARX_INFO << "Local trajectory controller was not available or active.";
348 }
349
350 ARMARX_INFO << "Stopping global trajectory controller (if available and active)";
351 if (globalTrajCtrl_ && globalTrajCtrl_->ctrl() &&
352 globalTrajCtrl_->ctrl()->isControllerActive())
353 {
354 ARMARX_INFO << "Stopping global trajectory controller.";
355 globalTrajCtrl_->deactivate();
356 lastActiveController_ = ControllerType::GlobalTrajectory;
357 }
358 else
359 {
360 ARMARX_INFO << "Global trajectory controller was not available or active.";
361 }
362
363
364 auto robotUnit = controllerPlugin_.getRobotUnitPlugin().getRobotUnit();
365 if (robotUnit)
366 {
367 const auto platformUnitPrx = robotUnit->getPlatformUnit();
368 if (platformUnitPrx)
369 {
370 ARMARX_INFO << "Stopping platform via PlatformUnit";
371 platformUnitPrx->stopPlatform();
372 }
373 else
374 {
375 ARMARX_WARNING << "PlatformUnit proxy not available, cannot stop platform";
376 }
377 }
378 else
379 {
380 ARMARX_INFO << "RobotUnit not available, cannot stop platform";
381 }
382 }
383
384 void
386 {
387
388 if (localTrajCtrl_->ctrl()->isControllerActive())
389 {
390 // keep the initial config as the upper limit
391 localTrajCtrl_->config.params.limits.linear =
392 std::min(limits.linear, localTrajCtrlInitialConfig_.params.limits.linear);
393 localTrajCtrl_->config.params.limits.angular =
394 std::min(limits.angular, localTrajCtrlInitialConfig_.params.limits.angular);
395
396 localTrajCtrl_->updateConfig();
397 }
398
399 if (globalTrajCtrl_->ctrl()->isControllerActive())
400 {
401 // keep the initial config as the upper limit
402 globalTrajCtrl_->config.params.limits.linear =
403 std::min(limits.linear, globalTrajCtrlInitialConfig_.params.limits.linear);
404 globalTrajCtrl_->config.params.limits.angular =
405 std::min(limits.angular, globalTrajCtrlInitialConfig_.params.limits.angular);
406
407 globalTrajCtrl_->updateConfig();
408 }
409 }
410
411 void
413 {
414 ARMARX_CHECK_POSITIVE(velocityFactor)
415 << "Scaling factor may not be negative, but is " << velocityFactor;
416 ARMARX_CHECK_LESS_EQUAL(velocityFactor, 1)
417 << "Scaling factor may not be > 1, but is " << velocityFactor;
418
419 if (localTrajCtrl_->ctrl()->isControllerActive())
420 {
421 localTrajCtrl_->config.params.velocityFactor = velocityFactor;
422
423 localTrajCtrl_->updateConfig();
424 }
425
426 if (globalTrajCtrl_->ctrl()->isControllerActive())
427 {
428 globalTrajCtrl_->config.params.velocityFactor = velocityFactor;
429
430 globalTrajCtrl_->updateConfig();
431 }
432 }
433
434} // namespace armarx::navigation::server
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
static void WaitFor(const Duration &duration)
Wait for a certain duration on the virtual clock.
Definition Clock.cpp:99
static Duration Seconds(std::int64_t seconds)
Constructs a duration in seconds.
Definition Duration.cpp:72
The robot's software emergency stop, as far as navigation needs to know it.
void ensureIsActive(ControllerType controllerType) override
PlatformControllerExecutor(ControllerComponentPlugin &controllerComponentPlugin, const Properties &properties, const EmergencyStopInterface *emergencyStop=nullptr)
void updateVelocityLimits(const core::TwistLimits &limits) override
bool consumeEmergencyStopRelease() override
Whether the emergency stop has been released since this was last asked.
armarx::control::client::ComponentPlugin ControllerComponentPlugin
void execute(const core::LocalTrajectory &trajectory, bool activateController=false) override
void dumpDiagnostics() override
Bumps the controller's diagnostics.dumpRequest, which makes it write the episode it has recorded and ...
#define ARMARX_CHECK_POSITIVE(number)
This macro evaluates whether number is positive (> 0) and if it turns out to be false it will throw a...
#define ARMARX_CHECK_LESS_EQUAL(lhs, rhs)
This macro evaluates whether lhs is less or equal (<=) rhs and if it turns out to be false it will th...
#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_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:188
#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 toAron(arondto::PackagePath &dto, const PackageFileLocation &bo)
#define ARMARX_TRACE
Definition trace.h:75