57 const std::string Component::defaultName =
"navigation_evaluator";
63 std::random_device rd;
64 randomGenerator.seed(rd());
73 def->component(manager,
"SkillMemory");
75 def->optional(properties.roomsProviderName,
76 "p.roomsProviderName",
77 "Provider segment name for rooms in the navigation memory. "
78 "Leave empty to query all providers.");
80 def->optional(properties.skillProviderName,
81 "p.skillProviderName",
82 "Name of the skill provider that offers NavigateTo.");
84 def->optional(properties.failureTimeoutSeconds,
85 "p.failureTimeoutSeconds",
86 "Failures within this time [s] after skill start are tolerated; "
87 "later failures stop the evaluation.");
110 navigateToSkillProxy =
111 std::make_unique<armarx::skills::SpecializedSkillProxy<skills::arondto::NavigateToParams>>(
112 manager, navigateToSkillId);
114 catch (
const std::exception& e)
116 ARMARX_ERROR <<
"Failed to create NavigateTo skill proxy: " << e.what();
124 evaluationTask->start();
130 stopRequested.store(
true, std::memory_order_release);
134 evaluationTask->stop(
true);
137 navigateToSkillProxy.reset();
148 return Component::defaultName;
154 return Component::defaultName;
162 tab.refreshRoomsButton.setLabel(
"Refresh Rooms");
163 tab.roomSelector.setValue(
"");
164 tab.availableRoomsLabel.setText(
"Available rooms: <click Refresh>");
165 tab.algorithmSelector.setOptions({
"SPFA",
"AStar",
"AStarWithOrientation",
"Point2Point"});
166 tab.algorithmSelector.setValue(
"SPFA");
167 tab.startButton.setLabel(
"Start");
168 tab.stopButton.setLabel(
"Stop");
169 tab.successCounter.setText(
"Successful: 0");
170 tab.totalCounter.setText(
"Total: 0");
171 tab.failureCounter.setText(
"Failed: 0");
172 tab.statusLabel.setText(
"Status: stopped");
177 grid.
add(
Label(
"Room"), {row, 0}).add(tab.roomSelector, {row, 1});
179 grid.
add(tab.refreshRoomsButton, {row, 0}, {1, 2});
181 grid.
add(tab.availableRoomsLabel, {row, 0}, {1, 2});
184 grid.
add(
Label(
"Algorithm"), {row, 0}).add(tab.algorithmSelector, {row, 1});
187 grid.
add(tab.startButton, {row, 0}).
add(tab.stopButton, {row, 1});
190 grid.
add(tab.statusLabel, {row, 0}, {1, 2});
192 grid.
add(tab.successCounter, {row, 0}, {1, 2});
194 grid.
add(tab.totalCounter, {row, 0}, {1, 2});
196 grid.
add(tab.failureCounter, {row, 0}, {1, 2});
206 if (tab.refreshRoomsButton.wasClicked())
208 const auto rooms = queryRooms();
209 std::vector<std::string> roomNames;
210 for (
const auto& room :
rooms)
212 roomNames.push_back(room.name);
215 if (roomNames.empty())
217 tab.availableRoomsLabel.setText(
"Available rooms: <none>");
222 for (std::size_t i = 0; i < roomNames.size(); ++i)
228 joined += roomNames[i];
230 tab.availableRoomsLabel.setText(
"Available rooms: " + joined);
234 if (tab.startButton.wasClicked() && not running.load(std::memory_order_acquire))
236 const std::string roomName = tab.roomSelector.getValue();
237 if (roomName.empty())
239 tab.statusLabel.setText(
"Status: enter a room name");
244 const auto room = findRoom(roomName);
247 tab.statusLabel.setText(
"Status: room '" + roomName +
"' not found");
253 std::lock_guard g{settingsMutex};
254 selectedRoomName = roomName;
255 selectedAlgorithm = algorithmFromString(tab.algorithmSelector.getValue());
258 successCount.store(0, std::memory_order_release);
259 totalAttempts.store(0, std::memory_order_release);
260 failureCount.store(0, std::memory_order_release);
261 stopRequested.store(
false, std::memory_order_release);
262 running.store(
true, std::memory_order_release);
264 tab.statusLabel.setText(
"Status: running");
268 if (tab.stopButton.wasClicked() && running.load(std::memory_order_acquire))
270 stopRequested.store(
true, std::memory_order_release);
273 if (not running.load(std::memory_order_acquire))
275 tab.statusLabel.setText(
"Status: stopped");
282 Component::updateGuiCounters()
284 tab.successCounter.
setText(
"Successful: " + std::to_string(successCount.load(std::memory_order_acquire)));
285 tab.totalCounter.
setText(
"Total: " + std::to_string(totalAttempts.load(std::memory_order_acquire)));
286 tab.failureCounter.
setText(
"Failed: " + std::to_string(failureCount.load(std::memory_order_acquire)));
289 std::vector<algorithms::Room>
290 Component::queryRooms()
const
294 const std::optional<std::string> providerName =
295 properties.roomsProviderName.empty()
297 : std::optional<std::string>{properties.roomsProviderName};
300 << (providerName ?
" for provider '" + *providerName +
"'" :
" (all providers)")
304 .providerName = providerName,
307 const auto result = roomsReaderPlugin->get().query(query);
312 ARMARX_WARNING <<
"Failed to query rooms from provider '" << *providerName
313 <<
"': " << result.errorMessage;
317 ARMARX_WARNING <<
"Failed to query rooms from memory: " << result.errorMessage;
325 std::optional<algorithms::Room>
326 Component::findRoom(
const std::string& name)
const
328 const auto rooms = queryRooms();
329 for (
const auto& room : rooms)
331 if (room.name == name)
339 std::optional<Eigen::Isometry3f>
340 Component::samplePoseInRoom(
const algorithms::Room& room)
const
342 const auto [
min,
max] = room.aabb();
344 std::uniform_real_distribution<float> xDist(
min.x(),
max.x());
345 std::uniform_real_distribution<float> yDist(
min.y(),
max.y());
346 std::uniform_real_distribution<float> angleDist(-
static_cast<float>(
M_PI),
347 static_cast<float>(
M_PI));
349 constexpr std::size_t maxSamples = 1000;
350 for (std::size_t i = 0; i < maxSamples; ++i)
352 const Eigen::Vector2f candidate(xDist(randomGenerator), yDist(randomGenerator));
353 if (room.isInside(candidate))
355 Eigen::Isometry3f pose = Eigen::Isometry3f::Identity();
356 pose.translation() << candidate.x(), candidate.y(), 0.0F;
357 pose.linear() = Eigen::AngleAxisf(angleDist(randomGenerator),
358 Eigen::Vector3f::UnitZ())
364 ARMARX_ERROR <<
"Could not sample a valid position inside room '" << room.name
365 <<
"' after " << maxSamples <<
" attempts.";
369 skills::arondto::GlobalPlanningAlgorithm::ImplEnum
370 Component::algorithmFromString(
const std::string& name)
const
372 using ImplEnum = skills::arondto::GlobalPlanningAlgorithm::ImplEnum;
374 return ImplEnum::AStar;
375 if (name ==
"AStarWithOrientation")
376 return ImplEnum::AStarWithOrientation;
377 if (name ==
"Point2Point")
378 return ImplEnum::Point2Point;
379 return ImplEnum::SPFA;
383 Component::algorithmToString(skills::arondto::GlobalPlanningAlgorithm::ImplEnum algorithm)
const
385 using ImplEnum = skills::arondto::GlobalPlanningAlgorithm::ImplEnum;
388 case ImplEnum::AStar:
390 case ImplEnum::AStarWithOrientation:
391 return "AStarWithOrientation";
392 case ImplEnum::Point2Point:
393 return "Point2Point";
402 Component::executeSingleNavigation(
403 const Eigen::Isometry3f& targetPose,
404 skills::arondto::GlobalPlanningAlgorithm::ImplEnum algorithm)
408 skills::arondto::NavigateToParams params;
409 params.targetPose = targetPose.matrix();
410 params.navigatingSkillParams.globalPlanningAlgorithm = algorithm;
411 params.navigatingSkillParams.enableLocalPlanning =
false;
412 params.navigatingSkillParams.enableSafetyGuard =
true;
414 armarx::skills::TerminatedSkillStatusUpdate finalStatus;
417 finalStatus = navigateToSkillProxy->executeSkill(
getName(), params);
419 catch (
const std::exception& e)
421 ARMARX_ERROR <<
"Synchronous NavigateTo execution failed: " << e.what();
430 ARMARX_INFO <<
"Navigation succeeded after " << elapsed.toSeconds() <<
" s.";
431 successCount.fetch_add(1, std::memory_order_acq_rel);
435 ARMARX_WARNING <<
"Navigation failed after " << elapsed.toSeconds()
436 <<
" s with status " <<
static_cast<int>(finalStatus.
status);
438 return tolerateFailure(elapsed);
442 Component::tolerateFailure(
const armarx::Duration& elapsed)
444 failureCount.fetch_add(1, std::memory_order_acq_rel);
446 const bool tolerable =
451 ARMARX_INFO <<
"Failure occurred within " << properties.failureTimeoutSeconds
453 <<
" s), continuing with next random location.";
457 ARMARX_ERROR <<
"Failure occurred after " << properties.failureTimeoutSeconds
458 <<
" s (elapsed " << elapsed.
toSeconds() <<
" s), stopping evaluation.";
465 while (not evaluationTask->isStopped())
467 if (not running.load(std::memory_order_acquire))
473 std::string roomName;
474 skills::arondto::GlobalPlanningAlgorithm::ImplEnum
algorithm;
476 std::lock_guard g{settingsMutex};
477 roomName = selectedRoomName;
481 const auto room = findRoom(roomName);
484 ARMARX_ERROR <<
"Room '" << roomName <<
"' not found in memory. Stopping.";
485 running.store(
false, std::memory_order_release);
489 const auto targetPose = samplePoseInRoom(*room);
492 ARMARX_ERROR <<
"Failed to sample a pose in room '" << roomName
494 running.store(
false, std::memory_order_release);
498 totalAttempts.fetch_add(1, std::memory_order_acq_rel);
500 const bool continueEvaluation = executeSingleNavigation(*targetPose,
algorithm);
501 if (not continueEvaluation)
503 running.store(
false, std::memory_order_release);