31 NJointControllerRegistration<NJointWipingMixImpVelColMPController>
33 "NJointWipingMixImpVelColMPController");
37 const NJointControllerConfigPtr& config,
48 return "NJointWipingMixImpVelColMPController";
54 const Ice::Current& iceCurrent)
58 for (
auto& pair :
limb)
60 pair.second->rtFirstRun.store(
true);
68 const Ice::Current& iceCurrent)
70 const auto adaptionCfg = arondto::WipingAdaptionConfigs::FromAron(dto);
74 for (
auto& pair :
limb)
76 auto search = adaptionCfg.cfg.find(pair.first);
77 if (search == adaptionCfg.cfg.end())
79 ARMARX_ERROR <<
"Arm " << pair.first <<
" is not included in the adaption config";
90 adaptionReady.store(
true);
104 for (
const auto& pair :
limb)
107 status.kpImpedance = pair.second->rtConfig.kpImpedance;
108 status.kpCartesianVel = pair.second->rtConfig.kpCartesianVel;
109 status.desiredPose = pair.second->rtConfig.desiredPose;
110 adaptionStatus[pair.first] =
status;
117 if (not adaptionReady.load())
123 std::lock_guard<std::recursive_mutex> lock(
mtx_mps);
127 std::map<std::string, bool> flagMPToStop;
128 for (
auto& pair :
limb)
130 flagMPToStop[pair.first] =
limb.at(pair.first)->controller.ftsensor.ftSafe.load();
133 const double timeScalingFactor =
134 adaptionCfg.timeScalingFactor.has_value()
135 ? fmin(fmax(adaptionCfg.timeScalingFactor.value(), 0.25), 4.)
138 const double sizeScalingFactor =
139 adaptionCfg.sizeScalingFactor.has_value() ? adaptionCfg.sizeScalingFactor.value() : 1.;
141 std::map<std::string, bool> mpRunning;
142 for (
auto& _mp :
mps)
144 const auto mpNodeSet = _mp.second.mp->getNodeSetName();
145 auto search = flagMPToStop.find(mpNodeSet);
146 if (search != flagMPToStop.end() and flagMPToStop.at(mpNodeSet) and
147 _mp.second.mp->isRunning() and
148 (
limb.at(mpNodeSet)->controller.ftsensor.isForceGuardEnabled() or
149 limb.at(mpNodeSet)->controller.ftsensor.isTorqueGuardEnabled()))
151 _mp.second.mp->stop();
152 ARMARX_INFO <<
"Due to force/torque safe guard, MP " << _mp.second.mp->getMPName()
153 <<
" is stopped at " << _mp.second.mp->getCanonicalValue();
155 mpRunning[_mp.second.mp->getMPName()] = _mp.second.mp->isRunning();
156 if (_mp.second.mp->isFinished())
160 if (_mp.second.mp->getRole() ==
"taskspace")
162 auto& arm =
limb.at(_mp.second.mp->getNodeSetName());
163 if (_mp.second.mp->isFirstRun())
168 const std::vector<double> mpStart = _mp.second.mp->getStartVec();
171 arm->rtStatusInNonRT.currentPose,
174 "TSMP initial start pose",
175 arm->nonRtConfig.safeDistanceMMToGoal,
176 arm->nonRtConfig.safeRotAngleDegreeToGoal,
177 _mp.second.mp->getMPName() +
"mp_set_target"))
180 <<
"-- deviation from current pose too large, reset MP start pose";
181 _mp.second.mp->validateInitialState(
186 mp::TSMPInputPtr in = std::dynamic_pointer_cast<mp::TSMPInput>(_mp.second.input);
187 in->pose = arm->rtStatusInNonRT.currentPose;
188 in->vel = arm->rtStatusInNonRT.currentTwist;
189 in->deltaT = arm->rtStatusInNonRT.deltaT * timeScalingFactor;
191 else if (_mp.second.mp->getRole() ==
"nullspace")
193 auto& arm =
limb.at(_mp.second.mp->getNodeSetName());
194 mp::JSMPInputPtr in = std::dynamic_pointer_cast<mp::JSMPInput>(_mp.second.input);
196 arm->rtStatusInNonRT.jointPos.size());
197 in->angleRadian = arm->rtStatusInNonRT.jointPos;
198 in->angularVel = arm->rtStatusInNonRT.qvelFiltered;
199 in->deltaT = arm->rtStatusInNonRT.deltaT * timeScalingFactor;
201 else if (_mp.second.mp->getRole() ==
"hand")
203 auto&
hand =
hands->hands.at(_mp.second.mp->getNodeSetName());
204 mp::JSMPInputPtr in = std::dynamic_pointer_cast<mp::JSMPInput>(_mp.second.input);
206 hand->bufferRTToNonRT.getUpToDateReadBuffer().jointPosition.value();
207 in->deltaT =
hand->bufferRTToNonRT.getReadBuffer().deltaT * timeScalingFactor;
210 if (not rtTargetSafe)
223 for (
auto& _mp :
mps)
225 if (not mpRunning.at(_mp.second.mp->getMPName()))
229 for (
auto& ftGuard :
mpConfig.ftGuard)
231 if (ftGuard.mpName == _mp.second.mp->getMPName())
233 bool const forceGuard =
234 (ftGuard.force.has_value() and
235 ftGuard.force.value() >= _mp.second.mp->getCanonicalValue());
236 bool const torqueGuard =
237 (ftGuard.torque.has_value() and
238 ftGuard.torque.value() >= _mp.second.mp->getCanonicalValue());
240 auto& arm =
limb.at(_mp.second.mp->getNodeSetName());
241 bool const resetForce =
242 not arm->controller.ftsensor.isForceGuardEnabled() and forceGuard;
243 bool const resetTorque =
244 not arm->controller.ftsensor.isTorqueGuardEnabled() and torqueGuard;
245 if (resetForce or resetTorque)
247 ARMARX_INFO <<
"Triggering force torque safety guard for "
248 << arm->kinematicChainName <<
" at can value "
249 << _mp.second.mp->getCanonicalValue();
252 arm->nonRtConfig.ftConfig.enableSafeGuardForce = forceGuard;
253 arm->nonRtConfig.ftConfig.enableSafeGuardTorque = torqueGuard;
254 arm->controller.ftsensor.enableSafeGuard(resetForce, resetTorque);
258 if (_mp.second.mp->getRole() ==
"taskspace")
260 const auto& nodeSetName = _mp.second.mp->getNodeSetName();
261 auto& cfg = adaptionCfg.cfg.at(nodeSetName);
262 auto&
s = adaptionStatus.at(nodeSetName);
263 auto& arm =
limb.at(nodeSetName);
265 std::dynamic_pointer_cast<mp::TSMPOutput>(_mp.second.output);
269 arm->nonRtConfig.desiredPose =
s.desiredPose;
271 arm->rtStatusInNonRT.currentPose,
272 arm->nonRtConfig.desiredPose,
274 "desiredPose for RT",
275 arm->nonRtConfig.safeDistanceMMToGoal,
276 arm->nonRtConfig.safeRotAngleDegreeToGoal,
277 _mp.second.mp->getMPName() +
"mp_set_target");
278 arm->nonRtConfig.desiredTwist = out->vel;
281 if (arm->rtStatusInNonRT.rtTargetSafe)
283 const float desiredVelZ =
284 cfg.kpf * (cfg.targetForce - arm->rtStatusInNonRT.currentForceTorque(2));
285 arm->nonRtConfig.desiredTwist(2) -= desiredVelZ;
287 arm->nonRtConfig.desiredTwist.tail<3>().setZero();
289 const float dT =
static_cast<float>(arm->rtStatusInNonRT.deltaT);
292 auto& adaptKImp =
s.kpImpedance;
293 auto& adaptKVel =
s.kpCartesianVel;
295 const Eigen::Vector2f& currentForceXY =
296 arm->rtStatusInNonRT.currentForceTorque.head<2>();
297 if (currentForceXY.norm() > cfg.deadZoneForce)
300 const Eigen::Vector2f dragForce =
301 currentForceXY - cfg.deadZoneForce * currentForceXY / currentForceXY.norm();
302 adaptKImp.head<2>().array() -= dT * cfg.adaptForceCoeff * dragForce.norm();
303 adaptKVel.head<2>().array() -= dT * cfg.adaptForceCoeff * dragForce.norm();
308 adaptKImp.head<2>().array() += fabs(dT * cfg.adaptCoeff);
309 adaptKVel.head<2>().array() += fabs(dT * cfg.adaptCoeff);
313 adaptKImp.head<2>() = adaptKImp.head<2>()
315 .min(arm->nonRtConfig.kpImpedance.head<2>().array())
317 adaptKVel.head<2>() = adaptKVel.head<2>()
319 .min(arm->nonRtConfig.kpCartesianVel.head<2>().array())
322 arm->nonRtConfig.kpImpedance = adaptKImp;
323 arm->nonRtConfig.kpCartesianVel = adaptKVel;
326 arm->nonRtConfig.desiredTwist.head<2>() *= sizeScalingFactor * timeScalingFactor;
329 arm->nonRtConfig.desiredPose.block<3, 1>(0, 3) +=
330 dT * arm->nonRtConfig.desiredTwist.head<3>();
333 if (cfg.minX.has_value())
335 arm->nonRtConfig.desiredPose(0, 3) =
336 fmax(arm->nonRtConfig.desiredPose(0, 3), *cfg.minX);
338 if (cfg.maxX.has_value())
340 arm->nonRtConfig.desiredPose(0, 3) =
341 fmin(arm->nonRtConfig.desiredPose(0, 3), *cfg.maxX);
343 if (cfg.minY.has_value())
345 arm->nonRtConfig.desiredPose(1, 3) =
346 fmax(arm->nonRtConfig.desiredPose(1, 3), *cfg.minY);
348 if (cfg.maxY.has_value())
350 arm->nonRtConfig.desiredPose(1, 3) =
351 fmin(arm->nonRtConfig.desiredPose(1, 3), *cfg.maxY);
353 if (cfg.minZ.has_value())
355 arm->nonRtConfig.desiredPose(2, 3) =
356 fmax(arm->nonRtConfig.desiredPose(2, 3), *cfg.minZ);
359 if (cfg.desiredUserPosition.has_value() and not cfg.desiredUserPosition->isZero())
361 if (not(*cfg.desiredUserPosition -
s.lastDesiredUserPosition).isZero())
363 if (
s.openDistanceToDesiredUserPosition > 0.)
365 ARMARX_INFO <<
"Didn't reach previously defined desired position "
366 <<
s.lastDesiredUserPosition;
368 s.lastDesiredUserPosition = *cfg.desiredUserPosition;
370 s.lastDesiredUserPosition -
371 arm->nonRtConfig.desiredPose.block<2, 1>(0, 3);
372 s.openDistanceToDesiredUserPosition =
distance.norm();
373 ARMARX_INFO <<
"Initialized new desired user position at "
374 <<
s.lastDesiredUserPosition <<
" which is "
375 <<
s.openDistanceToDesiredUserPosition
376 <<
" mm from current desired position";
379 if (
s.openDistanceToDesiredUserPosition > 0.)
381 Eigen::Vector2f desiredLinearVelocity =
382 s.lastDesiredUserPosition -
383 arm->nonRtConfig.desiredPose.block<2, 1>(0, 3);
384 desiredLinearVelocity = dT * cfg.kpLinear * desiredLinearVelocity /
385 desiredLinearVelocity.norm();
386 s.openDistanceToDesiredUserPosition -= desiredLinearVelocity.norm();
387 arm->nonRtConfig.desiredPose.block<2, 1>(0, 3) += desiredLinearVelocity;
388 if (
s.openDistanceToDesiredUserPosition < 0.)
391 <<
s.lastDesiredUserPosition;
399 const Eigen::Vector2f currentXY =
400 arm->rtStatusInNonRT.currentPose.block<2, 1>(0, 3);
401 if ((
s.lastPosition - currentXY).norm() < cfg.changePositionTolerance)
407 s.lastPosition = currentXY;
411 if (
s.changeTimer > cfg.changeTimerThreshold)
413 arm->nonRtConfig.desiredPose.block<2, 1>(0, 3) = currentXY;
417 << arm->nonRtConfig.desiredPose.block<3, 1>(0, 3).
transpose();
425 s.desiredPose = arm->nonRtConfig.desiredPose;
427 else if (_mp.second.mp->getRole() ==
"nullspace")
429 auto& arm =
limb.at(_mp.second.mp->getNodeSetName());
431 std::dynamic_pointer_cast<mp::JSMPOutput>(_mp.second.output);
433 arm->nonRtConfig.desiredNullspaceJointAngles.value() = out->angleRadian;
435 else if (_mp.second.mp->getRole() ==
"hand")
438 std::dynamic_pointer_cast<mp::JSMPOutput>(_mp.second.output);
439 auto&
hand =
hands->hands.at(_mp.second.mp->getNodeSetName());
440 mp::JSMPInputPtr in = std::dynamic_pointer_cast<mp::JSMPInput>(_mp.second.input);
442 out->angleRadian.size());
443 hand->targetNonRT.jointPosition.value() = out->angleRadian;
445 if (mpRunning.at(_mp.second.mp->getMPName()) and _mp.second.mp->isFinished())
447 ARMARX_INFO <<
"reset buffer for nonRtConfig of " << _mp.second.mp->getMPName();
448 for (
auto& pair :
limb)
450 auto& arm = pair.second;
451 arm->bufferConfigUserToNonRt.reinitAllBuffers(arm->nonRtConfig);
453 for (
auto& pair :
limb)
455 userConfig.limbs.at(pair.first) = pair.second->nonRtConfig;