11 const RobotUnitPtr& robUnit,
12 const armarx::NJointControllerConfigPtr& config,
15 ARMARX_INFO <<
"creating periodic task-space impedance dmp controller";
18 cfg = DeprecatedNJointPeriodicTSDMPCompliantControllerConfigPtr::dynamicCast(config);
21 VirtualRobot::RobotNodeSetPtr rns =
rtGetRobot()->getRobotNodeSet(cfg->nodeSetName);
23 for (
size_t i = 0; i < rns->getSize(); ++i)
25 std::string jointName = rns->getNode(i)->getName();
29 targets.push_back(ct->
asA<ControlTarget1DoFActuatorTorque>());
31 const SensorValue1DoFActuatorVelocity* velocitySensor = sv->
asA<SensorValue1DoFActuatorVelocity>();
32 const SensorValue1DoFActuatorPosition* positionSensor = sv->
asA<SensorValue1DoFActuatorPosition>();
43 velocitySensors.push_back(velocitySensor);
44 positionSensors.push_back(positionSensor);
48 ik.reset(
new VirtualRobot::DifferentialIK(rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
49 ik->setDampedSvdLambda(0.0001);
50 numOfJoints = targets.size();
51 qvel_filtered.setZero(targets.size());
52 torqueLimit = cfg->jointTorqueLimit;
55 const SensorValueBase* svlf = robUnit->getSensorDevice(cfg->forceSensorName)->getSensorValue();
59 Eigen::Vector3f tcpCoMInForceSensorFrame;
60 tcpCoMInForceSensorFrame.setZero();
62 enableTCPGravityCompensation.store(cfg->enableTCPGravityCompensation);
64 if (enableTCPGravityCompensation.load())
66 tcpMass = cfg->tcpMass;
67 tcpCoMInForceSensorFrame = cfg->tcpCoMInForceSensorFrame;
70 forceOffset.setZero();
71 torqueOffset.setZero();
72 filteredForce.setZero();
73 filteredTorque.setZero();
74 filteredForceInRoot.setZero();
75 filteredTorqueInRoot.setZero();
78 toolFrameInRoot = cfg->toolFrameInRoot;
79 forcePID.reset(
new PIDController(cfg->pidForce[0], cfg->pidForce[1], cfg->pidForce[2], cfg->pidForce[3]));
86 taskSpaceDMPConfig.
DMPMode =
"Linear";
87 taskSpaceDMPConfig.
DMPStyle =
"Periodic";
99 kinematic_chain = cfg->nodeSetName;
111 CtrlParams initParams =
113 cfg->kpImpedance, cfg->kdImpedance,
114 cfg->Knull, cfg->Dnull,
116 tcpMass, tcpCoMInForceSensorFrame
126 if (!cfg->ignoreWSLimitChecks)
156 RT2InterfaceData rt2InterfaceData;
157 rt2InterfaceData.currentTcpPose = tcp->getPoseInRootFrame();
158 rt2InterfaceData.waitTimeForCalibration = 0;
163 rt2MPData.deltaT = 0;
164 rt2MPData.currentTime = 0;
165 rt2MPData.currentPose = tcp->getPoseInRootFrame();
166 rt2MPData.currentTwist.setZero();
167 rt2MPData.isPhaseStop =
false;
177 runTask(
"DeprecatedNJointPeriodicTSDMPCompliantController", [&]
181 while (
getState() == eManagedIceObjectStarted)
187 c.waitForCycleDuration();
196 return "DeprecatedNJointPeriodicTSDMPCompliantController";
208 if (!isPhaseStop && mpRunning.load())
216 dmpCtrl->flow(deltaT, currentPose, currentTwist);
218 targetVels = dmpCtrl->getTargetVelocity();
220 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_x"] = currentPose(0, 3);
221 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_y"] = currentPose(1, 3);
222 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_z"] = currentPose(2, 3);
224 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_qw"] = currentQ.w;
225 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_qx"] = currentQ.x;
226 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_qy"] = currentQ.y;
227 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_qz"] = currentQ.z;
228 debugMPBuffer.
getWriteBuffer().currentCanVal = dmpCtrl->debugData.canVal;
229 debugMPBuffer.
getWriteBuffer().mpcFactor = dmpCtrl->debugData.mpcFactor;
230 debugMPBuffer.
getWriteBuffer().error = dmpCtrl->debugData.poseError;
231 debugMPBuffer.
getWriteBuffer().posError = dmpCtrl->debugData.posiError;
232 debugMPBuffer.
getWriteBuffer().oriError = dmpCtrl->debugData.oriError;
253 debugMPBuffer.
getWriteBuffer().latestTargetVelocities[
"x_vel"] = targetVels(0);
254 debugMPBuffer.
getWriteBuffer().latestTargetVelocities[
"y_vel"] = targetVels(1);
255 debugMPBuffer.
getWriteBuffer().latestTargetVelocities[
"z_vel"] = targetVels(2);
256 debugMPBuffer.
getWriteBuffer().latestTargetVelocities[
"roll_vel"] = targetVels(3);
257 debugMPBuffer.
getWriteBuffer().latestTargetVelocities[
"pitch_vel"] = targetVels(4);
258 debugMPBuffer.
getWriteBuffer().latestTargetVelocities[
"yaw_vel"] = targetVels(5);
268 Eigen::MatrixXf jacobi = ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All);
270 Eigen::VectorXf qpos(positionSensors.size());
271 Eigen::VectorXf qvel(velocitySensors.size());
272 for (
size_t i = 0; i < positionSensors.size(); ++i)
274 qpos(i) = positionSensors[i]->position;
275 qvel(i) = velocitySensors[i]->velocity;
277 qvel_filtered = (1 - cfg->qvelFilter) * qvel_filtered + cfg->qvelFilter * qvel;
278 Eigen::VectorXf currentTwist = jacobi * qvel_filtered;
279 jacobi.block(0, 0, 3, numOfJoints) = 0.001 * jacobi.block(0, 0, 3, numOfJoints);
281 double deltaT = timeSinceLastIteration.toSecondsDouble();
289 forcePID->Kp = pidForce(0);
290 forcePID->Ki = pidForce(1);
291 forcePID->Kd = pidForce(2);
292 forcePID->maxControlValue = pidForce(3);
299 Eigen::Vector3f forceBaseline = Eigen::Vector3f::Zero();
300 Eigen::Vector3f torqueBaseline = Eigen::Vector3f::Zero();
303 forceTorque.setZero();
304 tcpGravityCompensation.setZero();
309 Eigen::VectorXf targetNullSpaceJointValues =
rtGetControlStruct().targetNullSpaceJointValues;
310 Eigen::Vector3f targetVelInTool = Eigen::Vector3f::Zero();
313 float targetForce = 0.0f;
314 if (rtFirstRun.load())
316 rtReady.store(
false);
317 rtFirstRun.store(
false);
318 timeForCalibration = 0;
319 forceOffset.setZero();
320 torqueOffset.setZero();
324 forceFrameInTCP.block<3, 3>(0, 0) = currentPose.block<3, 3>(0, 0).transpose() * forceFrameInRoot.block<3, 3>(0, 0);
325 tcpCoMInTCPFrame = forceFrameInTCP.block<3, 3>(0, 0) * tcpCoMInFTFrame;
327 targetPose = currentPose;
328 previousTargetPose = currentPose;
329 toolOriInHand = currentPose.block<3, 3>(0, 0).
transpose() * toolFrameInRoot.block<3, 3>(0, 0);
339 if (enableTCPGravityCompensation.load())
345 targetPose = previousTargetPose;
346 forceOffset = (1 - cfg->forceFilter) * forceOffset + cfg->forceFilter * (forceSensor->
force - tcpGravityCompensation.head(3));
347 torqueOffset = (1 - cfg->forceFilter) * torqueOffset + cfg->forceFilter * (forceSensor->
torque - tcpGravityCompensation.tail(3));
348 timeForCalibration = timeForCalibration + deltaT;
349 if (timeForCalibration > cfg->waitTimeForCalibration)
359 currentToolOriInRoot = currentPose.block<3, 3>(0, 0) * toolOriInHand;
361 Eigen::VectorXf ftInTool = forceTorque;
362 ftInTool.head(3) = currentToolOriInRoot.transpose() * ftInTool.head(3);
368 forcePID->update(deltaT, ftInTool(2), targetForce);
369 float forcePIDVel = -1000.0f * (
float)forcePID->getControlValue();
371 targetVelInTool(2) = forcePIDVel;
372 targetVel.head(3) += currentToolOriInRoot * targetVelInTool;
375 targetPose.block<3, 1>(0, 3) = targetPose.block<3, 1>(0, 3) + (
float)deltaT * targetVel.block<3, 1>(0, 0);
376 if ((previousTargetPose.block<3, 1>(0, 3) - targetPose.block<3, 1>(0, 3)).norm() > 100.0f)
379 targetPose = previousTargetPose;
381 previousTargetPose = targetPose;
385 bool isPhaseStop =
false;
386 float diff = (targetPose.block<2, 1>(0, 3) - currentPose.block<2, 1>(0, 3)).
norm();
387 if (diff > cfg->phaseDist0)
394 Eigen::Vector2f currentXY = currentPose.block<2, 1>(0, 3);
395 if ((lastPosition - currentXY).norm() < cfg->changePositionTolerance)
397 changeTimer += deltaT;
401 lastPosition = currentPose.block<2, 1>(0, 3);
405 if (changeTimer > cfg->changeTimerThreshold)
407 targetPose(0, 3) = currentPose(0, 3);
408 targetPose(1, 3) = currentPose(1, 3);
418 targetPose(0, 3) =
std::clamp(targetPose(0, 3), cfg->ws_x[0], cfg->ws_x[1]);
419 targetPose(1, 3) =
std::clamp(targetPose(1, 3), cfg->ws_y[0], cfg->ws_y[1]);
420 targetPose(2, 3) =
std::clamp(targetPose(2, 3), cfg->ws_z[0], cfg->ws_z[1]);
425 rt2InterfaceBuffer.
getWriteBuffer().waitTimeForCalibration += deltaT;
430 debugRTBuffer.
getWriteBuffer().filteredForce = filteredForceInRoot;
448 Eigen::Matrix3f diffMat = targetPose.block<3, 3>(0, 0) * currentPose.block<3, 3>(0, 0).transpose();
449 poseErrorImp.head(3) = 0.001 * (targetPose.block<3, 1>(0, 3) - currentPose.block<3, 1>(0, 3));
450 currentTwist.head(3) *= 0.001;
451 poseErrorImp.tail(3) = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
452 Eigen::Vector6f forceImpedance = kpImpedance.cwiseProduct(poseErrorImp) - kdImpedance.cwiseProduct(currentTwist);
455 Eigen::VectorXf nullspaceTorque = knull.cwiseProduct(targetNullSpaceJointValues - qpos) - dnull.cwiseProduct(qvel);
459 Eigen::MatrixXf jtpinv = ik->computePseudoInverseJacobianMatrix(jacobi.transpose(), 2.0);
460 Eigen::VectorXf jointDesiredTorques = jacobi.transpose() * forceImpedance + (I - jacobi.transpose() * jtpinv) * nullspaceTorque;
464 for (
size_t i = 0; i < targets.size(); ++i)
466 targets.at(i)->torque = jointDesiredTorques(i);
467 if (!targets.at(i)->isValid() || isnan(targets.at(i)->torque))
469 targets.at(i)->torque = 0.0f;
473 if (fabs(targets.at(i)->torque) > fabs(torqueLimit))
475 targets.at(i)->torque = fabs(torqueLimit) * (targets.at(i)->torque / fabs(targets.at(i)->torque));
486 Eigen::Vector3f gravity;
487 gravity << 0.0, 0.0, -9.8;
488 Eigen::Vector3f localGravity = currentPose.block<3, 3>(0, 0).
transpose() * gravity;
489 Eigen::Vector3f localForceVec = tcpMass * localGravity;
490 Eigen::Vector3f localTorqueVec = tcpCoMInTCPFrame.cross(localForceVec);
493 tcpGravityCompensation << localForceVec, localTorqueVec;
494 return tcpGravityCompensation;
499 filteredForce = (1 - cfg->forceFilter) * filteredForce + cfg->forceFilter * forceSensor->
force;
500 filteredTorque = (1 - cfg->forceFilter) * filteredTorque + cfg->forceFilter * forceSensor->
torque;
503 filteredForceInRoot = forceFrameInRoot.block<3, 3>(0, 0) * (filteredForce - forceOffset - handCompensatedFT.head(3)) - forceBaseline;
504 filteredTorqueInRoot = forceFrameInRoot.block<3, 3>(0, 0) * (filteredTorque - torqueOffset - handCompensatedFT.tail(3)) - torqueBaseline;
506 for (
size_t i = 0; i < 3; ++i)
508 if (fabs(filteredForceInRoot(i)) > cfg->forceDeadZone)
510 filteredForceInRoot(i) -= (filteredForceInRoot(i) / fabs(filteredForceInRoot(i))) * cfg->forceDeadZone;
514 filteredForceInRoot(i) = 0;
517 if (fabs(filteredTorqueInRoot(i)) > cfg->torqueDeadZone)
519 filteredTorqueInRoot(i) -= (filteredTorqueInRoot(i) / fabs(filteredTorqueInRoot(i))) * cfg->torqueDeadZone;
523 filteredTorqueInRoot(i) = 0;
528 forceTorque << filteredForceInRoot, filteredTorqueInRoot;
548 return kinematic_chain;
556 dmpCtrl->learnDMPFromFiles(fileNames);
564 TrajectoryPtr dmpTraj = TrajectoryPtr::dynamicCast(trajectory);
568 dmpCtrl->learnDMPFromTrajectory(dmpTraj);
580 dmpCtrl->setSpeed(times);
587 dmpCtrl->setGoalPoseVec(goals);
593 dmpCtrl->setAmplitude(amp);
605 rtFirstRun.store(
true);
606 while (rtFirstRun.load() || !rtReady.load() || !rt2InterfaceBuffer.
updateReadBuffer())
614 dmpCtrl->prepareExecution(dmpCtrl->eigen4f2vec(pose), goals);
615 dmpCtrl->setSpeed(tau);
617 mpRunning.store(
true);
618 dmpCtrl->resumeController();
624 return dmpCtrl->canVal;
631 if (mpRunning.load())
640 mpRunning.store(
false);
648 dmpCtrl->pauseController();
653 dmpCtrl->resumeController();
660 std::string datafieldName;
661 std::string debugName =
"Periodic";
665 datafields[
"target_x"] =
new Variant(targetPoseDebug(0, 3));
666 datafields[
"target_y"] =
new Variant(targetPoseDebug(1, 3));
667 datafields[
"target_z"] =
new Variant(targetPoseDebug(2, 3));
670 datafields[
"targetVelInTool_x"] =
new Variant(targetVelInTool(0));
671 datafields[
"targetVelInTool_y"] =
new Variant(targetVelInTool(1));
672 datafields[
"targetVelInTool_z"] =
new Variant(targetVelInTool(2));
675 datafields[
"current_x"] =
new Variant(currentPoseDebug(0, 3));
676 datafields[
"current_y"] =
new Variant(currentPoseDebug(1, 3));
677 datafields[
"current_z"] =
new Variant(currentPoseDebug(2, 3));
680 datafields[
"filteredforce_x"] =
new Variant(filteredForce(0));
681 datafields[
"filteredforce_y"] =
new Variant(filteredForce(1));
682 datafields[
"filteredforce_z"] =
new Variant(filteredForce(2));
686 datafields[
"reactForce_x"] =
new Variant(reactForce(0));
687 datafields[
"reactForce_y"] =
new Variant(reactForce(1));
688 datafields[
"reactForce_z"] =
new Variant(reactForce(2));
691 datafields[
"targetVel_x"] =
new Variant(targetVel(0));
692 datafields[
"targetVel_y"] =
new Variant(targetVel(1));
693 datafields[
"targetVel_z"] =
new Variant(targetVel(2));
732 datafieldName =
"PeriodicDMP";
733 debugObs->setDebugChannel(datafieldName, datafields);