30 #include <SimoxUtility/algorithm/get_map_keys_values.h>
31 #include <SimoxUtility/algorithm/string/string_tools.h>
34 #include <boost/regex.hpp>
49 monitorUpdateHealthTask =
52 defaultMaximumCycleTimeWarn =
54 defaultMaximumCycleTimeErr =
57 const std::vector<std::string> requiredTags =
simox::alg::split(p.requiredTags,
",");
59 tagsPerRequester[
PROPERTY_REQUESTER_ID] = std::set<std::string>(requiredTags.begin(), requiredTags.end());
69 monitorUpdateHealthTask->start();
73 RobotHealth::monitorHealthUpdateTaskClb()
75 const std::scoped_lock lock(updateMutex);
80 for (
auto & e : updateEntries)
83 const std::scoped_lock elock(e.mutex);
95 auto deltaToArrival = now - e.history.back().arrivalTime;
99 if (deltaToArrival > e.maximumCycleTimeErr)
103 if (e.state != HealthError)
108 e.state = HealthError;
111 else if (deltaToArrival > e.maximumCycleTimeWarn)
115 <<
" is running too slow.";
117 e.state = HealthWarning;
127 RobotHealthState overallHealthState = RobotHealthState::HealthOK;
131 for (
auto & e : updateEntries)
134 std::scoped_lock elock(e.mutex);
137 while (e.history.size() > 20)
139 e.history.pop_front();
144 if (e.state == HealthWarning && overallHealthState != HealthError)
146 overallHealthState = RobotHealthState::HealthWarning;
148 else if (e.state == HealthError)
150 overallHealthState = RobotHealthState::HealthError;
155 if (e.state != HealthOK && overallHealthState != HealthError)
157 overallHealthState = RobotHealthState::HealthWarning;
162 if (overallHealthState == HealthError)
167 p.emergencyStopTopicPrx->reportEmergencyStopState(
168 EmergencyStopState::eEmergencyStopActive);
172 p.aggregatedRobotHealthTopicPrx->aggregatedHeartbeat(overallHealthState);
174 reportDebugObserver();
181 monitorUpdateHealthTask->stop();
196 defs->topic(p.emergencyStopTopicPrx,
"EmergencyStop",
197 "The name of the topic over which changes of the emergencyStopState are sent.");
198 defs->topic<RobotHealthInterfacePrx>(p.robotHealthTopicName,
"RobotHealthTopic",
199 "Name of the RobotHealth topic");
201 defs->topic(p.aggregatedRobotHealthTopicPrx,
"AggregatedRobotHealthTopic",
"Name of the AggregatedRobotHealthTopic");
203 defs->optional(p.maximumCycleTimeWarnMS,
"MaximumCycleTimeWarnMS",
204 "Default value of the maximum cycle time for warnings");
205 defs->optional(p.maximumCycleTimeErrMS,
"MaximumCycleTimeErrMS",
206 "Default value of the maximum cycle time for error");
208 defs->optional(p.requiredTags,
"RequiredTags",
"Tags that should be requested.");
213 RobotHealth::UpdateEntry*
214 RobotHealth::findUpdateEntry(
const std::string& name)
218 for (
auto & updateEntrie : updateEntries)
220 if (updateEntrie.name == name)
222 return &updateEntrie;
229 std::pair<bool, RobotHealth::UpdateEntry&>
230 RobotHealth::findOrCreateUpdateEntry(
const std::string& name)
234 for (
auto & updateEntrie : updateEntries)
236 if (updateEntrie.name == name)
238 return {
false, updateEntrie};
243 ARMARX_INFO <<
"registering for heartbeat: '" << name <<
"'";
245 updateEntries.emplace_back(name, defaultMaximumCycleTimeWarn, defaultMaximumCycleTimeErr);
247 return {
true, updateEntries.back()};
254 std::scoped_lock lockU(updateMutex);
256 auto e = findOrCreateUpdateEntry(args.identifier);
259 std::scoped_lock lock(e.second.mutex);
263 ARMARX_INFO <<
"Newly registering component " << args.identifier <<
" for updates.";
270 e.second.tags = args.tags;
272 e.second.description = args.description;
273 e.second.enabled =
true;
274 e.second.state = HealthOK;
275 e.second.history.clear();
278 updateRequiredElements();
283 const core::time::dto::DateTime& referenceTime,
284 const Ice::Current& current)
294 std::scoped_lock lockU(updateMutex);
295 auto*
const entry = findUpdateEntry(identifier);
297 if (entry ==
nullptr)
300 <<
"` was not signed up for heartbeat. Ignoring heartbeat for now...";
306 std::scoped_lock lock(entry->mutex);
308 if (not entry->enabled)
311 <<
"` was not enabled. The heartbeat is ignored... ";
320 fromIce(referenceTime, refTime);
328 std::scoped_lock lock(updateMutex);
332 for (
auto & e : updateEntries)
334 if (e.name == identifier)
336 std::scoped_lock elock(e.mutex);
348 ARMARX_INFO <<
"Component " << identifier <<
" disabled from heartbeat";
352 ARMARX_INFO <<
"Could not unregister component " << identifier <<
". Not found.";
355 updateRequiredElements();
360 const std::vector<std::string>& tags,
361 const Ice::Current& current)
363 std::scoped_lock lock(updateMutex);
366 for(
const auto& tag : tags)
368 tagsPerRequester[requesterIdentifier].insert(tag);
371 updateRequiredElements();
374 std::set<std::string>
375 armarx::RobotHealth::requestedTags()
const
378 std::set<std::string> allRequestedTags;
379 for(
const auto& tgs: simox::alg::get_values(tagsPerRequester))
381 for(
const auto& tag : tgs)
383 allRequestedTags.insert(tag);
386 return allRequestedTags;
392 return std::any_of(searchKeys.begin(), searchKeys.end(), [&
values](
const auto& key){
393 return values.count(key) > 0;
397 void armarx::RobotHealth::updateRequiredElements()
400 const std::set<std::string> allRequestedTags = requestedTags();
402 for (
auto &e : updateEntries) {
407 std::unique_lock lock(e.mutex);
414 << e.name <<
". Enabling it...";
423 const std::vector<std::string>& tags,
424 const Ice::Current& current)
426 std::scoped_lock lock(updateMutex);
429 for(
const auto& tag : tags)
431 tagsPerRequester[requesterIdentifier].erase(tag);
434 updateRequiredElements();
440 std::scoped_lock lock(updateMutex);
447 tagsPerRequester.clear();
454 std::scoped_lock lock(updateMutex);
464 for (
const auto& e : updateEntries)
466 RobotHealthInfoEntry healthEntry;
468 for (
size_t i = 1; i < e.history.size(); i++)
470 auto later = e.history[i];
471 auto pre = e.history[i - 1];
473 auto delta = later.arrivalTime - pre.arrivalTime;
475 if (minDelta > delta)
480 if (maxDelta < delta)
493 healthEntry.identifier = e.name;
494 healthEntry.state = e.state;
495 healthEntry.enabled = e.enabled;
496 healthEntry.required = e.required;
497 toIce(healthEntry.minDelta, minDelta);
498 toIce(healthEntry.maxDelta,maxDelta);
499 toIce(healthEntry.lastReferenceTimestamp, lastReferenceTime);
500 toIce(healthEntry.timeSinceLastArrival, timeSinceLastUpdateArrival);
501 toIce(healthEntry.timeSyncDelayAndIce, timeSyncDelayAndIce);
502 toIce(healthEntry.timeSinceLastUpdateReference, timeSinceLastUpdateReference);
503 toIce(healthEntry.maximumCycleTimeWarning, e.maximumCycleTimeWarn);
504 toIce(healthEntry.maximumCycleTimeError, e.maximumCycleTimeErr);
505 healthEntry.tags = e.tags;
507 ret.entries[e.name] = healthEntry;
510 const auto tags = requestedTags();
511 ret.activeTags = std::vector<std::string>(tags.begin(), tags.end());
519 return p.robotHealthTopicName;
523 RobotHealth::reportDebugObserver()
525 for (
const auto& entry : updateEntries)
527 if (entry.history.size() > 1)
529 auto later = entry.history[entry.history.size() - 1];
530 auto pre = entry.history[entry.history.size() - 2];
531 const Duration delta = later.arrivalTime - pre.arrivalTime;
533 const Duration timeSinceLastArrival =
Clock::Now() - entry.history.back().arrivalTime;
534 const Duration timeToLastReference =
Clock::Now() - entry.history.back().referenceTime;
535 const Duration timeSyncDelay = entry.history.back().arrivalTime - entry.history.back().referenceTime;
546 entry.maximumCycleTimeWarn.toMilliSecondsDouble());
548 entry.maximumCycleTimeErr.toMilliSecondsDouble());