ObjectCollisionAvoidanceImpedanceController.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<NJointTSObjectCollisionAvoidanceImpedanceMPController>
33 "NJointTSObjectCollisionAvoidanceImpedanceMPController");
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 std::lock_guard<std::recursive_mutex> lock(mtx_mps);
69 auto [rtTargetSafe, ftSafe] = additionalTaskUpdateStatus();
70
71 // when ft guard is enabled and rt is not safe due to ft trigger, then we stop the corresponding mp
72 std::map<std::string, bool> flagMPToStop;
73 for (auto& pair : limb)
74 {
75 flagMPToStop[pair.first] = not limb.at(pair.first)->controller.ftsensor.ftSafe.load();
76 pair.second->nonRTDeltaT =
77 pair.second->rtStatusInNonRT.accumulateTime - pair.second->nonRTAccumulateTime;
78 pair.second->nonRTAccumulateTime = pair.second->rtStatusInNonRT.accumulateTime;
79 }
80 if (hands)
81 {
82 for (auto& pair : hands->hands)
83 {
84 pair.second->nonRTDeltaT =
85 pair.second->rtsInNonRT.accumulateTime - pair.second->nonRTAccumulateTime;
86 pair.second->nonRTAccumulateTime = pair.second->rtsInNonRT.accumulateTime;
87 }
88 }
89
90 std::map<std::string, bool> mpRunning;
91 for (auto& _mp : mps)
92 {
93 const auto mpNodeSet = _mp.second.mp->getNodeSetName();
94 mpRunning[_mp.second.mp->getMPName()] = _mp.second.mp->isRunning();
95
96 auto search = flagMPToStop.find(mpNodeSet);
97 if (search != flagMPToStop.end() and flagMPToStop.at(mpNodeSet) and
98 _mp.second.mp->isRunning() and
99 (limb.at(mpNodeSet)->controller.ftsensor.isForceGuardEnabled() or
100 limb.at(mpNodeSet)->controller.ftsensor.isTorqueGuardEnabled()))
101 {
102 _mp.second.mp->stop();
103 ARMARX_INFO << "Due to force/torque safe guard, MP " << _mp.second.mp->getMPName()
104 << " is stopped at " << _mp.second.mp->getCanonicalValue();
105 }
106
107 if (_mp.second.mp->isFinished())
108 {
109 continue;
110 }
111 if (_mp.second.mp->getRole() == "taskspace")
112 {
113 auto& arm = limb.at(_mp.second.mp->getNodeSetName());
114 if (_mp.second.mp->isFirstRun())
115 {
116 ARMARX_INFO << "checking TSMP initial status ...";
117 /// Here we check if the TSMP start pose is too far away from the current pose, if so, we would
118 /// prefer to reset the mp start from the current pose.
119 const std::vector<double> mpStart = _mp.second.mp->getStartVec();
120 const auto mpStartPose = common::dVecToMat4(mpStart);
121 if (_mp.second.mp->getStartFromPrevTarget() or
123 arm->rtStatusInNonRT.currentPose,
124 mpStartPose,
125 "current pose",
126 "TSMP initial start pose",
127 arm->nonRtConfig.safeDistanceMMToGoal,
128 arm->nonRtConfig.safeRotAngleDegreeToGoal,
129 _mp.second.mp->getMPName() + "mp_set_target"))
130 {
131 if (_mp.second.mp->getStartFromPrevTarget())
132 {
133 ARMARX_INFO << "User requested to start the current TS MP from the "
134 "previous target pose";
135 }
136 else
137 {
139 << "deviation from current pose too large, reset MP start pose";
140 }
141 _mp.second.mp->validateInitialState(
142 common::mat4ToDVec(arm->rtStatusInNonRT.desiredPose));
143 }
144 ARMARX_INFO << "done";
145 }
146 mp::TSMPInputPtr in = std::dynamic_pointer_cast<mp::TSMPInput>(_mp.second.input);
147 in->pose = arm->rtStatusInNonRT.currentPose;
148 in->vel = arm->rtStatusInNonRT.currentTwist;
149 // in->deltaT = arm->rtStatusInNonRT.deltaT;
150 in->deltaT = arm->nonRTDeltaT;
151 }
152 else if (_mp.second.mp->getRole() == "nullspace")
153 {
154 auto& arm = limb.at(_mp.second.mp->getNodeSetName());
155 mp::JSMPInputPtr in = std::dynamic_pointer_cast<mp::JSMPInput>(_mp.second.input);
156 ARMARX_CHECK_EQUAL(arm->rtStatusInNonRT.nDoF,
157 arm->rtStatusInNonRT.jointPosition.size());
158 in->angleRadian = arm->rtStatusInNonRT.jointPosition;
159 in->angularVel = arm->rtStatusInNonRT.qvelFiltered;
160 in->deltaT = arm->nonRTDeltaT;
161 }
162 else if (_mp.second.mp->getRole() == "hand")
163 {
164 auto& hand = hands->hands.at(_mp.second.mp->getNodeSetName());
165 mp::JSMPInputPtr in = std::dynamic_pointer_cast<mp::JSMPInput>(_mp.second.input);
166 in->angleRadian = hand->rtsInNonRT.jointPosition.value();
167 in->deltaT = hand->nonRTDeltaT;
168 }
169 }
170 if (not rtTargetSafe)
171 {
173
174 // return;
175 // Make sure that you do not call additionalTaskSetTarget before return;
176 // since we overwrite the arm->nonRtConfig in additionalTaskUpdateStatus() with user config, which does not
177 // align with the up-to-date mp status. userConfig is only updated to align with MP status everytime a MP
178 // finishes execution. Only then, user can use this controller as if no mp is there.
179 }
180 runMPs(rtTargetSafe);
181
182 /// set mp target to nonRT config data structure
183 for (auto& _mp : mps)
184 {
185 if (not mpRunning.at(_mp.second.mp->getMPName()))
186 {
187 continue;
188 }
189 for (auto& ftGuard : mpConfig.ftGuard)
190 {
191 if (ftGuard.mpName == _mp.second.mp->getMPName())
192 {
193 bool const forceGuard =
194 (ftGuard.force.has_value() and
195 ftGuard.force.value() >= _mp.second.mp->getCanonicalValue());
196 bool const torqueGuard =
197 (ftGuard.torque.has_value() and
198 ftGuard.torque.value() >= _mp.second.mp->getCanonicalValue());
199
200 auto& arm = limb.at(_mp.second.mp->getNodeSetName());
201 bool const resetForce =
202 not arm->controller.ftsensor.isForceGuardEnabled() and forceGuard;
203 bool const resetTorque =
204 not arm->controller.ftsensor.isTorqueGuardEnabled() and torqueGuard;
205 if (resetForce or resetTorque)
206 {
207 ARMARX_INFO << "Triggering force torque safety guard for "
208 << arm->kinematicChainName << " at can value "
209 << _mp.second.mp->getCanonicalValue();
210 }
211
212 arm->nonRtConfig.ftConfig.enableSafeGuardForce = forceGuard;
213 arm->nonRtConfig.ftConfig.enableSafeGuardTorque = torqueGuard;
214 arm->controller.ftsensor.enableSafeGuard(resetForce, resetTorque);
215 }
216 }
217
218 if (_mp.second.mp->getRole() == "taskspace")
219 {
220 auto& arm = limb.at(_mp.second.mp->getNodeSetName());
222 std::dynamic_pointer_cast<mp::TSMPOutput>(_mp.second.output);
223
224 /// Note that here we only report warning but still set target to RT, we rely on MP phase stop and
225 /// RT safety mechanism to stop or pause the action if needed
227 arm->rtStatusInNonRT.currentPose,
228 out->pose,
229 "current pose",
230 "TSMP pose",
231 arm->nonRtConfig.safeDistanceMMToGoal,
232 arm->nonRtConfig.safeRotAngleDegreeToGoal,
233 _mp.second.mp->getMPName() + "mp_set_target");
234 arm->nonRtConfig.desiredPose = out->pose;
235 arm->nonRtConfig.desiredTwist = out->vel;
236 }
237 else if (_mp.second.mp->getRole() == "nullspace")
238 {
239 auto& arm = limb.at(_mp.second.mp->getNodeSetName());
241 std::dynamic_pointer_cast<mp::JSMPOutput>(_mp.second.output);
242 ARMARX_CHECK_EQUAL(arm->rtStatusInNonRT.nDoF, out->angleRadian.size());
243 arm->nonRtConfig.desiredNullspaceJointAngles.value() = out->angleRadian;
244 }
245 else if (_mp.second.mp->getRole() == "hand")
246 {
248 std::dynamic_pointer_cast<mp::JSMPOutput>(_mp.second.output);
249 auto& hand = hands->hands.at(_mp.second.mp->getNodeSetName());
250 mp::JSMPInputPtr in = std::dynamic_pointer_cast<mp::JSMPInput>(_mp.second.input);
251 ARMARX_CHECK_EQUAL(hand->targetNonRT.jointPosition.value().size(),
252 out->angleRadian.size());
253 hand->targetNonRT.jointPosition.value() = out->angleRadian;
254 }
255 if (mpRunning.at(_mp.second.mp->getMPName()) and _mp.second.mp->isFinished())
256 {
257 ARMARX_INFO << "reset buffer for nonRtConfig of " << _mp.second.mp->getMPName();
258 for (auto& pair : limb)
259 {
260 auto& arm = pair.second;
261 arm->bufferConfigUserToNonRt.reinitAllBuffers(arm->nonRtConfig);
262 }
263 for (auto& pair : limb)
264 {
265 userConfig.limbs.at(pair.first) = pair.second->nonRtConfig;
266 }
267 if (hands)
268 {
269 hands->reinitBuffer(userConfig.hands);
270 }
271 }
272 }
274 }
275
276 void
278 const SensorAndControl& sc,
279 const DebugDrawerInterfacePrx& drawer,
280 const DebugObserverInterfacePrx& debugObs)
281 {
283 for (auto& _mp : mps)
284 {
285 // visualize goal position
286 if (!mpLayer)
287 {
288 mpLayer = arviz.layer("MP Visualization");
289 }
290
291 if (_mp.second.mp->getRole() == "taskspace")
292 {
293 auto& arm = limb.at(_mp.second.mp->getNodeSetName());
294
295 mp::TSMPOutputPtr out = std::dynamic_pointer_cast<mp::TSMPOutput>(_mp.second.output);
296 auto outPose = out->pose;
297 outPose.block<3, 1>(0, 3) /= 1000;
298
299 mp::TSMPInputPtr in = std::dynamic_pointer_cast<mp::TSMPInput>(_mp.second.input);
300 auto inPose = in->pose;
301 inPose.block<3, 1>(0, 3) /= 1000;
302
303 // name is current time
304 auto outPoseSphere = viz::Sphere("poseOut_" + std::to_string(IceUtil::Time::now().toMicroSecondsDouble()))
305 .radius(10)
306 .position((coll->globalPose.matrix().cast<float>() * outPose).block<3, 1>(0, 3) * 1000)
307 .color(255, 0, 0, 128);
308 mpLayer.value().add(outPoseSphere);
309
310 auto inPoseSphere = viz::Sphere("poseIn_" + std::to_string(IceUtil::Time::now().toMicroSecondsDouble()))
311 .radius(10)
312 .position((coll->globalPose.matrix().cast<float>() * inPose).block<3, 1>(0, 3) * 1000)
313 .color(0, 0, 255, 128);
314 mpLayer.value().add(inPoseSphere);
315 }
316 arviz.commit(mpLayer.value());
317
318 }
319 }
320} // 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
Brief description of class NJointTaskspaceImpedanceController.
std::map< std::string, VirtualRobot::RobotNodeSetPtr > controllableNodeSets
NJointTaskspaceObjectCollisionAvoidanceImpedanceController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &robot)
void onPublish(const SensorAndControl &sc, const DebugDrawerInterfacePrx &drawer, const DebugObserverInterfacePrx &) override
void updateMPConfig(const ::armarx::aron::data::dto::DictPtr &dto, const Ice::Current &iceCurrent=Ice::emptyCurrent) override
NJointTSObjectCollisionAvoidanceImpedanceMPController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &)
void onPublish(const SensorAndControl &sc, const DebugDrawerInterfacePrx &drawer, const DebugObserverInterfacePrx &) override
DerivedT & color(Color color)
Definition ElementOps.h:218
DerivedT & position(float x, float y, float z)
Definition ElementOps.h:136
#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
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< NJointTSObjectCollisionAvoidanceImpedanceMPController > registrationControllerNJointTSObjectCollisionAvoidanceImpedanceMPController("NJointTSObjectCollisionAvoidanceImpedanceMPController")
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugObserverInterface > DebugObserverInterfacePrx
IceUtil::Handle< class RobotUnit > RobotUnitPtr
Definition FTSensor.h:34
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugDrawerInterface > DebugDrawerInterfacePrx
detail::ControlThreadOutputBufferEntry SensorAndControl
Sphere & radius(float r)
Definition Elements.h:138