3 #include <VirtualRobot/IK/DifferentialIK.h>
4 #include <VirtualRobot/MathTools.h>
5 #include <VirtualRobot/Nodes/RobotNode.h>
6 #include <VirtualRobot/Robot.h>
7 #include <VirtualRobot/RobotNodeSet.h>
24 "DeprecatedNJointPeriodicTSDMPCompliantController");
29 const armarx::NJointControllerConfigPtr& config,
32 ARMARX_INFO <<
"creating periodic task-space impedance dmp controller";
35 cfg = DeprecatedNJointPeriodicTSDMPCompliantControllerConfigPtr::dynamicCast(config);
38 VirtualRobot::RobotNodeSetPtr rns =
rtGetRobot()->getRobotNodeSet(cfg->nodeSetName);
40 for (
size_t i = 0; i < rns->getSize(); ++i)
42 std::string jointName = rns->getNode(i)->getName();
46 targets.push_back(ct->
asA<ControlTarget1DoFActuatorTorque>());
48 const SensorValue1DoFActuatorVelocity* velocitySensor =
49 sv->
asA<SensorValue1DoFActuatorVelocity>();
50 const SensorValue1DoFActuatorPosition* positionSensor =
51 sv->
asA<SensorValue1DoFActuatorPosition>();
62 velocitySensors.push_back(velocitySensor);
63 positionSensors.push_back(positionSensor);
67 ik.reset(
new VirtualRobot::DifferentialIK(
68 rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
69 ik->setDampedSvdLambda(0.0001);
70 numOfJoints = targets.size();
71 qvel_filtered.setZero(targets.size());
72 torqueLimit = cfg->jointTorqueLimit;
76 robUnit->getSensorDevice(cfg->forceSensorName)->getSensorValue();
80 Eigen::Vector3f tcpCoMInForceSensorFrame;
81 tcpCoMInForceSensorFrame.setZero();
83 enableTCPGravityCompensation.store(cfg->enableTCPGravityCompensation);
85 if (enableTCPGravityCompensation.load())
87 tcpMass = cfg->tcpMass;
88 tcpCoMInForceSensorFrame = cfg->tcpCoMInForceSensorFrame;
91 forceOffset.setZero();
92 torqueOffset.setZero();
93 filteredForce.setZero();
94 filteredTorque.setZero();
95 filteredForceInRoot.setZero();
96 filteredTorqueInRoot.setZero();
99 toolFrameInRoot = cfg->toolFrameInRoot;
101 cfg->pidForce[0], cfg->pidForce[1], cfg->pidForce[2], cfg->pidForce[3]));
108 taskSpaceDMPConfig.
DMPMode =
"Linear";
109 taskSpaceDMPConfig.
DMPStyle =
"Periodic";
121 kinematic_chain = cfg->nodeSetName;
133 CtrlParams initParams = {cfg->kpImpedance,
139 tcpCoMInForceSensorFrame};
148 if (!cfg->ignoreWSLimitChecks)
179 RT2InterfaceData rt2InterfaceData;
180 rt2InterfaceData.currentTcpPose = tcp->getPoseInRootFrame();
181 rt2InterfaceData.waitTimeForCalibration = 0;
186 rt2MPData.deltaT = 0;
187 rt2MPData.currentTime = 0;
188 rt2MPData.currentPose = tcp->getPoseInRootFrame();
189 rt2MPData.currentTwist.setZero();
190 rt2MPData.isPhaseStop =
false;
200 runTask(
"DeprecatedNJointPeriodicTSDMPCompliantController",
205 while (
getState() == eManagedIceObjectStarted)
211 c.waitForCycleDuration();
221 return "DeprecatedNJointPeriodicTSDMPCompliantController";
234 if (!isPhaseStop && mpRunning.load())
242 dmpCtrl->flow(deltaT, currentPose, currentTwist);
244 targetVels = dmpCtrl->getTargetVelocity();
246 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_x"] = currentPose(0, 3);
247 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_y"] = currentPose(1, 3);
248 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_z"] = currentPose(2, 3);
250 VirtualRobot::MathTools::eigen4f2quat(currentPose);
251 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_qw"] = currentQ.w;
252 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_qx"] = currentQ.x;
253 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_qy"] = currentQ.y;
254 debugMPBuffer.
getWriteBuffer().currentPose[
"currentPose_qz"] = currentQ.z;
255 debugMPBuffer.
getWriteBuffer().currentCanVal = dmpCtrl->debugData.canVal;
256 debugMPBuffer.
getWriteBuffer().mpcFactor = dmpCtrl->debugData.mpcFactor;
257 debugMPBuffer.
getWriteBuffer().error = dmpCtrl->debugData.poseError;
258 debugMPBuffer.
getWriteBuffer().posError = dmpCtrl->debugData.posiError;
259 debugMPBuffer.
getWriteBuffer().oriError = dmpCtrl->debugData.oriError;
281 debugMPBuffer.
getWriteBuffer().latestTargetVelocities[
"x_vel"] = targetVels(0);
282 debugMPBuffer.
getWriteBuffer().latestTargetVelocities[
"y_vel"] = targetVels(1);
283 debugMPBuffer.
getWriteBuffer().latestTargetVelocities[
"z_vel"] = targetVels(2);
284 debugMPBuffer.
getWriteBuffer().latestTargetVelocities[
"roll_vel"] = targetVels(3);
285 debugMPBuffer.
getWriteBuffer().latestTargetVelocities[
"pitch_vel"] = targetVels(4);
286 debugMPBuffer.
getWriteBuffer().latestTargetVelocities[
"yaw_vel"] = targetVels(5);
298 Eigen::MatrixXf jacobi =
299 ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All);
301 Eigen::VectorXf qpos(positionSensors.size());
302 Eigen::VectorXf qvel(velocitySensors.size());
303 for (
size_t i = 0; i < positionSensors.size(); ++i)
305 qpos(i) = positionSensors[i]->position;
306 qvel(i) = velocitySensors[i]->velocity;
308 qvel_filtered = (1 - cfg->qvelFilter) * qvel_filtered + cfg->qvelFilter * qvel;
309 Eigen::VectorXf currentTwist = jacobi * qvel_filtered;
310 jacobi.block(0, 0, 3, numOfJoints) =
311 0.001 * jacobi.block(0, 0, 3, numOfJoints);
313 double deltaT = timeSinceLastIteration.toSecondsDouble();
321 forcePID->Kp = pidForce(0);
322 forcePID->Ki = pidForce(1);
323 forcePID->Kd = pidForce(2);
324 forcePID->maxControlValue = pidForce(3);
327 Eigen::Vector3f tcpCoMInFTFrame =
332 Eigen::Vector3f forceBaseline = Eigen::Vector3f::Zero();
333 Eigen::Vector3f torqueBaseline = Eigen::Vector3f::Zero();
336 forceTorque.setZero();
337 tcpGravityCompensation.setZero();
342 Eigen::VectorXf targetNullSpaceJointValues =
344 Eigen::Vector3f targetVelInTool = Eigen::Vector3f::Zero();
347 float targetForce = 0.0f;
348 if (rtFirstRun.load())
350 rtReady.store(
false);
351 rtFirstRun.store(
false);
352 timeForCalibration = 0;
353 forceOffset.setZero();
354 torqueOffset.setZero();
358 rtGetRobot()->getRobotNode(cfg->forceFrameName)->getPoseInRootFrame();
359 forceFrameInTCP.block<3, 3>(0, 0) =
360 currentPose.block<3, 3>(0, 0).transpose() * forceFrameInRoot.block<3, 3>(0, 0);
361 tcpCoMInTCPFrame = forceFrameInTCP.block<3, 3>(0, 0) * tcpCoMInFTFrame;
363 targetPose = currentPose;
364 previousTargetPose = currentPose;
366 currentPose.block<3, 3>(0, 0).
transpose() * toolFrameInRoot.block<3, 3>(0, 0);
376 if (enableTCPGravityCompensation.load())
382 targetPose = previousTargetPose;
384 (1 - cfg->forceFilter) * forceOffset +
385 cfg->forceFilter * (forceSensor->
force - tcpGravityCompensation.head<3>());
387 (1 - cfg->forceFilter) * torqueOffset +
388 cfg->forceFilter * (forceSensor->
torque - tcpGravityCompensation.tail<3>());
389 timeForCalibration = timeForCalibration + deltaT;
390 if (timeForCalibration > cfg->waitTimeForCalibration)
394 <<
VAROUT(forceOffset) <<
"\n"
395 <<
VAROUT(torqueOffset) <<
"\n"
403 currentToolOriInRoot = currentPose.block<3, 3>(0, 0) * toolOriInHand;
406 Eigen::VectorXf ftInTool = forceTorque;
407 ftInTool.head<3>() = currentToolOriInRoot.transpose() * ftInTool.head<3>();
413 forcePID->update(deltaT, ftInTool(2), targetForce);
415 -1000.0f * (
float)forcePID->getControlValue();
417 targetVelInTool(2) = forcePIDVel;
418 targetVel.head<3>() += currentToolOriInRoot * targetVelInTool;
421 targetPose.block<3, 1>(0, 3) =
422 targetPose.block<3, 1>(0, 3) + (
float)deltaT * targetVel.block<3, 1>(0, 0);
423 if ((previousTargetPose.block<3, 1>(0, 3) - targetPose.block<3, 1>(0, 3)).norm() >
427 <<
VAROUT(targetPose) <<
"\nis too far away from\n"
428 <<
VAROUT(previousTargetPose);
429 targetPose = previousTargetPose;
431 previousTargetPose = targetPose;
435 bool isPhaseStop =
false;
436 float diff = (targetPose.block<2, 1>(0, 3) - currentPose.block<2, 1>(0, 3)).
norm();
437 if (diff > cfg->phaseDist0)
444 Eigen::Vector2f currentXY = currentPose.block<2, 1>(0, 3);
445 if ((lastPosition - currentXY).norm() < cfg->changePositionTolerance)
447 changeTimer += deltaT;
451 lastPosition = currentPose.block<2, 1>(0, 3);
455 if (changeTimer > cfg->changeTimerThreshold)
457 targetPose(0, 3) = currentPose(0, 3);
458 targetPose(1, 3) = currentPose(1, 3);
468 targetPose(0, 3) =
std::clamp(targetPose(0, 3), cfg->ws_x[0], cfg->ws_x[1]);
469 targetPose(1, 3) =
std::clamp(targetPose(1, 3), cfg->ws_y[0], cfg->ws_y[1]);
470 targetPose(2, 3) =
std::clamp(targetPose(2, 3), cfg->ws_z[0], cfg->ws_z[1]);
475 rt2InterfaceBuffer.
getWriteBuffer().waitTimeForCalibration += deltaT;
480 debugRTBuffer.
getWriteBuffer().filteredForce = filteredForceInRoot;
499 targetPose.block<3, 3>(0, 0) * currentPose.block<3, 3>(0, 0).transpose();
500 poseErrorImp.head<3>() =
501 0.001 * (targetPose.block<3, 1>(0, 3) - currentPose.block<3, 1>(0, 3));
502 currentTwist.head<3>() *= 0.001;
503 poseErrorImp.tail<3>() = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
505 kpImpedance.cwiseProduct(poseErrorImp) - kdImpedance.cwiseProduct(currentTwist);
508 Eigen::VectorXf nullspaceTorque =
509 knull.cwiseProduct(targetNullSpaceJointValues - qpos) - dnull.cwiseProduct(qvel);
513 Eigen::MatrixXf jtpinv = ik->computePseudoInverseJacobianMatrix(jacobi.transpose(), 2.0);
514 Eigen::VectorXf jointDesiredTorques = jacobi.transpose() * forceImpedance +
515 (I - jacobi.transpose() * jtpinv) * nullspaceTorque;
519 for (
size_t i = 0; i < targets.size(); ++i)
521 targets.at(i)->torque = jointDesiredTorques(i);
522 if (!targets.at(i)->isValid() || isnan(targets.at(i)->torque))
524 targets.at(i)->torque = 0.0f;
528 if (fabs(targets.at(i)->torque) > fabs(torqueLimit))
530 targets.at(i)->torque =
531 fabs(torqueLimit) * (targets.at(i)->torque / fabs(targets.at(i)->torque));
545 Eigen::Vector3f gravity;
546 gravity << 0.0, 0.0, -9.8;
547 Eigen::Vector3f localGravity = currentPose.block<3, 3>(0, 0).
transpose() * gravity;
548 Eigen::Vector3f localForceVec = tcpMass * localGravity;
549 Eigen::Vector3f localTorqueVec = tcpCoMInTCPFrame.cross(localForceVec);
552 tcpGravityCompensation << localForceVec, localTorqueVec;
553 return tcpGravityCompensation;
558 Eigen::Vector3f& forceBaseline,
559 Eigen::Vector3f& torqueBaseline,
563 (1 - cfg->forceFilter) * filteredForce + cfg->forceFilter * forceSensor->
force;
565 (1 - cfg->forceFilter) * filteredTorque + cfg->forceFilter * forceSensor->
torque;
568 rtGetRobot()->getRobotNode(cfg->forceFrameName)->getPoseInRootFrame();
569 filteredForceInRoot = forceFrameInRoot.block<3, 3>(0, 0) *
570 (filteredForce - forceOffset - handCompensatedFT.head<3>()) -
572 filteredTorqueInRoot = forceFrameInRoot.block<3, 3>(0, 0) *
573 (filteredTorque - torqueOffset - handCompensatedFT.tail<3>()) -
576 for (
size_t i = 0; i < 3; ++i)
578 if (fabs(filteredForceInRoot(i)) > cfg->forceDeadZone)
580 filteredForceInRoot(i) -=
581 (filteredForceInRoot(i) / fabs(filteredForceInRoot(i))) * cfg->forceDeadZone;
585 filteredForceInRoot(i) = 0;
588 if (fabs(filteredTorqueInRoot(i)) > cfg->torqueDeadZone)
590 filteredTorqueInRoot(i) -=
591 (filteredTorqueInRoot(i) / fabs(filteredTorqueInRoot(i))) * cfg->torqueDeadZone;
595 filteredTorqueInRoot(i) = 0;
600 forceTorque << filteredForceInRoot, filteredTorqueInRoot;
627 return kinematic_chain;
632 const Ice::StringSeq& fileNames,
638 dmpCtrl->learnDMPFromFiles(fileNames);
643 const TrajectoryBasePtr& trajectory,
648 TrajectoryPtr dmpTraj = TrajectoryPtr::dynamicCast(trajectory);
652 dmpCtrl->learnDMPFromTrajectory(dmpTraj);
666 dmpCtrl->setSpeed(times);
671 const Ice::Current& ice)
674 dmpCtrl->setGoalPoseVec(goals);
682 dmpCtrl->setAmplitude(amp);
699 rtFirstRun.store(
true);
700 while (rtFirstRun.load() || !rtReady.load() || !rt2InterfaceBuffer.
updateReadBuffer())
708 dmpCtrl->prepareExecution(dmpCtrl->eigen4f2vec(pose), goals);
709 dmpCtrl->setSpeed(tau);
711 mpRunning.store(
true);
712 dmpCtrl->resumeController();
719 return dmpCtrl->canVal;
726 if (mpRunning.load())
736 mpRunning.store(
false);
745 dmpCtrl->pauseController();
751 dmpCtrl->resumeController();
761 std::string datafieldName;
762 std::string debugName =
"Periodic";
766 datafields[
"target_x"] =
new Variant(targetPoseDebug(0, 3));
767 datafields[
"target_y"] =
new Variant(targetPoseDebug(1, 3));
768 datafields[
"target_z"] =
new Variant(targetPoseDebug(2, 3));
771 datafields[
"targetVelInTool_x"] =
new Variant(targetVelInTool(0));
772 datafields[
"targetVelInTool_y"] =
new Variant(targetVelInTool(1));
773 datafields[
"targetVelInTool_z"] =
new Variant(targetVelInTool(2));
776 datafields[
"current_x"] =
new Variant(currentPoseDebug(0, 3));
777 datafields[
"current_y"] =
new Variant(currentPoseDebug(1, 3));
778 datafields[
"current_z"] =
new Variant(currentPoseDebug(2, 3));
781 datafields[
"filteredforce_x"] =
new Variant(filteredForce(0));
782 datafields[
"filteredforce_y"] =
new Variant(filteredForce(1));
783 datafields[
"filteredforce_z"] =
new Variant(filteredForce(2));
787 datafields[
"reactForce_x"] =
new Variant(reactForce(0));
788 datafields[
"reactForce_y"] =
new Variant(reactForce(1));
789 datafields[
"reactForce_z"] =
new Variant(reactForce(2));
792 datafields[
"targetVel_x"] =
new Variant(targetVel(0));
793 datafields[
"targetVel_y"] =
new Variant(targetVel(1));
794 datafields[
"targetVel_z"] =
new Variant(targetVel(2));
833 datafieldName =
"PeriodicDMP";
834 debugObs->setDebugChannel(datafieldName, datafields);