12 cfg = NJointAdaptiveWipingControllerConfigPtr::dynamicCast(config);
14 VirtualRobot::RobotNodeSetPtr rns =
rtGetRobot()->getRobotNodeSet(cfg->nodeSetName);
17 for (
size_t i = 0; i < rns->getSize(); ++i)
19 std::string jointName = rns->getNode(i)->getName();
22 targets.push_back(ct->
asA<ControlTarget1DoFActuatorTorque>());
24 const SensorValue1DoFActuatorVelocity* velocitySensor = sv->
asA<SensorValue1DoFActuatorVelocity>();
25 const SensorValue1DoFActuatorPosition* positionSensor = sv->
asA<SensorValue1DoFActuatorPosition>();
27 velocitySensors.push_back(velocitySensor);
28 positionSensors.push_back(positionSensor);
33 nodeSetName = cfg->nodeSetName;
34 ik.reset(
new VirtualRobot::DifferentialIK(rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
40 taskSpaceDMPConfig.
DMPMode =
"Linear";
41 taskSpaceDMPConfig.
DMPStyle =
"Periodic";
58 for (
size_t i = 0; i < 6; ++i)
73 kpos << cfg->Kpos[0], cfg->Kpos[1], cfg->Kpos[2];
74 dpos << cfg->Dpos[0], cfg->Dpos[1], cfg->Dpos[2];
75 kori << cfg->Kori[0], cfg->Kori[1], cfg->Kori[2];
76 dori << cfg->Dori[0], cfg->Dori[1], cfg->Dori[2];
80 knull.setZero(targets.size());
81 dnull.setZero(targets.size());
83 for (
size_t i = 0; i < targets.size(); ++i)
85 knull(i) = cfg->Knull.at(i);
86 dnull(i) = cfg->Dnull.at(i);
90 nullSpaceJointsVec.resize(cfg->desiredNullSpaceJointValues.size());
91 for (
size_t i = 0; i < cfg->desiredNullSpaceJointValues.size(); ++i)
93 nullSpaceJointsVec(i) = cfg->desiredNullSpaceJointValues.at(i);
97 const SensorValueBase* svlf = robUnit->getSensorDevice(cfg->forceSensorName)->getSensorValue();
103 currentForceOffset.setZero();
104 forceOffset << cfg->ftOffset[0], cfg->ftOffset[1], cfg->ftOffset[2];
105 torqueOffset << cfg->ftOffset[3], cfg->ftOffset[4], cfg->ftOffset[5];
107 handMass = cfg->handMass;
108 handCOM << cfg->handCOM[0], cfg->handCOM[1], cfg->handCOM[2];
111 filteredForce.setZero();
112 filteredTorque.setZero();
114 filteredForceInRoot.setZero();
115 filteredTorqueInRoot.setZero();
117 UserToRTData initUserData;
118 initUserData.targetForce = 0;
121 oriToolDir << 0, 0, 1;
122 gravityInRoot << 0, 0, -9.8;
124 qvel_filtered.setZero(targets.size());
152 RTToControllerData initSensorData;
153 initSensorData.deltaT = 0;
154 initSensorData.currentTime = 0;
155 initSensorData.currentPose = tcp->getPoseInRootFrame();
156 initSensorData.currentTwist.setZero();
157 initSensorData.isPhaseStop =
false;
160 RTToUserData initInterfaceData;
161 initInterfaceData.currentTcpPose = tcp->getPoseInRootFrame();
162 initInterfaceData.waitTimeForCalibration = 0;
167 runTask(
"NJointAdaptiveWipingController", [&]
171 while (
getState() == eManagedIceObjectStarted)
177 c.waitForCycleDuration();
185 return "NJointAdaptiveWipingController";
200 Eigen::VectorXf targetVels(6);
204 targetVels.setZero();
214 dmpCtrl->flow(deltaT, currentPose, currentTwist);
216 targetVels = dmpCtrl->getTargetVelocity();
218 debugOutputData.
getWriteBuffer().latestTargetVelocities[
"x_vel"] = targetVels(0);
219 debugOutputData.
getWriteBuffer().latestTargetVelocities[
"y_vel"] = targetVels(1);
220 debugOutputData.
getWriteBuffer().latestTargetVelocities[
"z_vel"] = targetVels(2);
221 debugOutputData.
getWriteBuffer().latestTargetVelocities[
"roll_vel"] = targetVels(3);
222 debugOutputData.
getWriteBuffer().latestTargetVelocities[
"pitch_vel"] = targetVels(4);
223 debugOutputData.
getWriteBuffer().latestTargetVelocities[
"yaw_vel"] = targetVels(5);
224 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_x"] = currentPose(0, 3);
225 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_y"] = currentPose(1, 3);
226 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_z"] = currentPose(2, 3);
228 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_qw"] = currentQ.w;
229 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_qx"] = currentQ.x;
230 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_qy"] = currentQ.y;
231 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_qz"] = currentQ.z;
232 debugOutputData.
getWriteBuffer().currentCanVal = dmpCtrl->debugData.canVal;
233 debugOutputData.
getWriteBuffer().mpcFactor = dmpCtrl->debugData.mpcFactor;
234 debugOutputData.
getWriteBuffer().error = dmpCtrl->debugData.poseError;
235 debugOutputData.
getWriteBuffer().posError = dmpCtrl->debugData.posiError;
236 debugOutputData.
getWriteBuffer().oriError = dmpCtrl->debugData.oriError;
250 double deltaT = timeSinceLastIteration.toSecondsDouble();
257 Eigen::Vector3f currentToolDir;
258 currentToolDir.setZero();
259 Eigen::MatrixXf jacobi = ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All);
261 Eigen::VectorXf qpos(positionSensors.size());
262 Eigen::VectorXf qvel(velocitySensors.size());
263 for (
size_t i = 0; i < positionSensors.size(); ++i)
265 qpos(i) = positionSensors[i]->position;
266 qvel(i) = velocitySensors[i]->velocity;
269 qvel_filtered = (1 - cfg->velFilter) * qvel_filtered + cfg->velFilter * qvel;
270 Eigen::VectorXf currentTwist = jacobi * qvel_filtered;
272 Eigen::VectorXf targetVel(6);
273 Eigen::Vector3f axis;
276 Eigen::Vector3f forceInToolFrame;
277 forceInToolFrame << 0, 0, 0;
279 Eigen::Vector3f torqueInToolFrame;
280 torqueInToolFrame << 0, 0, 0;
283 if (firstRun || !dmpRunning)
285 lastPosition = currentPose.block<2, 1>(0, 3);
286 targetPose = currentPose;
288 filteredForce.setZero();
289 Eigen::Vector3f currentForce = forceSensor->
force - forceOffset;
291 Eigen::Matrix3f forceFrameOri =
rtGetRobot()->getSensor(cfg->forceSensorName)->getRobotNode()->getPoseInRootFrame().block<3, 3>(0, 0);
292 Eigen::Vector3f gravityInForceFrame = forceFrameOri.transpose() * gravityInRoot;
293 Eigen::Vector3f handGravity = handMass * gravityInForceFrame;
294 currentForce = currentForce - handGravity;
296 currentForceOffset = 0.1 * currentForceOffset + 0.9 * currentForce;
297 origHandOri = currentPose.block<3, 3>(0, 0);
298 toolTransform = origHandOri.transpose();
309 Eigen::Vector3f currentForce = forceSensor->
force - forceOffset - currentForceOffset;
311 Eigen::Matrix3f forceFrameOri =
rtGetRobot()->getSensor(cfg->forceSensorName)->getRobotNode()->getPoseInRootFrame().block<3, 3>(0, 0);
312 Eigen::Vector3f gravityInForceFrame = forceFrameOri.transpose() * gravityInRoot;
313 Eigen::Vector3f handGravity = handMass * gravityInForceFrame;
315 currentForce = currentForce - handGravity;
316 filteredForce = (1 - cfg->forceFilter) * filteredForce + cfg->forceFilter * currentForce;
318 Eigen::Vector3f currentTorque = forceSensor->
torque - torqueOffset;
319 Eigen::Vector3f handTorque = handCOM.cross(gravityInForceFrame);
320 currentTorque = currentTorque - handTorque;
321 filteredTorque = (1 - cfg->forceFilter) * filteredTorque + cfg->forceFilter * currentTorque;
323 for (
size_t i = 0; i < 3; ++i)
325 if (fabs(filteredForce(i)) > cfg->forceDeadZone)
327 filteredForce(i) -= (filteredForce(i) / fabs(filteredForce(i))) * cfg->forceDeadZone;
331 filteredForce(i) = 0;
335 filteredForceInRoot = forceFrameOri * filteredForce;
336 filteredTorqueInRoot = forceFrameOri * filteredTorque;
342 forceInToolFrame = currentToolOri.transpose() * filteredForceInRoot;
343 torqueInToolFrame = currentToolOri.transpose() * filteredTorqueInRoot;
345 float desiredZVel = kpf * (targetForce - forceInToolFrame(2));
346 targetVel(2) -= desiredZVel;
347 targetVel.block<3, 1>(0, 0) = currentToolOri * targetVel.block<3, 1>(0, 0);
349 currentToolDir = currentToolOri * oriToolDir;
351 for (
int i = 3; i < 6; ++i)
358 if (filteredForceInRoot.norm() > fabs(cfg->minimumReactForce))
360 Eigen::Vector3f toolYDir;
361 toolYDir << 0, 1.0, 0;
362 Eigen::Vector3f toolYDirInRoot = currentToolOri * toolYDir;
363 Eigen::Vector3f projectedFilteredForceInRoot = filteredForceInRoot - filteredForceInRoot.dot(toolYDirInRoot) * toolYDirInRoot;
364 Eigen::Vector3f desiredToolDir = projectedFilteredForceInRoot.normalized();
365 currentToolDir.normalize();
367 axis = currentToolDir.cross(desiredToolDir);
368 axis = axis.normalized();
369 angle = acosf(currentToolDir.dot(desiredToolDir));
375 float adaptedAngularKp = cfg->angularKp / (1 + exp(10 * (
angle -
M_PI / 4)));
376 float angularKp = fmin(adaptedAngularKp, cfg->angularKp);
379 Eigen::Vector3f fixedAxis;
382 fixedAxis << 0.0, 1.0, 0.0;
386 fixedAxis << 0.0, -1.0, 0.0;
388 Eigen::AngleAxisf desiredToolRot(
angle - cfg->frictionCone, fixedAxis);
391 Eigen::Vector3f angularDiff = VirtualRobot::MathTools::eigen3f2rpy(desiredRotMat);
393 targetVel.tail(3) = angularKp * angularDiff;
396 Eigen::Vector3f checkedToolDir = desiredRotMat * currentToolDir;
397 checkedToolDir.normalize();
403 bool isPhaseStop =
false;
405 float diff = (targetPose.block<2, 1>(0, 3) - currentPose.block<2, 1>(0, 3)).
norm();
406 if (diff > cfg->phaseDist0)
411 float dTf = (
float)deltaT;
414 if (filteredForceInRoot.block<2, 1>(0, 0).norm() > cfg->dragForceDeadZone)
416 Eigen::Vector2f dragForce = filteredForceInRoot.block<2, 1>(0, 0) - cfg->dragForceDeadZone * filteredForceInRoot.block<2, 1>(0, 0) / filteredForceInRoot.block<2, 1>(0, 0).
norm();
417 adaptK(0) = fmax(adaptK(0) - dTf * cfg->adaptForceCoeff * dragForce.norm(), 0);
418 adaptK(1) = fmax(adaptK(1) - dTf * cfg->adaptForceCoeff * dragForce.norm(), 0);
423 adaptK(0) = fmin(adaptK(0) + fabs(dTf * cfg->adaptCoeff), kpos(0));
424 adaptK(1) = fmin(adaptK(1) + fabs(dTf * cfg->adaptCoeff), kpos(1));
433 targetPose.block<3, 1>(0, 3) = targetPose.block<3, 1>(0, 3) + dTf * targetVel.block<3, 1>(0, 0);
434 Eigen::Matrix3f rotMat = VirtualRobot::MathTools::rpy2eigen3f(dTf * targetVel(3), dTf * targetVel(4), dTf * targetVel(5));
435 targetPose.block<3, 3>(0, 0) = rotMat * targetPose.block<3, 3>(0, 0);
439 Eigen::Vector2f currentXY = currentPose.block<2, 1>(0, 3);
440 if ((lastPosition - currentXY).norm() < cfg->changePositionTolerance)
442 changeTimer += deltaT;
446 lastPosition = currentPose.block<2, 1>(0, 3);
450 if (changeTimer > cfg->changeTimerThreshold)
452 targetPose(0, 3) = currentPose(0, 3);
453 targetPose(1, 3) = currentPose(1, 3);
464 targetPose(0, 3) = targetPose(0, 3) > cfg->ws_x[0] ? targetPose(0, 3) : cfg->ws_x[0];
465 targetPose(0, 3) = targetPose(0, 3) < cfg->ws_x[1] ? targetPose(0, 3) : cfg->ws_x[1];
467 targetPose(1, 3) = targetPose(1, 3) > cfg->ws_y[0] ? targetPose(1, 3) : cfg->ws_y[0];
468 targetPose(1, 3) = targetPose(1, 3) < cfg->ws_y[1] ? targetPose(1, 3) : cfg->ws_y[1];
470 targetPose(2, 3) = targetPose(2, 3) > cfg->ws_z[0] ? targetPose(2, 3) : cfg->ws_z[0];
471 targetPose(2, 3) = targetPose(2, 3) < cfg->ws_z[1] ? targetPose(2, 3) : cfg->ws_z[1];
475 debugRT.
getWriteBuffer().currentToolDir = tcp->getRobot()->getRootNode()->toGlobalCoordinateSystemVec(currentToolDir);
477 debugRT.
getWriteBuffer().globalPose = tcp->getRobot()->getRootNode()->toGlobalCoordinateSystem(targetPose);
479 debugRT.
getWriteBuffer().filteredForceInRoot = filteredForceInRoot;
482 debugRT.
getWriteBuffer().globalFilteredForce = tcp->getRobot()->getRootNode()->toGlobalCoordinateSystemVec(filteredForceInRoot);
504 jacobi.block<3, 8>(0, 0) = 0.001 * jacobi.block<3, 8>(0, 0);
511 Eigen::Vector3f targetTCPLinearVelocity;
512 targetTCPLinearVelocity << 0.001 * targetVel(0), 0.001 * targetVel(1), 0.001 * targetVel(2);
513 Eigen::Vector3f currentTCPLinearVelocity;
514 currentTCPLinearVelocity << 0.001 * currentTwist(0), 0.001 * currentTwist(1), 0.001 * currentTwist(2);
515 Eigen::Vector3f currentTCPPosition = currentPose.block<3, 1>(0, 3);
516 Eigen::Vector3f desiredPosition = targetPose.block<3, 1>(0, 3);
518 Eigen::Vector3f linearVel = adaptK.cwiseProduct(desiredPosition - currentTCPPosition);
532 Eigen::Vector3f tcpDesiredForce = 0.001 * linearVel + dpos.cwiseProduct(- currentTCPLinearVelocity);
534 Eigen::Vector3f currentTCPAngularVelocity;
535 currentTCPAngularVelocity << currentTwist(3), currentTwist(4), currentTwist(5);
537 Eigen::Matrix3f diffMat = targetPose.block<3, 3>(0, 0) * currentRotMat.inverse();
538 Eigen::Vector3f rpy = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
539 Eigen::Vector3f tcpDesiredTorque = kori.cwiseProduct(rpy) + dori.cwiseProduct(- currentTCPAngularVelocity);
540 jointControlWrench << tcpDesiredForce, tcpDesiredTorque;
546 Eigen::VectorXf nullspaceTorque = knull.cwiseProduct(nullSpaceJointsVec - qpos) - dnull.cwiseProduct(qvel);
547 Eigen::MatrixXf jtpinv = ik->computePseudoInverseJacobianMatrix(jacobi.transpose(), 2.0);
548 Eigen::VectorXf jointDesiredTorques = jacobi.transpose() * jointControlWrench + (I - jacobi.transpose() * jtpinv) * nullspaceTorque;
551 for (
size_t i = 0; i < targets.size(); ++i)
553 targets.at(i)->torque = jointDesiredTorques(i);
555 if (!targets.at(i)->isValid())
557 targets.at(i)->torque = 0.0f;
561 if (fabs(targets.at(i)->torque) > fabs(cfg->maxJointTorque))
563 targets.at(i)->torque = fabs(cfg->maxJointTorque) * (targets.at(i)->torque / fabs(targets.at(i)->torque));
577 dmpCtrl->learnDMPFromFiles(fileNames);
585 TrajectoryPtr dmpTraj = TrajectoryPtr::dynamicCast(trajectory);
589 dmpCtrl->learnDMPFromTrajectory(dmpTraj);
596 dmpCtrl->setSpeed(times);
603 dmpCtrl->setGoalPoseVec(goals);
609 dmpCtrl->setAmplitude(amp);
622 while (firstRun || rt2UserData.
getUpToDateReadBuffer().waitTimeForCalibration < cfg->waitTimeForCalibration)
631 dmpCtrl->prepareExecution(dmpCtrl->eigen4f2vec(pose), goals);
632 dmpCtrl->setSpeed(tau);
642 std::string datafieldName;
643 std::string debugName =
"Periodic";
647 datafields[
"target_x"] =
new Variant(targetPoseDebug(0, 3));
648 datafields[
"target_y"] =
new Variant(targetPoseDebug(1, 3));
649 datafields[
"target_z"] =
new Variant(targetPoseDebug(2, 3));
652 datafields[
"current_x"] =
new Variant(currentPoseDebug(0, 3));
653 datafields[
"current_y"] =
new Variant(currentPoseDebug(1, 3));
654 datafields[
"current_z"] =
new Variant(currentPoseDebug(2, 3));
657 datafields[
"filteredforceInTool_x"] =
new Variant(filteredForce(0));
658 datafields[
"filteredforceInTool_y"] =
new Variant(filteredForce(1));
659 datafields[
"filteredforceInTool_z"] =
new Variant(filteredForce(2));
662 datafields[
"filteredtorqueInTool_x"] =
new Variant(filteredTorque(0));
663 datafields[
"filteredtorqueInTool_y"] =
new Variant(filteredTorque(1));
664 datafields[
"filteredtorqueInTool_z"] =
new Variant(filteredTorque(2));
668 datafields[
"filteredForceInRoot_x"] =
new Variant(filteredForceInRoot(0));
669 datafields[
"filteredForceInRoot_y"] =
new Variant(filteredForceInRoot(1));
670 datafields[
"filteredForceInRoot_z"] =
new Variant(filteredForceInRoot(2));
673 datafields[
"rotationAxis_x"] =
new Variant(rotationAxis(0));
674 datafields[
"rotationAxis_y"] =
new Variant(rotationAxis(1));
675 datafields[
"rotationAxis_z"] =
new Variant(rotationAxis(2));
678 datafields[
"reactForce_x"] =
new Variant(reactForce(0));
679 datafields[
"reactForce_y"] =
new Variant(reactForce(1));
680 datafields[
"reactForce_z"] =
new Variant(reactForce(2));
683 datafields[
"targetVel_x"] =
new Variant(targetVel(0));
684 datafields[
"targetVel_y"] =
new Variant(targetVel(1));
685 datafields[
"targetVel_z"] =
new Variant(targetVel(2));
686 datafields[
"targetVel_ro"] =
new Variant(targetVel(3));
687 datafields[
"targetVel_pi"] =
new Variant(targetVel(4));
688 datafields[
"targetVel_ya"] =
new Variant(targetVel(5));
691 datafields[
"currentTwist_x"] =
new Variant(currentTwist(0));
692 datafields[
"currentTwist_y"] =
new Variant(currentTwist(1));
693 datafields[
"currentTwist_z"] =
new Variant(currentTwist(2));
694 datafields[
"currentTwist_ro"] =
new Variant(currentTwist(3));
695 datafields[
"currentTwist_pi"] =
new Variant(currentTwist(4));
696 datafields[
"currentTwist_ya"] =
new Variant(currentTwist(5));
700 datafields[
"adaptK_x"] =
new Variant(adaptK(0));
701 datafields[
"adaptK_y"] =
new Variant(adaptK(1));
741 datafieldName =
"PeriodicDMP";
742 debugObs->setDebugChannel(datafieldName, datafields);
747 Eigen::Vector3f handPosition = globalPose.block<3, 1>(0, 3);
750 debugDrawer->setArrowVisu(
"Force",
"currentForce",
new Vector3(handPosition),
new Vector3(forceDir), DrawColor {0, 0, 1, 1}, 10 * forceDir.norm(), 3);
754 debugDrawer->setArrowVisu(
"Tool",
"Tool",
new Vector3(handPosition),
new Vector3(currentToolDir), DrawColor {1, 0, 0, 1}, 100, 3);
755 debugDrawer->setPoseVisu(
"target",
"targetPose",
new Pose(globalPose));