Component.cpp
Go to the documentation of this file.
1/**
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package Navigation::ArmarXObjects::Navigator
17 * @author Fabian Reister ( fabian dot reister at kit dot edu )
18 * @author Christian R. G. Dreher ( c dot dreher at kit dot edu )
19 * @date 2021
20 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
21 * GNU General Public License
22 */
23
24#include "Component.h"
25
26#include <algorithm>
27#include <cmath>
28#include <cstdint>
29#include <experimental/memory>
30#include <iterator>
31#include <memory>
32#include <optional>
33#include <string>
34#include <tuple>
35#include <utility>
36#include <vector>
37
38#include <Eigen/Geometry>
39
40#include <Ice/Current.h>
41
42#include <opencv2/core/eigen.hpp>
43
44#include <SimoxUtility/color/ColorMap.h>
45#include <SimoxUtility/color/cmaps/colormaps.h>
46
56
59#include <RobotAPI/interface/ArViz/Elements.h>
60#include <RobotAPI/interface/aron/Aron.h>
62
64#include <armarx/navigation/client/ice/NavigatorInterface.h>
83
88
89namespace armarx::navigation
90{
91
92 std::vector<core::Pose>
93 convert(const std::vector<Eigen::Matrix4f>& wps)
94 {
95 std::vector<core::Pose> p;
96 p.reserve(wps.size());
97 std::transform(wps.begin(),
98 wps.end(),
99 std::back_inserter(p),
100 [](const auto& p) { return core::Pose(p); });
101 return p;
102 }
103
104} // namespace armarx::navigation
105
107{
108
109 Component::Component() : parameterizationService(nullptr, nullptr)
110 // publisher(&resultsWriter, &eventsWriter)
111 {
112 // scene().timeServer = &timeServer;
113
114 addPlugin(parameterizationReaderPlugin);
115 addPlugin(parameterizationWriterPlugin);
116 addPlugin(eventsWriterPlugin);
117 addPlugin(resultsWriterPlugin);
118 addPlugin(graphReaderPlugin);
119 addPlugin(costmapReaderPlugin);
120 addPlugin(costmap3dReaderPlugin);
121 addPlugin(humanReaderPlugin);
122 addPlugin(laserScannerFeaturesReaderPlugin);
123
124 addPlugin(virtualRobotReaderPlugin);
125
126 parameterizationService = server::MemoryParameterizationService(
127 &parameterizationReaderPlugin->get(), &parameterizationWriterPlugin->get());
128 }
129
130
131 Component::~Component() = default;
132
133 void
135 {
136 usingProxy("RobotStateMemory");
137 usingProxy("ObjectMemory");
138 usingProxy("navigation_memory");
139 }
140
141 void
143 {
145
146 // virtualRobotReaderPlugin->get().setSyncTimeout(Duration::MilliSeconds(20));
147 // virtualRobotReaderPlugin->get().setSleepAfterSyncFailure(Duration::MilliSeconds(10));
148
150
151 // initialize scene provider
153 {
155 .graphReader = &graphReaderPlugin->get(),
156 .costmapReader = &costmapReaderPlugin->get(),
157 .costmap3dReader = &costmap3dReaderPlugin->get(),
158 .virtualRobotReader = &virtualRobotReaderPlugin->get(),
159 .humanReader = &humanReaderPlugin->get(),
160 .laserScannerFeaturesReader = &laserScannerFeaturesReaderPlugin->get(),
161 .objectPoseClient = ObjectPoseClientPluginUser::getClient()};
162
163 // emplace (below) will be effectless if object is already initialized
164 if (sceneProvider)
165 {
166 ARMARX_INFO << "Resetting scene provider";
167 sceneProvider.reset();
168 }
169 sceneProvider.emplace(srv, params.sceneCfg);
170 }
171
173
175
176 if (not params.disableExecutor)
177 {
178 if (executor)
179 {
180 ARMARX_INFO << "Executor will be reset.";
181 executor.reset();
182 }
183
184 // Resolved here rather than declared with `usingProxy`: that would make the
185 // navigator wait for the emergency stop master and would break every deployment and
186 // test that does not run one. Its absence is tolerated and means "not configured";
187 // once resolved, a failure to reach it counts as broken and blocks activation.
188 emergencyStop.reset();
189 if (not params.emergencyStopMasterName.empty())
190 {
191 try
192 {
193 emergencyStop.emplace(
194 getProxy<EmergencyStopMasterInterfacePrx>(params.emergencyStopMasterName));
195 ARMARX_INFO << "Emergency stop master "
196 << QUOTED(params.emergencyStopMasterName)
197 << " resolved. Controllers will not be activated while it is "
198 "engaged.";
199 }
200 catch (const std::exception& e)
201 {
202 ARMARX_WARNING << "Emergency stop master "
203 << QUOTED(params.emergencyStopMasterName)
204 << " is not available: " << e.what()
205 << ". Proceeding without an emergency stop check.";
206 }
207 }
208
209 executor.emplace(
212 .robotName = params.sceneCfg.robotName,
213 .rtUnitDynamicallyLoadLibraries = params.rtUnitDynamicallyLoadLibraries},
214 emergencyStop ? &emergencyStop.value() : nullptr);
215 }
216
218
219 if(introspector)
220 {
221 ARMARX_INFO << "Resetting introspector";
222 introspector.reset();
223 }
224 introspector = server::ArvizIntrospector(
226 // memoryIntrospector = server::MemoryIntrospector(resultsWriterPlugin->get(), );
227
228 // initialized = true;
229
230 // Setup the remote GUI.
231 {
234 }
235
236 ARMARX_INFO << "Initialized. Will now respond to navigation requests.";
237 }
238
239 void
241 {
243
244 // "Running" in a broader sense. The navigator could also be paused but will be stopped subsequenty.
245 // Scoped: the snapshot holds the entries alive, and holding it across the resets below
246 // would destroy the navigators after the executor they call `stop()` on.
247 bool isAnyNavigatorRunning = false;
248 {
249 const auto entries = allEntries();
250 isAnyNavigatorRunning = std::any_of(
251 entries.begin(),
252 entries.end(),
253 [](const auto& p) -> bool { return not p.second->navigator.isStopped(); });
254 }
255
256 if (isAnyNavigatorRunning)
257 {
259 << "A navigator was running when the component got disconnected. Will try to stop "
260 "as much as possible but expect something to be broken now.";
261 }
262
263 stopAllImpl(isAnyNavigatorRunning);
264
265 // Drop the registrations before the services they point into. Every navigator holds
266 // raw `srv.sceneProvider` / `srv.executor` / `srv.introspector` / `srv.drawer`
267 // pointers, so entries left registered across the resets below stay callable with
268 // dangling services and the next request faults inside the navigator. That it
269 // currently survives a reconnect at all is an accident of `std::optional` reusing its
270 // inline storage, which puts the re-`emplace`d services back at the same addresses.
271 //
272 // Clients must re-register with `createConfig` after a reconnect. Every client in the
273 // tree already does: statecharts and `NavigatingSkillHelper` register per invocation,
274 // and `DigitalRobotTwinComponentPlugin` registers from `postOnConnectComponent()`.
275 // A client that registered only once would have to call `configureNavigator()` again.
276 //
277 // Swapped out under the lock and destroyed after it: `~Navigator` joins the periodic
278 // task, and joining while holding `navigatorsMtx` would deadlock a waiting request.
279 decltype(navigators) stale;
280 {
281 const std::scoped_lock lock{navigatorsMtx};
282 stale.swap(navigators);
283 }
284 stale.clear();
285
286 sceneProvider.reset();
287 executor.reset();
288 introspector.reset();
289 }
290
291 void
295
296 bool
298 {
300 return sceneProvider->initialize(armarx::Clock::Now());
301 }
302
303 std::string
305 {
306 return GetDefaultName();
307 }
308
309 std::string
311 {
312 return "navigator";
313 }
314
315 void
317 const std::string& callerId,
318 const Ice::Current&)
319 {
320 // TODO: Not thread-safe.
322 ARMARX_INFO << "Creating config for caller " << QUOTED(callerId);
323
324 parameterizationService.store(stackConfig, callerId, armarx::Clock::Now());
325
328 sceneProvider->scene(),
331
332 // FIXME unify this. The local planner also needs the visu. Yet, it is passed to the navigation stack factory above now.
333 // set visualization of LocalPlanner
334 if (stack.localPlanner)
335 {
336 stack.localPlanner->setVisualization(getArvizClient());
337 }
338
339 auto memoryIntrospector =
340 std::make_unique<server::MemoryIntrospector>(resultsWriterPlugin->get(), callerId);
341
342 auto memoryPublisher = std::make_unique<server::MemoryPublisher>(
343 &resultsWriterPlugin->get(), &eventsWriterPlugin->get(), callerId);
344
345 server::ExecutorInterface* executorPtr = nullptr;
346 if (executor.has_value())
347 {
348 executorPtr = &executor.value();
349 }
350
351 // Extract goal reached config from stack config if present
352 server::GoalReachedMonitorConfig goalReachedCfg = params.navigatorGoalReachedConfig;
353 {
354 aron::data::Dict aronDict(stackConfig);
355 const std::string goalReachedKey =
357 if (aronDict.hasElement(goalReachedKey))
358 {
359 auto goalReachedElement =
360 aron::data::Dict::DynamicCast(aronDict.getElement(goalReachedKey));
361 if (goalReachedElement && goalReachedElement->hasElement(core::PARAMS_KEY))
362 {
363 auto paramsDict = aron::data::Dict::DynamicCast(
364 goalReachedElement->getElement(core::PARAMS_KEY));
365 if (paramsDict)
366 {
367 auto coreCfg = core::GoalReachedConfig::FromAron(paramsDict);
368 goalReachedCfg.posTh = coreCfg.posTh;
369 goalReachedCfg.oriTh = coreCfg.oriTh;
370 goalReachedCfg.linearVelTh = coreCfg.linearVelTh;
371 goalReachedCfg.angularVelTh = coreCfg.angularVelTh;
372 goalReachedCfg.filterCount = coreCfg.filterCount;
373 }
374 }
375 }
376 }
377
378 // Read before the moves below: within a braced-init-list the members are initialized
379 // left to right, so `memoryPublisher` is already moved from by the time `.navigator`
380 // is initialized.
381 server::MemoryPublisher* const publisherPtr = memoryPublisher.get();
382
383 // Built outside the lock: constructing the navigator is expensive, and the entry is
384 // not reachable by other threads until it is inserted below.
385 auto entry = std::make_shared<NavigatorEntry>(NavigatorEntry{
386 .publisher = std::move(memoryPublisher),
387 .introspector = std::move(memoryIntrospector),
388 .navigator = server::Navigator{
389 server::Navigator::Config{.stack = std::move(stack),
390 .general = params.navigatorGeneralConfig,
391 .goalReachedConfig = goalReachedCfg},
393 .executor = executorPtr,
394 .publisher = publisherPtr,
395 .introspector = introspector.has_value() ? &(introspector.value()) : nullptr,
396 .drawer = introspector.has_value() ? &(introspector.value()) : nullptr,
397 .debugObserverHelper = &getDebugObserverComponentPlugin(),
398 .sceneProvider =
399 sceneProvider.has_value() ? &sceneProvider.value() : nullptr}}});
400
401 // Replaces any previous registration for this caller. The old entry is released after
402 // the lock, so its `~Navigator` (which joins the periodic task) cannot deadlock
403 // against another request waiting for `navigatorsMtx`; and it survives until the last
404 // in-flight request inside it has returned.
405 NavigatorEntryPtr previous;
406 {
407 const std::scoped_lock lock{navigatorsMtx};
408 previous = std::exchange(navigators[callerId], std::move(entry));
409 }
410 previous.reset();
411 }
412
413 void
414 Component::removeConfig(const std::string& callerId, const Ice::Current&)
415 {
416 // Same contract as above: drop the map's reference under the lock, destroy outside it.
418 {
419 const std::scoped_lock lock{navigatorsMtx};
420 if (const auto it = navigators.find(callerId); it != navigators.end())
421 {
422 entry = std::move(it->second);
423 navigators.erase(it);
424 }
425 }
426 entry.reset();
427 }
428
430 Component::entry(const std::string& callerId) const
431 {
432 const std::scoped_lock lock{navigatorsMtx};
433
434 const auto it = navigators.find(callerId);
435 ARMARX_CHECK(it != navigators.end())
436 << "Navigator config for caller " << QUOTED(callerId) << " not registered!";
437
438 return it->second;
439 }
440
441 std::vector<std::pair<std::string, Component::NavigatorEntryPtr>>
443 {
444 const std::scoped_lock lock{navigatorsMtx};
445 return {navigators.begin(), navigators.end()};
446 }
447
448 void
449 Component::moveTo(const std::vector<Eigen::Matrix4f>& waypoints,
450 const std::string& navigationMode,
451 const std::string& callerId,
452 const Ice::Current&)
453 {
455
456 ARMARX_INFO << "moveTo() requested by caller " << QUOTED(callerId)
457 << " with navigation mode `" << navigationMode << "`.";
458 try
459 {
460 entry(callerId)->navigator.moveTo(convert(waypoints),
461 core::NavigationFrameNames.from_name(navigationMode));
462 }
463 catch (...)
464 {
466
467 // TODO: Error handling.
468 ARMARX_WARNING << "Failed to execute moveTo()."
469 << "Movement will be paused.";
470 stopAll(); // TODO pause movement must not throw
471 throw;
472 }
473 }
474
475 void
476 Component::updateMoveTo(const std::vector<Eigen::Matrix4f>& waypoints,
477 const std::string& navigationMode,
478 const std::string& callerId,
479 const Ice::Current& /*c*/)
480 {
482
483 ARMARX_INFO << "updateMoveTo() requested by caller " << QUOTED(callerId);
484 const auto checkIsActiveNavigator = [&](const std::string& callerId)
485 {
486 const std::optional<std::string> activeNavigatorCallerId = activeNavigatorId();
487 if (not activeNavigatorCallerId.has_value())
488 {
489 ARMARX_VERBOSE << "No navigator is active.";
490 return false;
491 }
492
493 return activeNavigatorCallerId == callerId;
494 };
495
496 ARMARX_CHECK(checkIsActiveNavigator(callerId))
497 << "The navigator with id " << QUOTED(callerId) << " is not active!";
498
499 entry(callerId)->navigator.update(convert(waypoints),
500 core::NavigationFrameNames.from_name(navigationMode));
501 }
502
503 void
505 const std::string& navigationMode,
506 const std::string& callerId,
507 const Ice::Current& c)
508 {
510
511 ARMARX_IMPORTANT << "moveTo2 requested by caller " << QUOTED(callerId);
512
513 const std::vector<client::WaypointTarget> wps = client::defrost(waypoints);
514
515 entry(callerId)->navigator.moveTo(wps, core::NavigationFrameNames.from_name(navigationMode));
516 }
517
518 void
520 const std::string& navigationMode,
521 const std::string& callerId,
522 const Ice::Current& c)
523 {
525
526 ARMARX_INFO << "moveToAlternatives() requested by caller " << QUOTED(callerId)
527 << " with navigation mode `" << navigationMode << "`.";
528 const std::vector<core::TargetAlternative> alts = client::defrost(targets);
529
530 try
531 {
532 entry(callerId)->navigator.moveToAlternatives(
533 alts, core::NavigationFrameNames.from_name(navigationMode));
534 }
535 catch (...)
536 {
538
539 // TODO: Error handling.
540 ARMARX_WARNING << "Failed to execute moveTo()."
541 << "Movement will be paused.";
542 stopAll(); // TODO pause movement must not throw
543 throw;
544 }
545 }
546
547 void
549 const IceUtil::Optional<std::string>& providerNameIce,
550 const std::string& callerId,
551 const Ice::Current& c)
552 {
554 ARMARX_INFO << "MoveToLocation " << QUOTED(location) << " requested by caller '" << callerId
555 << "'";
556
557 std::optional<std::string> providerName;
558 if (providerNameIce)
559 {
560 providerName = providerNameIce.value();
561 }
562
563 entry(callerId)->navigator.moveToLocation(location, providerName);
564 }
565
566 void
567 Component::moveTowards(const Eigen::Vector3f& direction,
568 const std::string& navigationMode,
569 const std::string& callerId,
570 const Ice::Current&)
571 {
572 // TODO: Error handling.
574 ARMARX_INFO << "MoveTowards requested by caller " << QUOTED(callerId);
575
576 entry(callerId)->navigator.moveTowards(
577 direction, core::NavigationFrameNames.from_name(navigationMode));
578 }
579
580 void
581 Component::setVelocityFactor(float velocityFactor,
582 const std::string& callerId,
583 const Ice::Current&)
584 {
586 entry(callerId)->navigator.setVelocityFactor(velocityFactor);
587 }
588
589 void
590 Component::pause(const std::string& configId, const Ice::Current&)
591 {
592 entry(configId)->navigator.pause();
593 }
594
595 void
596 Component::resume(const std::string& configId, const Ice::Current&)
597 {
599 entry(configId)->navigator.resume();
600 }
601
602 void
603 Component::stop(const std::string& configId, const Ice::Current&)
604 {
605 // FIXME make sure that event is emitted
607
608 // One lookup for both: the reference keeps the publisher alive across the stop.
609 const NavigatorEntryPtr e = entry(configId);
610 e->navigator.stop();
611
612 // emit UserAbortTriggered event
614 core::Pose(scene().robot->getGlobalPose())};
615 e->publisher->userAbortTriggered(event);
616 }
617
618 void
619 Component::stopAll(const Ice::Current&)
620 {
621 stopAllImpl(true);
622 }
623
624 void
625 Component::stopAllImpl(const bool emitMemoryEvent)
626 {
627 ARMARX_IMPORTANT << "stopAll()";
628
630 const auto entries = allEntries();
631
632 for (const auto& [_, e] : entries)
633 {
634 e->navigator.stop();
635 }
636
637 if (emitMemoryEvent)
638 {
639 ARMARX_INFO << "Trying to emit memory event `UserAbortTriggered`";
640 // emit UserAbortTriggered event
642 core::Pose(scene().robot->getGlobalPose())};
643
644 // This call might fail if the component is already disconnected from the NavigationMemory in onDisconnectComponent.
645 for (const auto& [callerId, e] : entries)
646 {
647 e->publisher->userAbortTriggered(event);
648 }
649 }
650 }
651
652 bool
653 Component::isPaused(const std::string& configId, const Ice::Current&)
654 {
656 return entry(configId)->navigator.isPaused();
657 }
658
659 const core::Scene&
661 {
662 ARMARX_CHECK_NOT_NULL(sceneProvider);
663 return sceneProvider->scene();
664 }
665
666 bool
667 Component::isStopped(const std::string& configId, const Ice::Current&)
668 {
670 return entry(configId)->navigator.isStopped();
671 }
672
675 {
677
679
680 // Publish to a topic (passing the TopicListenerPrx).
681 // def->topic(myTopicListener);
682
683 // Subscribe to a topic (passing the topic name).
684 // def->topic<PlatformUnitListener>("MyTopic");
685
686 // Add a required property.
687 // def->required(properties.boxLayerName, "p.box.LayerName", "Name of the box layer in ArViz.");
688
689 // Add an optionalproperty.
690 def->optional(params.occupiedGridThreshold,
691 "p.occupancy_grid.occopied_threshold",
692 "Threshold for each cell to be considered occupied. Increase this value to "
693 "reduce noise.");
694
695 def->optional(params.disableExecutor,
696 "p.disableExecutor",
697 "If the executor is disabled, the navigator will only plan the trajectory "
698 "but won't execute it.");
699
700 def->required(params.sceneCfg.robotName, "p.scene.robotName");
701 def->optional(params.sceneCfg.staticCostmapProviderName,
702 "p.scene.staticCostmapProviderName");
703 def->optional(params.sceneCfg.staticCostmapName, "p.scene.staticCostmapName");
704 def->optional(params.sceneCfg.costmap3dProviderName, "p.scene.costmap3dProviderName");
705 def->optional(params.sceneCfg.costmap3dName, "p.scene.costmap3dName");
706 def->optional(params.sceneCfg.humanProviderName, "p.scene.humanProviderName");
707 def->optional(params.sceneCfg.laserScannerFeaturesProviderName,
708 "p.scene.laserScannerFeaturesProviderName");
709
710 def->optional(params.rtUnitDynamicallyLoadLibraries,
711 "p.rtUnitDynamicallyLoadLibraries",
712 "If enabled, the controller library will automatically be loaded in the "
713 "RobotUnit. If disabled (desired), you have to make sure that the controller "
714 "library is listed in the RobotUnit's property `LoadLibraries`");
715
716 def->optional(params.emergencyStopMasterName,
717 "p.navigator.emergencyStopMasterName",
718 "Name of the emergency stop master. While it reports the emergency stop "
719 "engaged, the trajectory controllers are not (re-)activated. Empty disables "
720 "the check, as does an unresolvable name.");
721
722
723 def->optional(params.navigatorGeneralConfig.tasks.replanningUpdatePeriod,
724 "p.navigator.general.replanningPeriod");
725
726 def->optional(params.navigatorGeneralConfig.platform,
727 "p.navigator.general.platform",
728 "Which platform's drive parameters the TOPP-RA parametrization uses: the "
729 "suffix selecting config/platform/PlatformDynamics<Platform>.json in the "
730 "armarx_navigation package: Armar7, Armar6 or ArmarDE.");
731 def->optional(params.navigatorGeneralConfig.platformDynamicsEnabled,
732 "p.navigator.general.platformDynamicsEnabled",
733 "Whether to read drive parameters at all. False makes TOPP-RA unavailable, "
734 "so the stack falls back to ramping.");
735
736 def->optional(params.navigatorGeneralConfig.parametrizationDump,
737 "p.navigator.general.parametrizationDump",
738 "Write a record of every parametrized navigation request, for offline "
739 "analysis with `plot-navigation-request`.");
740 def->optional(params.navigatorGeneralConfig.parametrizationDumpPath,
741 "p.navigator.general.parametrizationDumpPath",
742 "Where that record is written. A timestamped copy is written alongside it.");
743
744 def->optional(
745 params.navigatorGeneralConfig.subdivision.enable,
746 "p.navigator.general.subdivision.enable",
747 "Whether to enable global path subdivision when local planner is enabled as well.");
748 def->optional(params.navigatorGeneralConfig.subdivision.localPlannerCostmapThreshold,
749 "p.navigator.general.subdivision.localPlannerCostmapThreshold",
750 "The minimum value in the costmap to enable local planning.");
751 def->optional(
752 params.navigatorGeneralConfig.subdivision.globalPlanExpansionDistance,
753 "p.navigator.general.subdivision.globalPlanExpansionDistance",
754 "The length by which global planner segments are expaned (in both directions).");
755 def->optional(params.navigatorGeneralConfig.subdivision.minSegmentDistance,
756 "p.navigator.general.subdivision.minSegmentDistance",
757 "The minimum length for a local planner segment (otherwise it is deleted and "
758 "joined with the neighboring global planner segments).");
759
760 def->optional(params.navigatorGeneralConfig.targetAlternativesFilterTimeSeconds,
761 "p.navigator.general.targetAlternativesFilterTimeSeconds",
762 "The number of seconds to wait before replanning alternatives after all "
763 "alternatives where impossible.");
764
765 def->optional(params.navigatorGoalReachedConfig.posTh, "p.navigator.goalReached.posTh");
766 def->optional(params.navigatorGoalReachedConfig.oriTh, "p.navigator.goalReached.oriTh");
767 def->optional(params.navigatorGoalReachedConfig.linearVelTh,
768 "p.navigator.goalReached.linearVelTh");
769 def->optional(params.navigatorGoalReachedConfig.angularVelTh,
770 "p.navigator.goalReached.angularVelTh");
771 def->optional(params.navigatorGoalReachedConfig.filterCount,
772 "p.navigator.goalReached.filterCount");
773
774 return def;
775 }
776
777 void
778 visualize(const algorithms::Costmap& costmap, viz::Client& arviz, const std::string& name)
779 {
780 const auto cmap = simox::color::cmaps::viridis();
781 const float vmax = costmap.getGrid().array().maxCoeff();
782
783 const auto asColor = [&cmap, &vmax](const float distance) -> viz::data::Color
784 {
785 const auto color = cmap.at(distance, 0.F, vmax);
786 return {color.a, color.r, color.g, color.b};
787 };
788
789 auto layer = arviz.layer("costmap_" + name);
790
791 const std::int64_t cols = costmap.getGrid().cols();
792 const std::int64_t rows = costmap.getGrid().rows();
793
794 auto mesh = viz::Mesh("");
795
796 std::vector<std::vector<Eigen::Vector3f>> vertices;
797 std::vector<std::vector<viz::data::Color>> colors;
798
799 for (int r = 0; r < rows; r++)
800 {
801 auto& verticesRow = vertices.emplace_back(cols);
802 auto& colorsRow = colors.emplace_back(cols);
803
804 for (int c = 0; c < cols; c++)
805 {
806 verticesRow.at(c) = conv::to3D(costmap.toPositionGlobal({r, c}));
807 colorsRow.at(c) = asColor(costmap.getGrid()(r, c));
808 }
809 }
810
811 mesh.grid2D(vertices, colors);
812
813 layer.add(mesh);
814
815 arviz.commit(layer);
816 }
817
820 {
821 const auto isActive = [](const auto& nameNavPair) -> bool
822 { return not nameNavPair.second->navigator.isPaused(); };
823
824 // Found and returned from one snapshot: looking the id up again could race with a
825 // `removeConfig` and throw where this contract is to return null.
826 const auto entries = allEntries();
827 const auto it = std::find_if(entries.begin(), entries.end(), isActive);
828
829 return it == entries.end() ? nullptr : it->second;
830 }
831
832 std::optional<std::string>
834 {
836 // We define the active navigator to be the one whose movement is enabled.
837 const auto isActive = [](const auto& nameNavPair) -> bool
838 { return not nameNavPair.second->navigator.isPaused(); };
839
840 const auto entries = allEntries();
841 const auto it = std::find_if(entries.begin(), entries.end(), isActive);
842
843 // no navigator active?
844 if (it == entries.end())
845 {
846 return std::nullopt;
847 }
848
849 return it->first;
850 }
851
852 void
854 {
855 using namespace armarx::RemoteGui::Client;
856
857 VBoxLayout root;
858
859 tab.stopAll.setLabel("Stop All");
860
861 root.addChild(tab.stopAll);
862
863 RemoteGui_createTab(getName(), root, &tab);
864 }
865
866 void
868 {
869 if (tab.stopAll.wasClicked())
870 {
871 stopAll();
872 }
873 }
874
875} // namespace armarx::navigation::components::navigator
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
Definition Decoupled.h:29
#define QUOTED(x)
constexpr T c
armarx::viz::Client & getArvizClient()
static DateTime Now()
Current time on the virtual clock.
Definition Clock.cpp:93
Default component property definition container.
Definition Component.h:70
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Definition Component.cpp:88
plugins::DebugObserverComponentPlugin & getDebugObserverComponentPlugin()
bool usingProxy(const std::string &name, const std::string &endpoints="")
Registers a proxy for retrieval after initialization and adds it to the dependency list.
PluginT * addPlugin(const std::string prefix="", ParamsT &&... params)
std::string getName() const
Retrieve name of object.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
void setLogObjectDiscoveryError(bool logEnabled)
objpose::ObjectPoseClient getClient() const
bool hasElement(const std::string &) const
Definition Dict.cpp:229
VariantPtr getElement(const std::string &) const
Definition Dict.cpp:235
Position toPositionGlobal(const Index &index) const
Definition Costmap.cpp:75
void moveToLocation(const std::string &location, const IceUtil::Optional< std::string > &providerName, const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
void removeConfig(const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
void pause(const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
void resume(const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
void setVelocityFactor(float velocityFactor, const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
std::optional< std::string > activeNavigatorId() const
void moveToAlternatives(const client::detail::TargetAlternatives &targets, const std::string &navigationMode, const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
void RemoteGui_update() override
After calling RemoteGui_startRunningTask, this function is called periodically in a separate thread.
bool isPaused(const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
bool isStopped(const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
PropertyDefinitionsPtr createPropertyDefinitions() override
void updateMoveTo(const std::vector< Eigen::Matrix4f > &waypoints, const std::string &navigationMode, const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
std::vector< std::pair< std::string, NavigatorEntryPtr > > allEntries() const
A snapshot of every registered entry, each held alive by the returned references.
NavigatorEntryPtr entry(const std::string &callerId) const
The entry for callerId, throwing if it is not registered.
std::shared_ptr< NavigatorEntry > NavigatorEntryPtr
Definition Component.h:214
void createConfig(const aron::data::dto::DictPtr &stackConfig, const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
void stop(const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
void moveTo(const std::vector< Eigen::Matrix4f > &waypoints, const std::string &navigationMode, const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
void moveTowards(const Eigen::Vector3f &direction, const std::string &navigationMode, const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
void moveTo2(const client::detail::Waypoints &waypoints, const std::string &navigationMode, const std::string &callerId, const Ice::Current &c=Ice::emptyCurrent) override
void createRemoteGuiTab()
This function should be called once in onConnect() or when you need to re-create the Remote GUI tab.
static server::NavigationStack create(const aron::data::DictPtr &params, const core::Scene &scene, std::experimental::observer_ptr< viz::Client > arviz, std::experimental::observer_ptr< DebugObserverComponentPluginUser > debugObserver)
An executer the server navigator will use to send its control commands to.
Brief description of class targets.
Definition targets.h:39
virtual Layer layer(std::string const &name) const
Definition Client.cpp:80
CommitResult commit(StagedCommit const &commit)
Definition Client.cpp:89
#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_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
::IceInternal::Handle< Dict > DictPtr
sequence< TargetAlternative > TargetAlternatives
client::GlobalPlanningStrategy defrost(const client::detail::GlobalPlanningStrategy &strategy)
void visualize(const algorithms::Costmap &costmap, viz::Client &arviz, const std::string &name)
std::vector< Eigen::Vector3f > to3D(const std::vector< Eigen::Vector2f > &v)
Definition eigen.cpp:14
const std::string PARAMS_KEY
Definition constants.h:34
Eigen::Isometry3f Pose
Definition basic_types.h:31
const simox::meta::EnumNames< StackLayer > StackLayerNames
Definition constants.h:46
const simox::meta::EnumNames< NavigationFrame > NavigationFrameNames
Definition types.h:54
This file is part of ArmarX.
Definition constants.cpp:4
core::GoalReachedConfig GoalReachedMonitorConfig
This file is part of ArmarX.
std::vector< core::Pose > convert(const std::vector< Eigen::Matrix4f > &wps)
Definition Component.cpp:93
std::string GetHandledExceptionString()
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
observer_ptr< _Tp > make_observer(_Tp *__p) noexcept
double distance(const Point &a, const Point &b)
Definition point.hpp:95
void RemoteGui_createTab(std::string const &name, RemoteGui::Client::Widget const &rootWidget, RemoteGui::Client::Tab *tab)
void addChild(Widget const &child)
Definition Widgets.cpp:95
Everything registered for one callerId, kept alive as one unit.
Definition Component.h:208
static GoalReachedConfig FromAron(const aron::data::DictPtr &dict)
Event describing that the user aborted the current execution.
Definition events.h:97
local_planning::LocalPlannerPtr localPlanner
#define ARMARX_TRACE
Definition trace.h:75