13 #include <RobotAPI/interface/visualization/DebugDrawerInterface.h>
18 operator<<(std::ostream& out,
const NJointCartesianWaypointControllerRuntimeConfig& cfg)
20 out <<
"maxPositionAcceleration " << cfg.wpCfg.maxPositionAcceleration <<
'\n'
21 <<
"maxOrientationAcceleration " << cfg.wpCfg.maxOrientationAcceleration <<
'\n'
22 <<
"maxNullspaceAcceleration " << cfg.wpCfg.maxNullspaceAcceleration <<
'\n'
24 <<
"kpJointLimitAvoidance " << cfg.wpCfg.kpJointLimitAvoidance <<
'\n'
25 <<
"jointLimitAvoidanceScale " << cfg.wpCfg.jointLimitAvoidanceScale <<
'\n'
27 <<
"thresholdPositionNear " << cfg.wpCfg.thresholdPositionNear <<
'\n'
28 <<
"thresholdPositionReached " << cfg.wpCfg.thresholdPositionReached <<
'\n'
29 <<
"maxPosVel " << cfg.wpCfg.maxPosVel <<
'\n'
30 <<
"kpPos " << cfg.wpCfg.kpPos <<
'\n'
32 <<
"thresholdOrientationNear " << cfg.wpCfg.thresholdOrientationNear <<
'\n'
33 <<
"thresholdOrientationReached " << cfg.wpCfg.thresholdOrientationReached <<
'\n'
34 <<
"maxOriVel " << cfg.wpCfg.maxOriVel <<
'\n'
35 <<
"kpOri " << cfg.wpCfg.kpOri <<
'\n'
37 <<
"forceThreshold " << cfg.forceThreshold <<
'\n';
41 NJointControllerRegistration<NJointCartesianWaypointController>
43 "NJointCartesianWaypointController");
48 return "NJointCartesianWaypointController";
53 const NJointCartesianWaypointControllerConfigPtr& config,
63 _rtRns = _rtRobot->getRobotNodeSet(config->rns);
65 _rtTcp = _rtRns->getTCP();
68 _rtRobotRoot = _rtRobot->getRootNode();
73 if (!config->ftName.empty())
75 const auto svalFT = useSensorValue<SensorValueForceTorque>(config->ftName);
77 _rtForceSensor = &(svalFT->force);
78 _rtTorqueSensor = &(svalFT->force);
83 const auto reportFrameName = sdev->getReportingFrame();
85 <<
VAROUT(sdev->getReportingFrame());
87 _rtFT = _rtRobot->getRobotNode(reportFrameName);
89 <<
"No sensor report frame '" << reportFrameName <<
"' in robot";
94 _rtJointVelocityFeedbackBuffer =
95 Eigen::VectorXf::Zero(
static_cast<int>(_rtRns->getSize()));
97 VirtualRobot::RobotNodePtr referenceFrame =
nullptr;
98 if (!config->referenceFrameName.empty())
100 referenceFrame = _rtRobot->getRobotNode(config->referenceFrameName);
102 <<
"No node with name '" << config->referenceFrameName
103 <<
"' for referenceFrame in robot";
106 _rtWpController = std::make_unique<CartesianWaypointController>(
108 _rtJointVelocityFeedbackBuffer,
109 config->runCfg.wpCfg.maxPositionAcceleration,
110 config->runCfg.wpCfg.maxOrientationAcceleration,
111 config->runCfg.wpCfg.maxNullspaceAcceleration,
115 _rtWpController->setConfig({});
117 for (
size_t i = 0; i < _rtRns->getSize(); ++i)
119 std::string jointName = _rtRns->getNode(i)->getName();
120 auto ct = useControlTarget<ControlTarget1DoFActuatorVelocity>(
121 jointName, ControlModes::Velocity1DoF);
122 auto sv = useSensorValue<SensorValue1DoFActuatorVelocity>(jointName);
126 _rtVelTargets.emplace_back(&(ct->velocity));
127 _rtVelSensors.emplace_back(&(sv->velocity));
140 _publishIsAtTarget =
false;
141 _rtForceOffset = Eigen::Vector3f::Zero();
143 _publishErrorPos = 0;
144 _publishErrorOri = 0;
145 _publishErrorPosMax = 0;
146 _publishErrorOriMax = 0;
147 _publishForceThreshold = _rtForceThreshold;
151 #pragma GCC diagnostic push
152 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
153 for (std::size_t idx = 0; idx < _rtVelSensors.size(); ++idx)
155 const float* ptr = _rtVelSensors[idx];
156 _rtJointVelocityFeedbackBuffer(idx) = *ptr;
158 _rtWpController->setCurrentJointVelocity(_rtJointVelocityFeedbackBuffer);
159 #pragma GCC diagnostic pop
175 r.cfgUpdated =
false;
176 _rtWpController->setConfig(r.cfg.wpCfg);
177 _rtForceThreshold = r.cfg.forceThreshold;
178 _publishForceThreshold = _rtForceThreshold;
179 _rtOptimizeNullspaceIfTargetWasReached = r.cfg.optimizeNullspaceIfTargetWasReached;
180 _rtForceThresholdInRobotRootZ = r.cfg.forceThresholdInRobotRootZ;
181 _publishForceThresholdInRobotRootZ = r.cfg.forceThresholdInRobotRootZ;
186 _rtStopConditionReached =
false;
187 _publishIsAtTarget =
false;
188 r.wpsUpdated =
false;
190 _publishWpsNum = r.wps.size();
191 _rtHasWps = !r.wps.empty();
192 _rtWpController->swapWaypoints(r.wps);
193 if (r.cfg.skipToClosestWaypoint)
195 _rtWpController->skipToClosestWaypoint(r.skipRad2mmFactor);
198 _publishIsAtForceLimit =
false;
201 bool reachedTarget =
false;
202 bool reachedFtLimit =
false;
206 const Eigen::Vector3f ftInRoot =
207 _rtFT->getTransformationTo(_rtRobotRoot).topLeftCorner<3, 3>().
transpose() *
209 rt2nonrtBuf.ft.force = ftInRoot;
210 rt2nonrtBuf.ft.torque = *_rtTorqueSensor;
211 rt2nonrtBuf.ft.timestampInUs = sensorValuesTimestamp.toMicroSeconds();
212 rt2nonrtBuf.ftInRoot = _rtFT->getPoseInRootFrame();
214 Eigen::Vector3f ftVal = ftInRoot;
215 if (_rtForceThresholdInRobotRootZ)
222 _rtForceOffset = ftVal;
223 _setFTOffset =
false;
224 _publishIsAtForceLimit =
false;
226 rt2nonrtBuf.ftUsed = ftVal;
228 const float currentForce =
std::abs(ftVal.norm() - _rtForceOffset.norm());
230 reachedFtLimit = (_rtForceThreshold >= 0) && currentForce > _rtForceThreshold;
231 _publishForceCurrent = currentForce;
232 _publishIsAtForceLimit = _publishIsAtForceLimit || reachedFtLimit;
235 _publishWpsCur = _rtHasWps ? _rtWpController->currentWaypointIndex : 0;
237 rt2nonrtBuf.rootPose = _rtRobot->getGlobalPose();
238 rt2nonrtBuf.tcp = _rtTcp->getPoseInRootFrame();
241 const float errorPos = _rtWpController->getPositionError();
242 const float errorOri = _rtWpController->getOrientationError();
244 _publishErrorPos = errorPos;
245 _publishErrorOri = errorOri;
246 if (!_rtWpController->isLastWaypoint())
248 _publishErrorPosMax = _rtWpController->thresholdPositionNear;
249 _publishErrorOriMax = _rtWpController->thresholdOrientationNear;
253 _publishErrorPosMax = _rtWpController->thresholdPositionReached;
254 _publishErrorOriMax = _rtWpController->thresholdOrientationReached;
255 reachedTarget = (errorPos < _rtWpController->thresholdPositionReached) &&
256 (errorOri < _rtWpController->thresholdOrientationReached);
258 rt2nonrtBuf.tcpTarg = _rtWpController->getCurrentTarget();
262 rt2nonrtBuf.tcpTarg = rt2nonrtBuf.tcp;
264 _rtStopConditionReached = _rtStopConditionReached || reachedFtLimit ||
265 (reachedTarget && !_rtOptimizeNullspaceIfTargetWasReached);
266 _publishIsAtTarget = _publishIsAtTarget || reachedTarget;
267 if (!_rtHasWps || _rtStopConditionReached)
273 const Eigen::VectorXf& goal =
274 _rtWpController->calculate(timeSinceLastIteration.toSecondsDouble());
277 for (std::size_t idx = 0; idx < _rtVelTargets.size(); ++idx)
279 float* ptr = _rtVelTargets[idx];
285 _tripRt2NonRtRobotGP.
getWriteBuffer() = _rtRobot->getGlobalPose();
297 return _publishIsAtTarget;
302 const NJointCartesianWaypointControllerRuntimeConfig& cfg,
305 std::lock_guard g{_tripBufWpCtrlMut};
317 std::lock_guard g{_tripBufWpCtrlMut};
328 std::lock_guard g{_tripBufWpCtrlMut};
332 w.wps.emplace_back(wp);
341 std::lock_guard g{_tripBufWpCtrlMut};
345 w.wps.emplace_back(wp);
352 const NJointCartesianWaypointControllerRuntimeConfig& cfg,
353 const std::vector<Eigen::Matrix4f>& wps,
356 std::lock_guard g{_tripBufWpCtrlMut};
363 ARMARX_IMPORTANT <<
"set new config\n" << cfg <<
" and new waypoints\n" << wps;
368 const NJointCartesianWaypointControllerRuntimeConfig& cfg,
372 std::lock_guard g{_tripBufWpCtrlMut};
378 w.wps.emplace_back(wp);
380 ARMARX_IMPORTANT <<
"set new config\n" << cfg <<
"and a new waypoint\n" << wp;
384 NJointCartesianWaypointController::setNullVelocity()
386 for (
auto ptr : _rtVelTargets)
396 return _publishIsAtForceLimit;
403 std::lock_guard g{_tripRt2NonRtMutex};
430 std::lock_guard g{_tripBufWpCtrlMut};
433 w.cfgUpdated =
false;
444 const std::size_t wpsNum = _publishWpsNum;
445 const std::size_t wpsCur = wpsNum ? _publishWpsCur + 1 : 0;
447 const float errorPos = _publishErrorPos;
448 const float errorOri = _publishErrorOri;
449 const float errorPosMax = _publishErrorPosMax;
450 const float errorOriMax = _publishErrorOriMax;
451 const float forceThreshold = _publishForceThreshold;
452 const float forceCurrent = _publishForceCurrent;
456 datafields[
"WpNum"] =
new Variant(
static_cast<int>(wpsNum));
457 datafields[
"WpCur"] =
new Variant(
static_cast<int>(wpsCur));
459 datafields[
"errorPos"] =
new Variant(errorPos);
460 datafields[
"errorOri"] =
new Variant(errorOri);
461 datafields[
"errorPosMax"] =
new Variant(errorPosMax);
462 datafields[
"errorOriMax"] =
new Variant(errorOriMax);
464 datafields[
"forceThreshold"] =
new Variant(forceThreshold);
465 datafields[
"forceCurrent"] =
new Variant(forceCurrent);
471 <<
" / " << wpsNum <<
" (last " << _publishIsAtTarget <<
", ft limit "
472 << _publishIsAtForceLimit <<
", perror " << errorPos <<
" / " << errorPosMax
473 <<
", oerror " << errorOri <<
" / " << errorOriMax <<
')';
476 std::lock_guard g{_tripRt2NonRtMutex};
482 if (buf.tcp != buf.tcpTarg)
486 drawer->setPoseVisu(
getName(),
"tcp",
new Pose(gtcp));
487 drawer->setPoseVisu(
getName(),
"tcptarg",
new Pose(gtcptarg));
490 new Vector3(Eigen::Vector3f{gtcp.topRightCorner<3, 1>()}),
491 new Vector3(Eigen::Vector3f{gtcptarg.topRightCorner<3, 1>()}),
497 drawer->removePoseVisu(
getName(),
"tcp");
498 drawer->removePoseVisu(
getName(),
"tcptarg");
499 drawer->removeLineVisu(
getName(),
"tcp2targ");
505 drawer->setArrowVisu(
getName(),
508 new Vector3{buf.ft.force.normalized()},
512 drawer->setArrowVisu(
getName(),
515 new Vector3{buf.ftUsed.normalized()},
526 return _publishWpsCur;