CollisionAvoidanceImpedanceController.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{
31 NJointControllerRegistration<NJointTSCollisionAvoidanceImpedanceMPController>
33 "NJointTSCollisionAvoidanceImpedanceMPController");
34
44
45 std::string
47 {
48 return "NJointTSCollisionAvoidanceImpedanceMPController";
49 }
50
51 void
53 const ::armarx::aron::data::dto::DictPtr& dto,
54 const Ice::Current& iceCurrent)
55 {
57 {
58 for (auto& pair : limb)
59 {
60 pair.second->rtFirstRun.store(true);
61 }
62 }
63 }
64
65 void
67 {
68 const std::lock_guard<std::recursive_mutex> lock(mtx_mps);
69 auto [rtTargetSafe, ftSafe] = additionalTaskUpdateStatus();
70 if (coordinator)
71 {
72 coordinator->updateNonRt();
73 }
74
75 // when ft guard is enabled and rt is not safe due to ft trigger, then we stop the corresponding mp
76 std::map<std::string, bool> flagMPToStop;
77 for (auto& pair : limb)
78 {
79 flagMPToStop[pair.first] = not limb.at(pair.first)->controller.ftsensor.ftSafe.load();
80 pair.second->nonRTDeltaT =
81 pair.second->rtStatusInNonRT.accumulateTime - pair.second->nonRTAccumulateTime;
82 pair.second->nonRTAccumulateTime = pair.second->rtStatusInNonRT.accumulateTime;
83 }
84 if (hands)
85 {
86 for (auto& pair : hands->hands)
87 {
88 pair.second->nonRTDeltaT =
89 pair.second->rtsInNonRT.accumulateTime - pair.second->nonRTAccumulateTime;
90 pair.second->nonRTAccumulateTime = pair.second->rtsInNonRT.accumulateTime;
91 }
92 }
93
94 std::map<std::string, bool> mpRunning;
95 for (auto& mp : mps)
96 {
97 const auto mpNodeSet = mp.second.mp->getNodeSetName();
98 mpRunning[mp.second.mp->getMPName()] = mp.second.mp->isRunning();
99
100 /// TODO add loop the check if MP for the sync mode coordinator need to stop
101 auto search = flagMPToStop.find(mpNodeSet);
102 if (search != flagMPToStop.end() and flagMPToStop.at(mpNodeSet) and
103 mp.second.mp->isRunning() and
104 (limb.at(mpNodeSet)->controller.ftsensor.isForceGuardEnabled() or
105 limb.at(mpNodeSet)->controller.ftsensor.isTorqueGuardEnabled()))
106 {
107 mp.second.mp->stop();
108 ARMARX_INFO << "Due to force/torque safe guard, MP " << mp.second.mp->getMPName()
109 << " is stopped at " << mp.second.mp->getCanonicalValue();
110 }
111
112 if (mp.second.mp->isFinished())
113 {
114 continue;
115 }
116 if (mp.second.mp->getRole() == "taskspace")
117 {
118 auto& arm = limb.at(mp.second.mp->getNodeSetName());
119 if (mp.second.mp->isFirstRun())
120 {
121 ARMARX_INFO << "checking TSMP initial status ...";
122 /// Here we check if the TSMP start pose is too far away from the current pose, if so, we would
123 /// prefer to reset the mp start from the current pose.
124 const std::vector<double> mpStart = mp.second.mp->getStartVec();
125 const auto mpStartPose = common::dVecToMat4(mpStart);
126 if (mp.second.mp->getStartFromPrevTarget() or
128 arm->rtStatusInNonRT.currentPose,
129 mpStartPose,
130 "current pose",
131 "TSMP initial start pose",
132 arm->nonRtConfig.safeDistanceMMToGoal,
133 arm->nonRtConfig.safeRotAngleDegreeToGoal,
134 mp.second.mp->getMPName() + "mp_set_target"))
135 {
136 if (mp.second.mp->getStartFromPrevTarget())
137 {
138 ARMARX_INFO << "User requested to start the current TS MP from the "
139 "previous target pose";
140 }
141 else
142 {
144 << "deviation from current pose too large, reset MP start pose";
145 }
146 mp.second.mp->validateInitialState(
147 common::mat4ToDVec(arm->rtStatusInNonRT.desiredPose));
148 }
149 ARMARX_INFO << "done";
150 }
151 mp::TSMPInputPtr in = std::dynamic_pointer_cast<mp::TSMPInput>(mp.second.input);
152 in->pose = arm->rtStatusInNonRT.currentPose;
153 in->vel = arm->rtStatusInNonRT.currentTwist;
154 // in->deltaT = arm->rtStatusInNonRT.deltaT;
155 in->deltaT = arm->nonRTDeltaT;
156 }
157 else if (mp.second.mp->getRole() == "nullspace")
158 {
159 auto& arm = limb.at(mp.second.mp->getNodeSetName());
160 mp::JSMPInputPtr in = std::dynamic_pointer_cast<mp::JSMPInput>(mp.second.input);
161 ARMARX_CHECK_EQUAL(arm->rtStatusInNonRT.nDoF,
162 arm->rtStatusInNonRT.jointPosition.size());
163 in->angleRadian = arm->rtStatusInNonRT.jointPosition;
164 in->angularVel = arm->rtStatusInNonRT.qvelFiltered;
165 in->deltaT = arm->nonRTDeltaT;
166 }
167 else if (mp.second.mp->getRole() == "hand")
168 {
169 auto& hand = hands->hands.at(mp.second.mp->getNodeSetName());
170 mp::JSMPInputPtr in = std::dynamic_pointer_cast<mp::JSMPInput>(mp.second.input);
171 // in->angleRadian = hand->rtsInNonRT.jointPosition.value();
172 in->deltaT = hand->nonRTDeltaT;
173 }
174 else if (mp.second.mp->getRole() == "object")
175 {
176 if (not coordinator)
177 {
178 ARMARX_WARNING << "when using the object for MP, the coordinator must be first "
179 "instantiated";
180 return;
181 }
182 // auto& nodesetList = coord->getNodesetList();
183 // auto& rtsL = limb.at(coord->getLeftNodesetName())->rtStatusInNonRT;
184 // auto& rtsR = limb.at(coord->getRightNodesetName())->rtStatusInNonRT;
185
186 // setPos(currentPose, 0.5f * (getPos(rtsL.currentPose) + getPos(rtsR.currentPose)));
187 // setOri(currentPose, getOri(rtsL.currentPose));
188 const std::scoped_lock lock_vo_non_rt(coordinator->mtx_data_non_rt);
189 mp::TSMPInputPtr in = std::dynamic_pointer_cast<mp::TSMPInput>(mp.second.input);
190 in->pose = coordinator->dataNonRt.currentPose;
191 in->vel = coordinator->dataNonRt.currentVel;
192 in->deltaT = coordinator->dataNonRt.deltaT;
193 }
194 }
195 if (not rtTargetSafe)
196 {
198
199 // return;
200 // Make sure that you do not call additionalTaskSetTarget before return;
201 // since we overwrite the arm->nonRtConfig in additionalTaskUpdateStatus() with user config, which does not
202 // align with the up-to-date mp status. userConfig is only updated to align with MP status everytime a MP
203 // finishes execution. Only then, user can use this controller as if no mp is there.
204 }
205 runMPs(rtTargetSafe);
206
207 /// set mp target to nonRT config data structure
208 for (auto& mp : mps)
209 {
210 if (not mpRunning.at(mp.second.mp->getMPName()))
211 {
212 continue;
213 }
214 for (auto& ftGuard : mpConfig.ftGuard)
215 {
216 if (ftGuard.mpName == mp.second.mp->getMPName())
217 {
218 bool const forceGuard =
219 (ftGuard.force.has_value() and
220 ftGuard.force.value() >= mp.second.mp->getCanonicalValue());
221 bool const torqueGuard =
222 (ftGuard.torque.has_value() and
223 ftGuard.torque.value() >= mp.second.mp->getCanonicalValue());
224
225 auto& arm = limb.at(mp.second.mp->getNodeSetName());
226 bool const resetForce =
227 not arm->controller.ftsensor.isForceGuardEnabled() and forceGuard;
228 bool const resetTorque =
229 not arm->controller.ftsensor.isTorqueGuardEnabled() and torqueGuard;
230 if (resetForce or resetTorque)
231 {
232 ARMARX_INFO << "Triggering force torque safety guard for "
233 << arm->kinematicChainName << " at can value "
234 << mp.second.mp->getCanonicalValue();
235 }
236
237 arm->nonRtConfig.ftConfig.enableSafeGuardForce = forceGuard;
238 arm->nonRtConfig.ftConfig.enableSafeGuardTorque = torqueGuard;
239 arm->controller.ftsensor.enableSafeGuard(resetForce, resetTorque);
240 }
241 }
242
243 if (mp.second.mp->getRole() == "taskspace")
244 {
245 auto& arm = limb.at(mp.second.mp->getNodeSetName());
246 mp::TSMPOutputPtr out = std::dynamic_pointer_cast<mp::TSMPOutput>(mp.second.output);
247
248 /// Note that here we only report warning but still set target to RT, we rely on MP phase stop and
249 /// RT safety mechanism to stop or pause the action if needed
251 arm->rtStatusInNonRT.currentPose,
252 out->pose,
253 "current pose",
254 "TSMP pose",
255 arm->nonRtConfig.safeDistanceMMToGoal,
256 arm->nonRtConfig.safeRotAngleDegreeToGoal,
257 mp.second.mp->getMPName() + "mp_set_target");
258 arm->nonRtConfig.desiredPose = out->pose;
259 arm->nonRtConfig.desiredTwist = out->vel;
260 // arm->bufferNonRtToPublish.getWriteBuffer().poseVec = out->poseVec;
261 // arm->bufferNonRtToPublish.commitWrite();
262 }
263 else if (mp.second.mp->getRole() == "object")
264 {
265 if (not coordinator)
266 {
267 ARMARX_WARNING << "when using the object for MP, the coordinator must be first "
268 "instantiated";
269 return;
270 }
271 mp::TSMPOutputPtr out = std::dynamic_pointer_cast<mp::TSMPOutput>(mp.second.output);
272 coordinator->cfgInNonRt.desiredPose = out->pose;
273 }
274 else if (mp.second.mp->getRole() == "nullspace")
275 {
276 auto& arm = limb.at(mp.second.mp->getNodeSetName());
277 mp::JSMPOutputPtr out = std::dynamic_pointer_cast<mp::JSMPOutput>(mp.second.output);
278 ARMARX_CHECK_EQUAL(arm->rtStatusInNonRT.nDoF, out->angleRadian.size());
279 arm->nonRtConfig.desiredNullspaceJointAngles.value() = out->angleRadian;
280 }
281 else if (mp.second.mp->getRole() == "hand")
282 {
283 mp::JSMPOutputPtr out = std::dynamic_pointer_cast<mp::JSMPOutput>(mp.second.output);
284 auto& hand = hands->hands.at(mp.second.mp->getNodeSetName());
285 mp::JSMPInputPtr in = std::dynamic_pointer_cast<mp::JSMPInput>(mp.second.input);
286 ARMARX_CHECK_EQUAL(hand->targetNonRT.jointPosition.value().size(),
287 out->angleRadian.size());
288 hand->targetNonRT.jointPosition.value() = out->angleRadian;
289 }
290 if (mpRunning.at(mp.second.mp->getMPName()) and mp.second.mp->isFinished())
291 {
292 ARMARX_INFO << "reset buffer for nonRtConfig of " << mp.second.mp->getMPName();
293 for (auto& pair : limb)
294 {
295 auto& arm = pair.second;
296 arm->bufferConfigUserToNonRt.reinitAllBuffers(arm->nonRtConfig);
297 }
298 for (auto& pair : limb)
299 {
300 userConfig.limbs.at(pair.first) = pair.second->nonRtConfig;
301 }
302 if (hands)
303 {
304 hands->reinitBuffer(userConfig.hands);
305 }
306 if (coordinator)
307 {
308 coordinator->resetBufferUserCfgAfterMP();
309 }
310 }
311 }
312 // TODO apply coordinator (for loosely-coupled/tightly-coupled tasks)
313 // sync mode is handled directly by "object" type of mp
314 if (coordinator)
315 {
316 coordinator->commitNonRt();
317 }
318
320 }
321} // namespace armarx::control::njoint_mp_controller::task_space
bool resetMPsV1(const ::armarx::aron::data::dto::DictPtr &dto, const std::map< std::string, VirtualRobot::RobotNodeSetPtr > &rnsMap, const std::shared_ptr< common::coordination::Coordination > &coordinator)
Definition MPPool.cpp:604
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
NJointTaskspaceCollisionAvoidanceImpedanceController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &robot)
Brief description of class NJointTaskspaceImpedanceController.
std::map< std::string, VirtualRobot::RobotNodeSetPtr > controllableNodeSets
std::shared_ptr< common::coordination::SyncCoordination > coordinator
void updateMPConfig(const ::armarx::aron::data::dto::DictPtr &dto, const Ice::Current &iceCurrent=Ice::emptyCurrent) override
NJointTSCollisionAvoidanceImpedanceMPController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &)
#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
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
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< NJointTSCollisionAvoidanceImpedanceMPController > registrationControllerNJointTSCollisionAvoidanceImpedanceMPController("NJointTSCollisionAvoidanceImpedanceMPController")
IceUtil::Handle< class RobotUnit > RobotUnitPtr
Definition FTSensor.h:34