AdmittanceController.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 * @author Jianfeng Gao ( jianfeng dot gao at kit dot edu )
17 * @date 2023
18 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
19 * GNU General Public License
20 */
21
23
25#include <RobotAPI/components/units/RobotUnit/RobotUnit.h> // FIXME avoid this
26
28
30{
33
36 const NJointControllerConfigPtr& config,
37 const VirtualRobot::RobotPtr& robot) :
39 {
40 ARMARX_IMPORTANT << getClassName() + " construction done";
41 }
42
43 std::string
45 {
46 return "NJointTSAdmittanceMPController";
47 }
48
49 void
50 NJointTSAdmittanceMPController::updateMPConfig(const ::armarx::aron::data::dto::DictPtr& dto,
51 const Ice::Current& iceCurrent)
52 {
54 {
55 for (auto& pair : limb)
56 {
57 pair.second->rtFirstRun.store(true);
58 }
59 }
60 }
61
62 void
64 {
65 std::lock_guard<std::recursive_mutex> lock(mtx_mps);
66 bool rtSafe = additionalTaskUpdateStatus();
67
68 // when ft guard is enabled and rt is not safe due to ft trigger, then we stop the corresponding mp
69 std::map<std::string, bool> flagMPToStop;
70 for (auto& pair : limb)
71 {
72 flagMPToStop[pair.first] = not limb.at(pair.first)->controller.ftsensor.ftSafe.load();
73 pair.second->nonRTDeltaT =
74 pair.second->rtStatusInNonRT.accumulateTime - pair.second->nonRTAccumulateTime;
75 pair.second->nonRTAccumulateTime = pair.second->rtStatusInNonRT.accumulateTime;
76 }
77 if (hands)
78 {
79 for (auto& pair : hands->hands)
80 {
81 pair.second->nonRTDeltaT =
82 pair.second->rtsInNonRT.accumulateTime - pair.second->nonRTAccumulateTime;
83 pair.second->nonRTAccumulateTime = pair.second->rtsInNonRT.accumulateTime;
84 }
85 }
86
87 std::map<std::string, bool> mpRunning;
88 for (auto& _mp : mps)
89 {
90 const auto mpNodeSet = _mp.second.mp->getNodeSetName();
91 mpRunning[_mp.second.mp->getMPName()] = _mp.second.mp->isRunning();
92
93 auto search = flagMPToStop.find(mpNodeSet);
94 if (search != flagMPToStop.end() and flagMPToStop.at(mpNodeSet) and
95 _mp.second.mp->isRunning() and
96 (limb.at(mpNodeSet)->controller.ftsensor.isForceGuardEnabled() or
97 limb.at(mpNodeSet)->controller.ftsensor.isTorqueGuardEnabled()))
98 {
99 _mp.second.mp->stop();
100 ARMARX_INFO << "Due to force/torque safe guard, MP " << _mp.second.mp->getMPName()
101 << " is stopped at " << _mp.second.mp->getCanonicalValue();
102 }
103
104 if (_mp.second.mp->isFinished())
105 {
106 continue;
107 }
108 if (_mp.second.mp->getRole() == "taskspace")
109 {
110 auto& arm = limb.at(_mp.second.mp->getNodeSetName());
111 if (_mp.second.mp->isFirstRun())
112 {
113 ARMARX_INFO << "checking TSMP initial status ...";
114 /// Here we check if the TSMP start pose is too far away from the current pose, if so, we would
115 /// prefer to reset the mp start from the current pose.
116 const std::vector<double> mpStart = _mp.second.mp->getStartVec();
117 const auto mpStartPose = common::dVecToMat4(mpStart);
118 if (_mp.second.mp->getStartFromPrevTarget() or
120 arm->rtStatusInNonRT.currentPose,
121 mpStartPose,
122 "current pose",
123 "TSMP initial start pose",
124 arm->nonRtConfig.safeDistanceMMToGoal,
125 arm->nonRtConfig.safeRotAngleDegreeToGoal,
126 _mp.second.mp->getMPName() + "mp_set_target"))
127 {
128 if (_mp.second.mp->getStartFromPrevTarget())
129 {
130 ARMARX_INFO << "User requested to start the current TS MP from the "
131 "previous target pose";
132 }
133 else
134 {
136 << "deviation from current pose too large, reset MP start pose";
137 }
138 _mp.second.mp->validateInitialState(
139 common::mat4ToDVec(arm->rtStatusInNonRT.desiredPose));
140 }
141 ARMARX_INFO << "done";
142 }
143 mp::TSMPInputPtr in = std::dynamic_pointer_cast<mp::TSMPInput>(_mp.second.input);
144 in->pose = arm->rtStatusInNonRT.currentPose;
145 in->vel = arm->rtStatusInNonRT.currentTwist;
146 // in->deltaT = arm->rtStatusInNonRT.deltaT;
147 in->deltaT = arm->nonRTDeltaT;
148 }
149 else if (_mp.second.mp->getRole() == "nullspace")
150 {
151 auto& arm = limb.at(_mp.second.mp->getNodeSetName());
152 mp::JSMPInputPtr in = std::dynamic_pointer_cast<mp::JSMPInput>(_mp.second.input);
153 ARMARX_CHECK_EQUAL(arm->rtStatusInNonRT.nDoF,
154 arm->rtStatusInNonRT.jointPosition.size());
155 in->angleRadian = arm->rtStatusInNonRT.jointPosition;
156 in->angularVel = arm->rtStatusInNonRT.qvelFiltered;
157 in->deltaT = arm->nonRTDeltaT;
158 }
159 else if (_mp.second.mp->getRole() == "hand")
160 {
161 auto& hand = hands->hands.at(_mp.second.mp->getNodeSetName());
162 mp::JSMPInputPtr in = std::dynamic_pointer_cast<mp::JSMPInput>(_mp.second.input);
163 // in->angleRadian = hand->rtsInNonRT.jointPosition.value();
164 in->deltaT = hand->nonRTDeltaT;
165 }
166 }
167 if (not rtSafe)
168 {
170
171 // return;
172 // Make sure that you do not call additionalTaskSetTarget before return;
173 // since we overwrite the arm->nonRtConfig in additionalTaskUpdateStatus() with user config, which does not
174 // align with the up-to-date mp status. userConfig is only updated to align with MP status everytime a MP
175 // finishes execution. Only then, user can use this controller as if no mp is there.
176 }
177 runMPs(rtSafe);
178
179 /// set mp target to nonRT config data structure
180 for (auto& _mp : mps)
181 {
182 if (not mpRunning.at(_mp.second.mp->getMPName()))
183 {
184 continue;
185 }
186 for (auto& ftGuard : mpConfig.ftGuard)
187 {
188 if (ftGuard.mpName == _mp.second.mp->getMPName())
189 {
190 bool const forceGuard =
191 (ftGuard.force.has_value() and
192 ftGuard.force.value() >= _mp.second.mp->getCanonicalValue());
193 bool const torqueGuard =
194 (ftGuard.torque.has_value() and
195 ftGuard.torque.value() >= _mp.second.mp->getCanonicalValue());
196
197 auto& arm = limb.at(_mp.second.mp->getNodeSetName());
198 bool const resetForce =
199 not arm->controller.ftsensor.isForceGuardEnabled() and forceGuard;
200 bool const resetTorque =
201 not arm->controller.ftsensor.isTorqueGuardEnabled() and torqueGuard;
202 if (resetForce or resetTorque)
203 {
204 ARMARX_INFO << "Triggering force torque safety guard for "
205 << arm->kinematicChainName << " at can value "
206 << _mp.second.mp->getCanonicalValue();
207 }
208
209 arm->nonRtConfig.ftConfig.enableSafeGuardForce = forceGuard;
210 arm->nonRtConfig.ftConfig.enableSafeGuardTorque = torqueGuard;
211 arm->controller.ftsensor.enableSafeGuard(resetForce, resetTorque);
212 }
213 }
214
215 if (_mp.second.mp->getRole() == "taskspace")
216 {
217 auto& arm = limb.at(_mp.second.mp->getNodeSetName());
219 std::dynamic_pointer_cast<mp::TSMPOutput>(_mp.second.output);
220
221 /// Note that here we only report warning but still set target to RT, we rely on MP phase stop and
222 /// RT safety mechanism to stop or pause the action if needed
224 arm->rtStatusInNonRT.currentPose,
225 out->pose,
226 "current pose",
227 "TSMP pose",
228 arm->nonRtConfig.safeDistanceMMToGoal,
229 arm->nonRtConfig.safeRotAngleDegreeToGoal,
230 _mp.second.mp->getMPName() + "mp_set_target");
231 arm->nonRtConfig.desiredPose = out->pose;
232 arm->nonRtConfig.desiredTwist = out->vel;
233 }
234 else if (_mp.second.mp->getRole() == "nullspace")
235 {
236 auto& arm = limb.at(_mp.second.mp->getNodeSetName());
238 std::dynamic_pointer_cast<mp::JSMPOutput>(_mp.second.output);
239 ARMARX_CHECK_EQUAL(arm->rtStatusInNonRT.nDoF, out->angleRadian.size());
240 arm->nonRtConfig.desiredNullspaceJointAngles.value() = out->angleRadian;
241 }
242 else if (_mp.second.mp->getRole() == "hand")
243 {
245 std::dynamic_pointer_cast<mp::JSMPOutput>(_mp.second.output);
246 auto& hand = hands->hands.at(_mp.second.mp->getNodeSetName());
247 mp::JSMPInputPtr in = std::dynamic_pointer_cast<mp::JSMPInput>(_mp.second.input);
248 ARMARX_CHECK_EQUAL(hand->targetNonRT.jointPosition.value().size(),
249 out->angleRadian.size());
250 hand->targetNonRT.jointPosition.value() = out->angleRadian;
251 }
252 if (mpRunning.at(_mp.second.mp->getMPName()) and _mp.second.mp->isFinished())
253 {
254 ARMARX_INFO << "reset buffer for nonRtConfig of " << _mp.second.mp->getMPName();
255 for (auto& pair : limb)
256 {
257 auto& arm = pair.second;
258 arm->bufferConfigUserToNonRt.reinitAllBuffers(arm->nonRtConfig);
259 }
260 for (auto& pair : limb)
261 {
262 userConfig.limbs.at(pair.first) = pair.second->nonRtConfig;
263 }
264 if (hands)
265 {
266 hands->reinitBuffer(userConfig.hands);
267 }
268 }
269 }
271 }
272} // namespace armarx::control::njoint_mp_controller::task_space
bool resetMPs(const ::armarx::aron::data::dto::DictPtr &dto, const std::map< std::string, VirtualRobot::RobotNodeSetPtr > &rnsMap)
Definition MPPool.cpp:565
std::recursive_mutex mtx_mps
Definition MPPool.h:147
std::map< std::string, MPInputOutput > mps
Definition MPPool.h:146
MPListConfig mpConfig
this variable is only needed when constructing the MP instances, therefore you don't need to use trip...
Definition MPPool.h:153
NJointTaskspaceAdmittanceController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &)
std::string getClassName(const Ice::Current &=Ice::emptyCurrent) const override
NJointTSAdmittanceMPController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &)
void updateMPConfig(const ::armarx::aron::data::dto::DictPtr &dto, const Ice::Current &iceCurrent=Ice::emptyCurrent) override
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
This file is part of ArmarX.
std::shared_ptr< TSMPOutput > TSMPOutputPtr
Definition TSMP.h:47
std::shared_ptr< TSMPInput > TSMPInputPtr
Definition TSMP.h:46
std::shared_ptr< JSMPOutput > JSMPOutputPtr
Definition JSMP.h:48
std::shared_ptr< JSMPInput > JSMPInputPtr
Definition JSMP.h:47
bool detectAndReportPoseDeviationWarning(const Eigen::Matrix4f &pose1, const Eigen::Matrix4f &pose2, const std::string &namePose1, const std::string &namePose2, float positionThrMM, float angleThrDeg, const std::string &who)
Definition utils.cpp:773
Eigen::Matrix4f dVecToMat4(const DVec &dvec)
create Eigen:Matrix4f from 7D double vector.
Definition utils.cpp:325
DVec mat4ToDVec(const Eigen::Matrix4f &mat)
convert Eigen:Matrix4f to 7D double vector.
Definition utils.cpp:359
NJointControllerRegistration< NJointTSAdmittanceMPController > registrationControllerNJointTSAdmittanceMPController("NJointTSAdmittanceMPController")
IceUtil::Handle< class RobotUnit > RobotUnitPtr
Definition FTSensor.h:34