54 const Ice::Current& iceCurrent = Ice::emptyCurrent)
override;
71 std::map<common::mp::arondto::MPGroup, bool> groupDeviationFlag_;
72 void updateNonRTTiming();
73 std::map<std::string, bool> manageMPStopsAndGuards();
81 template <
typename TSControllerType,
typename MPInterfaceType>
84 const NJointControllerConfigPtr& config,
89 data.canonicalValue = 1.0;
93 template <
typename TSControllerType,
typename MPInterfaceType>
97 TSControllerType::rtPreActivateController();
99 if (not
isFinished(
"all") and (not this->rtGetDesiredPoseSafeStatusOnActivation() or
100 not this->rtGetDesiredPoseSafeStatus()))
102 ARMARX_WARNING <<
"Your MPs are not terminated before controller de-/re-activation, "
103 "and the controller is not in a safe status regarding desried pose. "
104 "either your MP has an improper desired pose, or "
105 "you interruped the controller with a different controller. "
106 "No worry, this is just a warning. I will terminate all running MPs.";
111 template <
typename TSControllerType,
typename MPInterfaceType>
118 TSControllerType::onPublish(sac, interface, debugObs);
122 datafields[
"canonicalValue"] =
new Variant(
data.canonicalValue);
124 auto& desiredPoses =
data.desiredPose;
125 for (
const auto& [name, pose] : desiredPoses)
129 debugObs->setDebugChannel(
"MP", datafields);
132 template <
typename TSControllerType,
typename MPInterfaceType>
135 const ::armarx::aron::data::dto::DictPtr& dto,
136 const Ice::Current& )
141 <<
"All running MPs will be terminated. This is only a temporal solution, most "
142 "likely your previous mp get into a un-safe status and in your high-level "
143 "application, you are not checking and using these status. A proper way to "
144 "terminate the mps is to get the ctrl proxy and call requestStop('all'). In "
145 "theory, controller should not handle this, but to save your time now, I will "
146 "force to remove the existing mp regardless and create new MPs on your request";
154 if (
resetMPsV1(dto, this->controllableNodeSets, this->coordinator))
156 for (
auto& [_, arm] : this->limb)
158 arm->rtFirstRun.store(
true);
162 const std::scoped_lock lock(
mtx_mps);
164 buffer.desiredPose.clear();
166 for (
const auto&
mp :
mps)
168 if (
mp.second.mp->getRole() ==
"taskspace")
170 buffer.desiredPose.emplace(
mp.second.mp->getNodeSetName(),
171 Eigen::Matrix4f::Identity());
172 ARMARX_VERBOSE <<
"reset mp debug message: " <<
mp.second.mp->getNodeSetName()
180 template <
typename TSControllerType,
typename MPInterfaceType>
184 const std::lock_guard<std::recursive_mutex> lock(
mtx_mps);
187 auto [rtTargetSafe, ftSafe] = this->additionalTaskUpdateStatus();
188 if (this->coordinator)
190 this->coordinator->updateNonRt();
195 this->updateNonRTTiming();
198 std::map<std::string, bool> mpRunningStatus = this->manageMPStopsAndGuards();
203 if (mpRunningStatus[
mp.second.mp->getMPName()] && !
mp.second.mp->isFinished())
205 this->updateMPInputs(
mp.second);
212 this->handleRTNotSafeInNonRT();
221 groupDeviationFlag_.clear();
222 for (
auto& mpWrapper :
mps)
224 auto& mpData = mpWrapper.second;
227 if (mpRunningStatus[mpData.mp->getMPName()])
229 this->processGroupSafety(mpData, buffer);
233 for (
auto& mpWrapper :
mps)
235 auto& mpData = mpWrapper.second;
238 if (mpRunningStatus[mpData.mp->getMPName()])
240 this->processMPOutput(mpData, buffer, rtTargetSafe);
245 if (this->coordinator)
247 this->coordinator->commitNonRt();
250 this->additionalTaskSetTarget();
254 template <
typename TSControllerType,
typename MPInterfaceType>
256 TSMPController<TSControllerType, MPInterfaceType>::updateNonRTTiming()
258 for (
auto& [name, arm] : this->limb)
260 arm->nonRTDeltaT = arm->rtStatusInNonRT.accumulateTime - arm->nonRTAccumulateTime;
261 arm->nonRTAccumulateTime = arm->rtStatusInNonRT.accumulateTime;
265 for (
auto& [_,
hand] : this->hands->hands)
267 hand->nonRTDeltaT =
hand->rtsInNonRT.accumulateTime -
hand->nonRTAccumulateTime;
268 hand->nonRTAccumulateTime =
hand->rtsInNonRT.accumulateTime;
273 template <
typename TSControllerType,
typename MPInterfaceType>
274 std::map<std::string, bool>
275 TSMPController<TSControllerType, MPInterfaceType>::manageMPStopsAndGuards()
277 std::map<std::string, bool> mpRunning;
280 std::map<std::string, bool> limbStopFlags;
281 for (
auto& [name, arm] : this->limb)
284 limbStopFlags[name] = not arm->controller.ftsensor.ftSafe.load();
287 for (
auto& mpWrapper : mps)
289 auto&
mp = mpWrapper.second.mp;
290 const auto mpName =
mp->getMPName();
291 const auto nodeSet =
mp->getNodeSetName();
293 mpRunning[mpName] =
mp->isRunning();
296 if (
mp->isStopRequested())
299 ARMARX_INFO <<
"user requested to stop mp execution at canonical value: "
300 <<
mp->getCanonicalValue();
305 bool forceGuardEnabled =
false;
306 bool torqueGuardEnabled =
false;
307 for (
auto& ftGuard : mpConfig.ftGuard)
309 if (ftGuard.mpName == mpName)
311 if (ftGuard.force.has_value() &&
312 ftGuard.force.value() >=
mp->getCanonicalValue())
314 forceGuardEnabled =
true;
316 if (ftGuard.torque.has_value() &&
317 ftGuard.torque.value() >=
mp->getCanonicalValue())
319 torqueGuardEnabled =
true;
325 bool globalFtUnsafe = (limbStopFlags.count(nodeSet) && limbStopFlags.at(nodeSet));
327 if (globalFtUnsafe &&
mp->isRunning() && !
mp->isFirstRun() &&
328 ((forceGuardEnabled &&
329 this->limb.at(nodeSet)->controller.ftsensor.isForceGuardEnabled()) ||
330 (torqueGuardEnabled &&
331 this->limb.at(nodeSet)->controller.ftsensor.isTorqueGuardEnabled())))
334 ARMARX_INFO <<
"Due to force/torque safe guard, MP " << mpName <<
" is stopped at "
335 <<
mp->getCanonicalValue();
337 if (this->coordinatorEnabled)
339 for (
auto& mpWrapper2 : mps)
341 auto& mp2 = mpWrapper2.second.mp;
343 <<
" as coordination is enabled";
348 for (
auto& mpWrapper2 : mps)
350 auto& mp2 = mpWrapper2.second.mp;
351 if (
mp->getGroup() == mp2->getGroup())
354 ARMARX_INFO <<
"Stopped MP " << mp2->getMPName() <<
" part of MP group "
355 <<
mp->getGroupName();
364 template <
typename TSControllerType,
typename MPInterfaceType>
366 TSMPController<TSControllerType, MPInterfaceType>::updateMPInputs(
369 auto&
mp = mpData.mp;
370 const std::string& role =
mp->getRole();
371 const std::string& nodeSet =
mp->getNodeSetName();
374 if (role ==
"taskspace")
376 auto& arm = this->limb.at(nodeSet);
379 if (
mp->isFirstRun())
382 const std::vector<double> mpStart =
mp->getStartVec();
386 arm->rtStatusInNonRT.currentPose,
389 "initial start pose",
390 arm->nonRtConfig.safeDistanceMMToGoal,
391 arm->nonRtConfig.safeRotAngleDegreeToGoal,
392 "Additional task for task space MPs: " +
mp->getMPName() +
393 " detects that the ");
395 if (
mp->getStartFromPrevTarget() or deviation)
398 arm->rtStatusInNonRT.currentPose,
399 arm->rtStatusInNonRT.desiredPose,
402 arm->nonRtConfig.safeDistanceMMToGoal,
403 arm->nonRtConfig.safeRotAngleDegreeToGoal,
404 "Additional task for task space MPs: " +
mp->getMPName() +
405 " detects that the ");
407 if (
mp->getStartFromPrevTarget() and not deviation2)
411 ARMARX_INFO <<
"User requested to start the current TS MP for " << nodeSet
412 <<
" with previous target pose:\n"
414 mp->validateInitialState(desiredPoseVec);
421 <<
"Deviation from current pose too large, reset TS MP for " << nodeSet
423 mp->validateInitialState(currentPoseVec);
430 std::dynamic_pointer_cast<common::mp::TSMPInput>(mpData.input);
431 in->pose = arm->rtStatusInNonRT.currentPose;
432 in->vel = arm->rtStatusInNonRT.currentTwist;
433 in->deltaT = arm->nonRTDeltaT;
437 if (role ==
"nullspace")
439 auto& arm = this->limb.at(nodeSet);
441 std::dynamic_pointer_cast<common::mp::JSMPInput>(mpData.input);
443 arm->rtStatusInNonRT.jointPosition.size());
444 in->angleRadian = arm->rtStatusInNonRT.jointPosition;
445 in->angularVel = arm->rtStatusInNonRT.qvelFiltered;
446 in->deltaT = arm->nonRTDeltaT;
452 auto&
hand = this->hands->hands.at(nodeSet);
454 std::dynamic_pointer_cast<common::mp::JSMPInput>(mpData.input);
455 if (
hand->targetNonRT.jointPosition.has_value())
457 in->angleRadian =
hand->targetNonRT.jointPosition.value();
458 in->deltaT =
hand->nonRTDeltaT;
464 if (role ==
"object")
466 if (not this->coordinator)
469 <<
"when using the object for MP, the coordinator must be first instantiated";
472 const std::scoped_lock lock_vo_non_rt(this->coordinator->mtx_data_non_rt);
474 std::dynamic_pointer_cast<common::mp::TSMPInput>(mpData.input);
475 in->pose = this->coordinator->dataNonRt.currentPose;
476 in->vel = this->coordinator->dataNonRt.currentVel;
477 in->deltaT = this->coordinator->dataNonRt.deltaT;
484 template <
typename TSControllerType,
typename MPInterfaceType>
486 TSMPController<TSControllerType, MPInterfaceType>::processGroupSafety(
490 auto&
mp = mpData.mp;
494 for (
auto& ftGuard : mpConfig.ftGuard)
496 if (ftGuard.mpName ==
mp->getMPName())
498 bool const forceGuard =
499 (ftGuard.force.has_value() && ftGuard.force.value() >=
mp->getCanonicalValue());
500 bool const torqueGuard = (ftGuard.torque.has_value() &&
501 ftGuard.torque.value() >=
mp->getCanonicalValue());
503 auto& arm = this->limb.at(
mp->getNodeSetName());
505 bool const resetForce =
506 not arm->controller.ftsensor.isForceGuardEnabled() and forceGuard;
507 bool const resetTorque =
508 not arm->controller.ftsensor.isTorqueGuardEnabled() and torqueGuard;
509 if (resetForce or resetTorque)
511 ARMARX_INFO <<
"Triggering force torque safety guard for "
512 << arm->kinematicChainName <<
" at can value "
513 <<
mp->getCanonicalValue();
516 arm->nonRtConfig.ftConfig.enableSafeGuardForce = forceGuard;
517 arm->nonRtConfig.ftConfig.enableSafeGuardTorque = torqueGuard;
518 arm->controller.ftsensor.enableSafeGuard(resetForce, resetTorque);
525 const std::string& role =
mp->getRole();
526 const std::string& nodeSetName =
mp->getNodeSetName();
528 if (role ==
"taskspace")
530 buffer.canonicalValue =
mp->getCanonicalValue();
531 auto& arm = this->limb.at(nodeSetName);
532 auto out = std::dynamic_pointer_cast<common::mp::TSMPOutput>(mpData.output);
535 arm->rtStatusInNonRT.currentPose,
539 arm->nonRtConfig.safeDistanceMMToGoal,
540 arm->nonRtConfig.safeRotAngleDegreeToGoal,
541 "Additional task for task space MPs: " +
mp->getMPName() +
" detects that the ");
542 groupDeviationFlag_.emplace(
mp->getGroup(), flag);
544 arm->nonRtConfig.desiredPose = out->pose;
545 arm->nonRtConfig.desiredTwist = out->vel;
546 buffer.desiredPose.at(nodeSetName) = out->pose;
550 template <
typename TSControllerType,
typename MPInterfaceType>
552 TSMPController<TSControllerType, MPInterfaceType>::processMPOutput(
557 auto&
mp = mpData.mp;
558 bool deviationFlag =
true;
559 if (groupDeviationFlag_.count(
mp->getGroup()))
561 deviationFlag = groupDeviationFlag_.at(
mp->getGroup());
563 const std::string& role =
mp->getRole();
564 const std::string& nodeSetName =
mp->getNodeSetName();
566 if (role ==
"object")
568 buffer.canonicalValue =
mp->getCanonicalValue();
569 if (this->coordinator)
571 auto out = std::dynamic_pointer_cast<common::mp::TSMPOutput>(mpData.output);
572 this->coordinator->cfgInNonRt.desiredPose = out->pose;
575 else if (role ==
"nullspace")
577 auto& arm = this->limb.at(nodeSetName);
578 auto out = std::dynamic_pointer_cast<common::mp::JSMPOutput>(mpData.output);
580 if (not deviationFlag)
582 arm->nonRtConfig.desiredNullspaceJointAngles.value() = out->angleRadian;
585 else if (role ==
"hand")
587 auto&
hand = this->hands->hands.at(nodeSetName);
588 auto out = std::dynamic_pointer_cast<common::mp::JSMPOutput>(mpData.output);
590 out->angleRadian.size());
591 if (not deviationFlag)
593 hand->targetNonRT.jointPosition.value() = out->angleRadian;
609 if (
mp->isFinished())
614 for (
auto& [name, arm] : this->limb)
617 if (!rtTargetSafe || deviationFlag)
619 ARMARX_VERBOSE <<
"-- discard the last MP desired pose, use the existing RT "
621 << arm->kinematicChainName <<
": \n"
622 << arm->rtStatusInNonRT.desiredPose;
623 arm->nonRtConfig.desiredPose = arm->rtStatusInNonRT.desiredPose;
625 arm->bufferConfigUserToNonRt.reinitAllBuffers(arm->nonRtConfig);
629 for (
auto& [name, arm] : this->limb)
631 this->userConfig.limbs.at(name) = arm->nonRtConfig;
637 this->hands->reinitBuffer(this->userConfig.hands);
641 if (this->coordinator)
643 this->coordinator->resetBufferUserCfgAfterMP();