5 #include <VirtualRobot/Nodes/RobotNode.h>
6 #include <VirtualRobot/Robot.h>
16 #include <RobotAPI/interface/visualization/DebugDrawerInterface.h>
21 operator<<(std::ostream& out,
const NJointCartesianWaypointControllerRuntimeConfig& cfg)
23 out <<
"maxPositionAcceleration " << cfg.wpCfg.maxPositionAcceleration <<
'\n'
24 <<
"maxOrientationAcceleration " << cfg.wpCfg.maxOrientationAcceleration <<
'\n'
25 <<
"maxNullspaceAcceleration " << cfg.wpCfg.maxNullspaceAcceleration <<
'\n'
27 <<
"kpJointLimitAvoidance " << cfg.wpCfg.kpJointLimitAvoidance <<
'\n'
28 <<
"jointLimitAvoidanceScale " << cfg.wpCfg.jointLimitAvoidanceScale <<
'\n'
30 <<
"thresholdPositionNear " << cfg.wpCfg.thresholdPositionNear <<
'\n'
31 <<
"thresholdPositionReached " << cfg.wpCfg.thresholdPositionReached <<
'\n'
32 <<
"maxPosVel " << cfg.wpCfg.maxPosVel <<
'\n'
33 <<
"kpPos " << cfg.wpCfg.kpPos <<
'\n'
35 <<
"thresholdOrientationNear " << cfg.wpCfg.thresholdOrientationNear <<
'\n'
36 <<
"thresholdOrientationReached " << cfg.wpCfg.thresholdOrientationReached <<
'\n'
37 <<
"maxOriVel " << cfg.wpCfg.maxOriVel <<
'\n'
38 <<
"kpOri " << cfg.wpCfg.kpOri <<
'\n'
40 <<
"forceThreshold " << cfg.forceThreshold <<
'\n';
44 NJointControllerRegistration<NJointCartesianWaypointController>
46 "NJointCartesianWaypointController");
51 return "NJointCartesianWaypointController";
56 const NJointCartesianWaypointControllerConfigPtr& config,
66 _rtRns = _rtRobot->getRobotNodeSet(config->rns);
68 _rtTcp = _rtRns->getTCP();
71 _rtRobotRoot = _rtRobot->getRootNode();
76 if (!config->ftName.empty())
78 const auto svalFT = useSensorValue<SensorValueForceTorque>(config->ftName);
80 _rtForceSensor = &(svalFT->force);
81 _rtTorqueSensor = &(svalFT->force);
86 const auto reportFrameName = sdev->getReportingFrame();
88 <<
VAROUT(sdev->getReportingFrame());
90 _rtFT = _rtRobot->getRobotNode(reportFrameName);
92 <<
"No sensor report frame '" << reportFrameName <<
"' in robot";
97 _rtJointVelocityFeedbackBuffer =
98 Eigen::VectorXf::Zero(
static_cast<int>(_rtRns->getSize()));
100 VirtualRobot::RobotNodePtr referenceFrame =
nullptr;
101 if (!config->referenceFrameName.empty())
103 referenceFrame = _rtRobot->getRobotNode(config->referenceFrameName);
105 <<
"No node with name '" << config->referenceFrameName
106 <<
"' for referenceFrame in robot";
109 _rtWpController = std::make_unique<CartesianWaypointController>(
111 _rtJointVelocityFeedbackBuffer,
112 config->runCfg.wpCfg.maxPositionAcceleration,
113 config->runCfg.wpCfg.maxOrientationAcceleration,
114 config->runCfg.wpCfg.maxNullspaceAcceleration,
118 _rtWpController->setConfig({});
120 for (
size_t i = 0; i < _rtRns->getSize(); ++i)
122 std::string jointName = _rtRns->getNode(i)->getName();
123 auto ct = useControlTarget<ControlTarget1DoFActuatorVelocity>(
124 jointName, ControlModes::Velocity1DoF);
125 auto sv = useSensorValue<SensorValue1DoFActuatorVelocity>(jointName);
129 _rtVelTargets.emplace_back(&(ct->velocity));
130 _rtVelSensors.emplace_back(&(sv->velocity));
143 _publishIsAtTarget =
false;
144 _rtForceOffset = Eigen::Vector3f::Zero();
146 _publishErrorPos = 0;
147 _publishErrorOri = 0;
148 _publishErrorPosMax = 0;
149 _publishErrorOriMax = 0;
150 _publishForceThreshold = _rtForceThreshold;
154 #pragma GCC diagnostic push
155 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
156 for (std::size_t idx = 0; idx < _rtVelSensors.size(); ++idx)
158 const float* ptr = _rtVelSensors[idx];
159 _rtJointVelocityFeedbackBuffer(idx) = *ptr;
161 _rtWpController->setCurrentJointVelocity(_rtJointVelocityFeedbackBuffer);
162 #pragma GCC diagnostic pop
178 r.cfgUpdated =
false;
179 _rtWpController->setConfig(r.cfg.wpCfg);
180 _rtForceThreshold = r.cfg.forceThreshold;
181 _publishForceThreshold = _rtForceThreshold;
182 _rtOptimizeNullspaceIfTargetWasReached = r.cfg.optimizeNullspaceIfTargetWasReached;
183 _rtForceThresholdInRobotRootZ = r.cfg.forceThresholdInRobotRootZ;
184 _publishForceThresholdInRobotRootZ = r.cfg.forceThresholdInRobotRootZ;
189 _rtStopConditionReached =
false;
190 _publishIsAtTarget =
false;
191 r.wpsUpdated =
false;
193 _publishWpsNum = r.wps.size();
194 _rtHasWps = !r.wps.empty();
195 _rtWpController->swapWaypoints(r.wps);
196 if (r.cfg.skipToClosestWaypoint)
198 _rtWpController->skipToClosestWaypoint(r.skipRad2mmFactor);
201 _publishIsAtForceLimit =
false;
204 bool reachedTarget =
false;
205 bool reachedFtLimit =
false;
209 const Eigen::Vector3f ftInRoot =
210 _rtFT->getTransformationTo(_rtRobotRoot).topLeftCorner<3, 3>().
transpose() *
212 rt2nonrtBuf.ft.force = ftInRoot;
213 rt2nonrtBuf.ft.torque = *_rtTorqueSensor;
214 rt2nonrtBuf.ft.timestampInUs = sensorValuesTimestamp.toMicroSeconds();
215 rt2nonrtBuf.ftInRoot = _rtFT->getPoseInRootFrame();
217 Eigen::Vector3f ftVal = ftInRoot;
218 if (_rtForceThresholdInRobotRootZ)
225 _rtForceOffset = ftVal;
226 _setFTOffset =
false;
227 _publishIsAtForceLimit =
false;
229 rt2nonrtBuf.ftUsed = ftVal;
231 const float currentForce =
std::abs(ftVal.norm() - _rtForceOffset.norm());
233 reachedFtLimit = (_rtForceThreshold >= 0) && currentForce > _rtForceThreshold;
234 _publishForceCurrent = currentForce;
235 _publishIsAtForceLimit = _publishIsAtForceLimit || reachedFtLimit;
238 _publishWpsCur = _rtHasWps ? _rtWpController->currentWaypointIndex : 0;
240 rt2nonrtBuf.rootPose = _rtRobot->getGlobalPose();
241 rt2nonrtBuf.tcp = _rtTcp->getPoseInRootFrame();
244 const float errorPos = _rtWpController->getPositionError();
245 const float errorOri = _rtWpController->getOrientationError();
247 _publishErrorPos = errorPos;
248 _publishErrorOri = errorOri;
249 if (!_rtWpController->isLastWaypoint())
251 _publishErrorPosMax = _rtWpController->thresholdPositionNear;
252 _publishErrorOriMax = _rtWpController->thresholdOrientationNear;
256 _publishErrorPosMax = _rtWpController->thresholdPositionReached;
257 _publishErrorOriMax = _rtWpController->thresholdOrientationReached;
258 reachedTarget = (errorPos < _rtWpController->thresholdPositionReached) &&
259 (errorOri < _rtWpController->thresholdOrientationReached);
261 rt2nonrtBuf.tcpTarg = _rtWpController->getCurrentTarget();
265 rt2nonrtBuf.tcpTarg = rt2nonrtBuf.tcp;
267 _rtStopConditionReached = _rtStopConditionReached || reachedFtLimit ||
268 (reachedTarget && !_rtOptimizeNullspaceIfTargetWasReached);
269 _publishIsAtTarget = _publishIsAtTarget || reachedTarget;
270 if (!_rtHasWps || _rtStopConditionReached)
276 const Eigen::VectorXf& goal =
277 _rtWpController->calculate(timeSinceLastIteration.toSecondsDouble());
280 for (std::size_t idx = 0; idx < _rtVelTargets.size(); ++idx)
282 float* ptr = _rtVelTargets[idx];
288 _tripRt2NonRtRobotGP.
getWriteBuffer() = _rtRobot->getGlobalPose();
300 return _publishIsAtTarget;
305 const NJointCartesianWaypointControllerRuntimeConfig& cfg,
308 std::lock_guard g{_tripBufWpCtrlMut};
320 std::lock_guard g{_tripBufWpCtrlMut};
331 std::lock_guard g{_tripBufWpCtrlMut};
335 w.wps.emplace_back(wp);
344 std::lock_guard g{_tripBufWpCtrlMut};
348 w.wps.emplace_back(wp);
355 const NJointCartesianWaypointControllerRuntimeConfig& cfg,
356 const std::vector<Eigen::Matrix4f>& wps,
359 std::lock_guard g{_tripBufWpCtrlMut};
366 ARMARX_IMPORTANT <<
"set new config\n" << cfg <<
" and new waypoints\n" << wps;
371 const NJointCartesianWaypointControllerRuntimeConfig& cfg,
375 std::lock_guard g{_tripBufWpCtrlMut};
381 w.wps.emplace_back(wp);
383 ARMARX_IMPORTANT <<
"set new config\n" << cfg <<
"and a new waypoint\n" << wp;
387 NJointCartesianWaypointController::setNullVelocity()
389 for (
auto ptr : _rtVelTargets)
399 return _publishIsAtForceLimit;
406 std::lock_guard g{_tripRt2NonRtMutex};
433 std::lock_guard g{_tripBufWpCtrlMut};
436 w.cfgUpdated =
false;
447 const std::size_t wpsNum = _publishWpsNum;
448 const std::size_t wpsCur = wpsNum ? _publishWpsCur + 1 : 0;
450 const float errorPos = _publishErrorPos;
451 const float errorOri = _publishErrorOri;
452 const float errorPosMax = _publishErrorPosMax;
453 const float errorOriMax = _publishErrorOriMax;
454 const float forceThreshold = _publishForceThreshold;
455 const float forceCurrent = _publishForceCurrent;
459 datafields[
"WpNum"] =
new Variant(
static_cast<int>(wpsNum));
460 datafields[
"WpCur"] =
new Variant(
static_cast<int>(wpsCur));
462 datafields[
"errorPos"] =
new Variant(errorPos);
463 datafields[
"errorOri"] =
new Variant(errorOri);
464 datafields[
"errorPosMax"] =
new Variant(errorPosMax);
465 datafields[
"errorOriMax"] =
new Variant(errorOriMax);
467 datafields[
"forceThreshold"] =
new Variant(forceThreshold);
468 datafields[
"forceCurrent"] =
new Variant(forceCurrent);
474 <<
" / " << wpsNum <<
" (last " << _publishIsAtTarget <<
", ft limit "
475 << _publishIsAtForceLimit <<
", perror " << errorPos <<
" / " << errorPosMax
476 <<
", oerror " << errorOri <<
" / " << errorOriMax <<
')';
479 std::lock_guard g{_tripRt2NonRtMutex};
485 if (buf.tcp != buf.tcpTarg)
489 drawer->setPoseVisu(
getName(),
"tcp",
new Pose(gtcp));
490 drawer->setPoseVisu(
getName(),
"tcptarg",
new Pose(gtcptarg));
493 new Vector3(Eigen::Vector3f{gtcp.topRightCorner<3, 1>()}),
494 new Vector3(Eigen::Vector3f{gtcptarg.topRightCorner<3, 1>()}),
500 drawer->removePoseVisu(
getName(),
"tcp");
501 drawer->removePoseVisu(
getName(),
"tcptarg");
502 drawer->removeLineVisu(
getName(),
"tcp2targ");
508 drawer->setArrowVisu(
getName(),
511 new Vector3{buf.ft.force.normalized()},
515 drawer->setArrowVisu(
getName(),
518 new Vector3{buf.ftUsed.normalized()},
529 return _publishWpsCur;