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();
165 ARMARX_INFO <<
" -- Debug message: reset MP debug buffer " <<
mps.size();
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_INFO <<
"reset mp debug message: " <<
mp.second.mp->getNodeSetName()
529 template <
typename TSControllerType,
typename MPInterfaceType>
533 const std::lock_guard<std::recursive_mutex> lock(
mtx_mps);
536 auto [rtTargetSafe, ftSafe] = this->additionalTaskUpdateStatus();
537 if (this->coordinator)
539 this->coordinator->updateNonRt();
544 this->updateNonRTTiming();
547 std::map<std::string, bool> mpRunningStatus = this->manageMPStopsAndGuards();
552 if (mpRunningStatus[
mp.second.mp->getMPName()] && !
mp.second.mp->isFinished())
554 this->updateMPInputs(
mp.second);
561 this->handleRTNotSafeInNonRT();
570 groupDeviationFlag_.clear();
571 for (
auto& mpWrapper :
mps)
573 auto& mpData = mpWrapper.second;
576 if (mpRunningStatus[mpData.mp->getMPName()])
578 this->processGroupSafety(mpData, buffer);
582 for (
auto& mpWrapper :
mps)
584 auto& mpData = mpWrapper.second;
587 if (mpRunningStatus[mpData.mp->getMPName()])
589 this->processMPOutput(mpData, buffer, rtTargetSafe);
594 if (this->coordinator)
596 this->coordinator->commitNonRt();
599 this->additionalTaskSetTarget();
603 template <
typename TSControllerType,
typename MPInterfaceType>
605 TSMPController<TSControllerType, MPInterfaceType>::updateNonRTTiming()
607 for (
auto& [name, arm] : this->limb)
609 arm->nonRTDeltaT = arm->rtStatusInNonRT.accumulateTime - arm->nonRTAccumulateTime;
610 arm->nonRTAccumulateTime = arm->rtStatusInNonRT.accumulateTime;
614 for (
auto& [_,
hand] : this->hands->hands)
616 hand->nonRTDeltaT =
hand->rtsInNonRT.accumulateTime -
hand->nonRTAccumulateTime;
617 hand->nonRTAccumulateTime =
hand->rtsInNonRT.accumulateTime;
622 template <
typename TSControllerType,
typename MPInterfaceType>
623 std::map<std::string, bool>
624 TSMPController<TSControllerType, MPInterfaceType>::manageMPStopsAndGuards()
626 std::map<std::string, bool> mpRunning;
629 std::map<std::string, bool> limbStopFlags;
630 for (
auto& [name, arm] : this->limb)
633 limbStopFlags[name] = not arm->controller.ftsensor.ftSafe.load();
636 for (
auto& mpWrapper : mps)
638 auto&
mp = mpWrapper.second.mp;
639 const auto mpName =
mp->getMPName();
640 const auto nodeSet =
mp->getNodeSetName();
642 mpRunning[mpName] =
mp->isRunning();
645 if (
mp->isStopRequested())
648 ARMARX_INFO <<
"user requested to stop mp execution at canonical value: "
649 <<
mp->getCanonicalValue();
654 bool forceGuardEnabled =
false;
655 bool torqueGuardEnabled =
false;
656 for (
auto& ftGuard : mpConfig.ftGuard)
658 if (ftGuard.mpName == mpName)
660 if (ftGuard.force.has_value() &&
661 ftGuard.force.value() >=
mp->getCanonicalValue())
663 forceGuardEnabled =
true;
665 if (ftGuard.torque.has_value() &&
666 ftGuard.torque.value() >=
mp->getCanonicalValue())
668 torqueGuardEnabled =
true;
674 bool globalFtUnsafe = (limbStopFlags.count(nodeSet) && limbStopFlags.at(nodeSet));
676 if (globalFtUnsafe &&
mp->isRunning() && !
mp->isFirstRun() &&
677 ((forceGuardEnabled &&
678 this->limb.at(nodeSet)->controller.ftsensor.isForceGuardEnabled()) ||
679 (torqueGuardEnabled &&
680 this->limb.at(nodeSet)->controller.ftsensor.isTorqueGuardEnabled())))
683 ARMARX_INFO <<
"Due to force/torque safe guard, MP " << mpName <<
" is stopped at "
684 <<
mp->getCanonicalValue();
686 if (this->coordinatorEnabled)
688 for (
auto& mpWrapper2 : mps)
690 auto& mp2 = mpWrapper2.second.mp;
691 ARMARX_INFO <<
"Stopped MP " << mp2->getMPName() <<
" as coordination is enabled";
696 for (
auto& mpWrapper2 : mps)
698 auto& mp2 = mpWrapper2.second.mp;
699 if (
mp->getGroup() == mp2->getGroup())
702 ARMARX_INFO <<
"Stopped MP " << mp2->getMPName() <<
" part of MP group " <<
mp->getGroupName();
711 template <
typename TSControllerType,
typename MPInterfaceType>
713 TSMPController<TSControllerType, MPInterfaceType>::updateMPInputs(
716 auto&
mp = mpData.mp;
717 const std::string& role =
mp->getRole();
718 const std::string& nodeSet =
mp->getNodeSetName();
721 if (role ==
"taskspace")
723 auto& arm = this->limb.at(nodeSet);
726 if (
mp->isFirstRun())
729 const std::vector<double> mpStart =
mp->getStartVec();
733 arm->rtStatusInNonRT.currentPose,
736 "initial start pose",
737 arm->nonRtConfig.safeDistanceMMToGoal,
738 arm->nonRtConfig.safeRotAngleDegreeToGoal,
739 "Additional task for task space MPs: " +
mp->getMPName() +
740 " detects that the ");
742 if (
mp->getStartFromPrevTarget() or deviation)
744 if (
mp->getStartFromPrevTarget())
746 ARMARX_INFO <<
"User requested to start the current TS MP from the "
747 "previous target pose";
751 ARMARX_INFO <<
"deviation from current pose too large, reset MP start pose";
760 std::dynamic_pointer_cast<common::mp::TSMPInput>(mpData.input);
761 in->pose = arm->rtStatusInNonRT.currentPose;
762 in->vel = arm->rtStatusInNonRT.currentTwist;
763 in->deltaT = arm->nonRTDeltaT;
767 if (role ==
"nullspace")
769 auto& arm = this->limb.at(nodeSet);
771 std::dynamic_pointer_cast<common::mp::JSMPInput>(mpData.input);
773 arm->rtStatusInNonRT.jointPosition.size());
774 in->angleRadian = arm->rtStatusInNonRT.jointPosition;
775 in->angularVel = arm->rtStatusInNonRT.qvelFiltered;
776 in->deltaT = arm->nonRTDeltaT;
782 auto&
hand = this->hands->hands.at(nodeSet);
784 std::dynamic_pointer_cast<common::mp::JSMPInput>(mpData.input);
785 if (
hand->targetNonRT.jointPosition.has_value())
787 in->angleRadian =
hand->targetNonRT.jointPosition.value();
788 in->deltaT =
hand->nonRTDeltaT;
794 if (role ==
"object")
796 if (not this->coordinator)
799 <<
"when using the object for MP, the coordinator must be first instantiated";
802 const std::scoped_lock lock_vo_non_rt(this->coordinator->mtx_data_non_rt);
804 std::dynamic_pointer_cast<common::mp::TSMPInput>(mpData.input);
805 in->pose = this->coordinator->dataNonRt.currentPose;
806 in->vel = this->coordinator->dataNonRt.currentVel;
807 in->deltaT = this->coordinator->dataNonRt.deltaT;
814 template <
typename TSControllerType,
typename MPInterfaceType>
816 TSMPController<TSControllerType, MPInterfaceType>::processGroupSafety(
820 auto&
mp = mpData.mp;
824 for (
auto& ftGuard : mpConfig.ftGuard)
826 if (ftGuard.mpName ==
mp->getMPName())
828 bool const forceGuard =
829 (ftGuard.force.has_value() && ftGuard.force.value() >=
mp->getCanonicalValue());
830 bool const torqueGuard = (ftGuard.torque.has_value() &&
831 ftGuard.torque.value() >=
mp->getCanonicalValue());
833 auto& arm = this->limb.at(
mp->getNodeSetName());
835 bool const resetForce =
836 not arm->controller.ftsensor.isForceGuardEnabled() and forceGuard;
837 bool const resetTorque =
838 not arm->controller.ftsensor.isTorqueGuardEnabled() and torqueGuard;
839 if (resetForce or resetTorque)
841 ARMARX_INFO <<
"Triggering force torque safety guard for "
842 << arm->kinematicChainName <<
" at can value "
843 <<
mp->getCanonicalValue();
846 arm->nonRtConfig.ftConfig.enableSafeGuardForce = forceGuard;
847 arm->nonRtConfig.ftConfig.enableSafeGuardTorque = torqueGuard;
848 arm->controller.ftsensor.enableSafeGuard(resetForce, resetTorque);
855 const std::string& role =
mp->getRole();
856 const std::string& nodeSetName =
mp->getNodeSetName();
858 if (role ==
"taskspace")
860 buffer.canonicalValue =
mp->getCanonicalValue();
861 auto& arm = this->limb.at(nodeSetName);
862 auto out = std::dynamic_pointer_cast<common::mp::TSMPOutput>(mpData.output);
865 arm->rtStatusInNonRT.currentPose,
869 arm->nonRtConfig.safeDistanceMMToGoal,
870 arm->nonRtConfig.safeRotAngleDegreeToGoal,
871 "Additional task for task space MPs: " +
mp->getMPName() +
" detects that the ");
872 groupDeviationFlag_.emplace(
mp->getGroup(), flag);
874 arm->nonRtConfig.desiredPose = out->pose;
875 arm->nonRtConfig.desiredTwist = out->vel;
876 buffer.desiredPose.at(nodeSetName) = out->pose;
880 template <
typename TSControllerType,
typename MPInterfaceType>
882 TSMPController<TSControllerType, MPInterfaceType>::processMPOutput(
887 auto&
mp = mpData.mp;
888 bool deviationFlag =
true;
889 if (groupDeviationFlag_.count(
mp->getGroup()))
891 deviationFlag = groupDeviationFlag_.at(
mp->getGroup());
893 const std::string& role =
mp->getRole();
894 const std::string& nodeSetName =
mp->getNodeSetName();
896 if (role ==
"object")
898 buffer.canonicalValue =
mp->getCanonicalValue();
899 if (this->coordinator)
901 auto out = std::dynamic_pointer_cast<common::mp::TSMPOutput>(mpData.output);
902 this->coordinator->cfgInNonRt.desiredPose = out->pose;
905 else if (role ==
"nullspace")
907 auto& arm = this->limb.at(nodeSetName);
908 auto out = std::dynamic_pointer_cast<common::mp::JSMPOutput>(mpData.output);
910 if (not deviationFlag)
912 arm->nonRtConfig.desiredNullspaceJointAngles.value() = out->angleRadian;
915 else if (role ==
"hand")
917 auto&
hand = this->hands->hands.at(nodeSetName);
918 auto out = std::dynamic_pointer_cast<common::mp::JSMPOutput>(mpData.output);
920 out->angleRadian.size());
921 if (not deviationFlag)
923 hand->targetNonRT.jointPosition.value() = out->angleRadian;
939 if (
mp->isFinished())
941 ARMARX_INFO <<
"-- reset buffer for nonRtConfig of " <<
mp->getMPName();
944 for (
auto& [name, arm] : this->limb)
947 if (!rtTargetSafe || deviationFlag)
949 ARMARX_INFO <<
"-- discard the last MP desired pose, use the existing RT "
951 << arm->kinematicChainName <<
": \n"
952 << arm->rtStatusInNonRT.desiredPose;
953 arm->nonRtConfig.desiredPose = arm->rtStatusInNonRT.desiredPose;
955 arm->bufferConfigUserToNonRt.reinitAllBuffers(arm->nonRtConfig);
959 for (
auto& [name, arm] : this->limb)
961 this->userConfig.limbs.at(name) = arm->nonRtConfig;
967 this->hands->reinitBuffer(this->userConfig.hands);
971 if (this->coordinator)
973 this->coordinator->resetBufferUserCfgAfterMP();