3 #include <VirtualRobot/IK/DifferentialIK.h>
4 #include <VirtualRobot/MathTools.h>
5 #include <VirtualRobot/Nodes/RobotNode.h>
6 #include <VirtualRobot/Nodes/Sensor.h>
7 #include <VirtualRobot/Robot.h>
8 #include <VirtualRobot/RobotNodeSet.h>
28 const armarx::NJointControllerConfigPtr& config,
32 cfg = NJointAdaptiveWipingControllerConfigPtr::dynamicCast(config);
34 VirtualRobot::RobotNodeSetPtr rns =
rtGetRobot()->getRobotNodeSet(cfg->nodeSetName);
37 for (
size_t i = 0; i < rns->getSize(); ++i)
39 std::string jointName = rns->getNode(i)->getName();
42 targets.push_back(ct->
asA<ControlTarget1DoFActuatorTorque>());
44 const SensorValue1DoFActuatorVelocity* velocitySensor =
45 sv->
asA<SensorValue1DoFActuatorVelocity>();
46 const SensorValue1DoFActuatorPosition* positionSensor =
47 sv->
asA<SensorValue1DoFActuatorPosition>();
49 velocitySensors.push_back(velocitySensor);
50 positionSensors.push_back(positionSensor);
55 nodeSetName = cfg->nodeSetName;
56 ik.reset(
new VirtualRobot::DifferentialIK(
57 rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
63 taskSpaceDMPConfig.
DMPMode =
"Linear";
64 taskSpaceDMPConfig.
DMPStyle =
"Periodic";
80 for (
size_t i = 0; i < 6; ++i)
95 kpos << cfg->Kpos[0], cfg->Kpos[1], cfg->Kpos[2];
96 dpos << cfg->Dpos[0], cfg->Dpos[1], cfg->Dpos[2];
97 kori << cfg->Kori[0], cfg->Kori[1], cfg->Kori[2];
98 dori << cfg->Dori[0], cfg->Dori[1], cfg->Dori[2];
102 knull.setZero(targets.size());
103 dnull.setZero(targets.size());
105 for (
size_t i = 0; i < targets.size(); ++i)
107 knull(i) = cfg->Knull.at(i);
108 dnull(i) = cfg->Dnull.at(i);
111 nullSpaceJointsVec.resize(cfg->desiredNullSpaceJointValues.size());
112 for (
size_t i = 0; i < cfg->desiredNullSpaceJointValues.size(); ++i)
114 nullSpaceJointsVec(i) = cfg->desiredNullSpaceJointValues.at(i);
119 robUnit->getSensorDevice(cfg->forceSensorName)->getSensorValue();
125 currentForceOffset.setZero();
126 forceOffset << cfg->ftOffset[0], cfg->ftOffset[1], cfg->ftOffset[2];
127 torqueOffset << cfg->ftOffset[3], cfg->ftOffset[4], cfg->ftOffset[5];
129 handMass = cfg->handMass;
130 handCOM << cfg->handCOM[0], cfg->handCOM[1], cfg->handCOM[2];
133 filteredForce.setZero();
134 filteredTorque.setZero();
136 filteredForceInRoot.setZero();
137 filteredTorqueInRoot.setZero();
139 UserToRTData initUserData;
140 initUserData.targetForce = 0;
143 oriToolDir << 0, 0, 1;
144 gravityInRoot << 0, 0, -9.8;
146 qvel_filtered.setZero(targets.size());
175 RTToControllerData initSensorData;
176 initSensorData.deltaT = 0;
177 initSensorData.currentTime = 0;
178 initSensorData.currentPose = tcp->getPoseInRootFrame();
179 initSensorData.currentTwist.setZero();
180 initSensorData.isPhaseStop =
false;
183 RTToUserData initInterfaceData;
184 initInterfaceData.currentTcpPose = tcp->getPoseInRootFrame();
185 initInterfaceData.waitTimeForCalibration = 0;
190 runTask(
"NJointAdaptiveWipingController",
195 while (
getState() == eManagedIceObjectStarted)
201 c.waitForCycleDuration();
209 return "NJointAdaptiveWipingController";
225 Eigen::VectorXf targetVels(6);
229 targetVels.setZero();
239 dmpCtrl->flow(deltaT, currentPose, currentTwist);
241 targetVels = dmpCtrl->getTargetVelocity();
243 debugOutputData.
getWriteBuffer().latestTargetVelocities[
"x_vel"] = targetVels(0);
244 debugOutputData.
getWriteBuffer().latestTargetVelocities[
"y_vel"] = targetVels(1);
245 debugOutputData.
getWriteBuffer().latestTargetVelocities[
"z_vel"] = targetVels(2);
246 debugOutputData.
getWriteBuffer().latestTargetVelocities[
"roll_vel"] = targetVels(3);
247 debugOutputData.
getWriteBuffer().latestTargetVelocities[
"pitch_vel"] = targetVels(4);
248 debugOutputData.
getWriteBuffer().latestTargetVelocities[
"yaw_vel"] = targetVels(5);
249 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_x"] = currentPose(0, 3);
250 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_y"] = currentPose(1, 3);
251 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_z"] = currentPose(2, 3);
253 VirtualRobot::MathTools::eigen4f2quat(currentPose);
254 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_qw"] = currentQ.w;
255 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_qx"] = currentQ.x;
256 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_qy"] = currentQ.y;
257 debugOutputData.
getWriteBuffer().currentPose[
"currentPose_qz"] = currentQ.z;
258 debugOutputData.
getWriteBuffer().currentCanVal = dmpCtrl->debugData.canVal;
259 debugOutputData.
getWriteBuffer().mpcFactor = dmpCtrl->debugData.mpcFactor;
260 debugOutputData.
getWriteBuffer().error = dmpCtrl->debugData.poseError;
261 debugOutputData.
getWriteBuffer().posError = dmpCtrl->debugData.posiError;
262 debugOutputData.
getWriteBuffer().oriError = dmpCtrl->debugData.oriError;
277 double deltaT = timeSinceLastIteration.toSecondsDouble();
284 Eigen::Vector3f currentToolDir;
285 currentToolDir.setZero();
286 Eigen::MatrixXf jacobi =
287 ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All);
289 Eigen::VectorXf qpos(positionSensors.size());
290 Eigen::VectorXf qvel(velocitySensors.size());
291 for (
size_t i = 0; i < positionSensors.size(); ++i)
293 qpos(i) = positionSensors[i]->position;
294 qvel(i) = velocitySensors[i]->velocity;
297 qvel_filtered = (1 - cfg->velFilter) * qvel_filtered + cfg->velFilter * qvel;
298 Eigen::VectorXf currentTwist = jacobi * qvel_filtered;
300 Eigen::VectorXf targetVel(6);
301 Eigen::Vector3f axis;
304 Eigen::Vector3f forceInToolFrame;
305 forceInToolFrame << 0, 0, 0;
307 Eigen::Vector3f torqueInToolFrame;
308 torqueInToolFrame << 0, 0, 0;
311 if (firstRun || !dmpRunning)
313 lastPosition = currentPose.block<2, 1>(0, 3);
314 targetPose = currentPose;
316 filteredForce.setZero();
317 Eigen::Vector3f currentForce = forceSensor->
force - forceOffset;
320 ->getSensor(cfg->forceSensorName)
322 ->getPoseInRootFrame()
324 Eigen::Vector3f gravityInForceFrame = forceFrameOri.transpose() * gravityInRoot;
325 Eigen::Vector3f handGravity = handMass * gravityInForceFrame;
326 currentForce = currentForce - handGravity;
328 currentForceOffset = 0.1 * currentForceOffset + 0.9 * currentForce;
329 origHandOri = currentPose.block<3, 3>(0, 0);
330 toolTransform = origHandOri.transpose();
341 Eigen::Vector3f currentForce = forceSensor->
force - forceOffset - currentForceOffset;
344 ->getSensor(cfg->forceSensorName)
346 ->getPoseInRootFrame()
348 Eigen::Vector3f gravityInForceFrame = forceFrameOri.transpose() * gravityInRoot;
349 Eigen::Vector3f handGravity = handMass * gravityInForceFrame;
351 currentForce = currentForce - handGravity;
353 (1 - cfg->forceFilter) * filteredForce + cfg->forceFilter * currentForce;
355 Eigen::Vector3f currentTorque = forceSensor->
torque - torqueOffset;
356 Eigen::Vector3f handTorque = handCOM.cross(gravityInForceFrame);
357 currentTorque = currentTorque - handTorque;
359 (1 - cfg->forceFilter) * filteredTorque + cfg->forceFilter * currentTorque;
361 for (
size_t i = 0; i < 3; ++i)
363 if (fabs(filteredForce(i)) > cfg->forceDeadZone)
366 (filteredForce(i) / fabs(filteredForce(i))) * cfg->forceDeadZone;
370 filteredForce(i) = 0;
374 filteredForceInRoot = forceFrameOri * filteredForce;
375 filteredTorqueInRoot = forceFrameOri * filteredTorque;
381 forceInToolFrame = currentToolOri.transpose() * filteredForceInRoot;
382 torqueInToolFrame = currentToolOri.transpose() * filteredTorqueInRoot;
384 float desiredZVel = kpf * (targetForce - forceInToolFrame(2));
385 targetVel(2) -= desiredZVel;
386 targetVel.block<3, 1>(0, 0) = currentToolOri * targetVel.block<3, 1>(0, 0);
388 currentToolDir = currentToolOri * oriToolDir;
390 for (
int i = 3; i < 6; ++i)
397 if (filteredForceInRoot.norm() > fabs(cfg->minimumReactForce))
399 Eigen::Vector3f toolYDir;
400 toolYDir << 0, 1.0, 0;
401 Eigen::Vector3f toolYDirInRoot = currentToolOri * toolYDir;
402 Eigen::Vector3f projectedFilteredForceInRoot =
403 filteredForceInRoot - filteredForceInRoot.dot(toolYDirInRoot) * toolYDirInRoot;
404 Eigen::Vector3f desiredToolDir =
405 projectedFilteredForceInRoot
407 currentToolDir.normalize();
409 axis = currentToolDir.cross(desiredToolDir);
410 axis = axis.normalized();
411 angle = acosf(currentToolDir.dot(desiredToolDir));
417 float adaptedAngularKp = cfg->angularKp / (1 + exp(10 * (
angle -
M_PI / 4)));
418 float angularKp = fmin(adaptedAngularKp, cfg->angularKp);
421 Eigen::Vector3f fixedAxis;
424 fixedAxis << 0.0, 1.0, 0.0;
428 fixedAxis << 0.0, -1.0, 0.0;
430 Eigen::AngleAxisf desiredToolRot(
angle - cfg->frictionCone, fixedAxis);
433 Eigen::Vector3f angularDiff =
434 VirtualRobot::MathTools::eigen3f2rpy(desiredRotMat);
436 targetVel.tail<3>() = angularKp * angularDiff;
439 Eigen::Vector3f checkedToolDir = desiredRotMat * currentToolDir;
440 checkedToolDir.normalize();
446 bool isPhaseStop =
false;
448 float diff = (targetPose.block<2, 1>(0, 3) - currentPose.block<2, 1>(0, 3)).
norm();
449 if (diff > cfg->phaseDist0)
454 float dTf = (
float)deltaT;
457 if (filteredForceInRoot.block<2, 1>(0, 0).norm() > cfg->dragForceDeadZone)
459 Eigen::Vector2f dragForce = filteredForceInRoot.block<2, 1>(0, 0) -
460 cfg->dragForceDeadZone *
461 filteredForceInRoot.block<2, 1>(0, 0) /
462 filteredForceInRoot.block<2, 1>(0, 0).
norm();
463 adaptK(0) = fmax(adaptK(0) - dTf * cfg->adaptForceCoeff * dragForce.norm(), 0);
464 adaptK(1) = fmax(adaptK(1) - dTf * cfg->adaptForceCoeff * dragForce.norm(), 0);
469 adaptK(0) = fmin(adaptK(0) + fabs(dTf * cfg->adaptCoeff), kpos(0));
470 adaptK(1) = fmin(adaptK(1) + fabs(dTf * cfg->adaptCoeff), kpos(1));
477 targetPose.block<3, 1>(0, 3) =
478 targetPose.block<3, 1>(0, 3) + dTf * targetVel.block<3, 1>(0, 0);
480 dTf * targetVel(3), dTf * targetVel(4), dTf * targetVel(5));
481 targetPose.block<3, 3>(0, 0) = rotMat * targetPose.block<3, 3>(0, 0);
485 Eigen::Vector2f currentXY = currentPose.block<2, 1>(0, 3);
486 if ((lastPosition - currentXY).norm() < cfg->changePositionTolerance)
488 changeTimer += deltaT;
492 lastPosition = currentPose.block<2, 1>(0, 3);
496 if (changeTimer > cfg->changeTimerThreshold)
498 targetPose(0, 3) = currentPose(0, 3);
499 targetPose(1, 3) = currentPose(1, 3);
510 targetPose(0, 3) = targetPose(0, 3) > cfg->ws_x[0] ? targetPose(0, 3) : cfg->ws_x[0];
511 targetPose(0, 3) = targetPose(0, 3) < cfg->ws_x[1] ? targetPose(0, 3) : cfg->ws_x[1];
513 targetPose(1, 3) = targetPose(1, 3) > cfg->ws_y[0] ? targetPose(1, 3) : cfg->ws_y[0];
514 targetPose(1, 3) = targetPose(1, 3) < cfg->ws_y[1] ? targetPose(1, 3) : cfg->ws_y[1];
516 targetPose(2, 3) = targetPose(2, 3) > cfg->ws_z[0] ? targetPose(2, 3) : cfg->ws_z[0];
517 targetPose(2, 3) = targetPose(2, 3) < cfg->ws_z[1] ? targetPose(2, 3) : cfg->ws_z[1];
521 tcp->getRobot()->getRootNode()->toGlobalCoordinateSystemVec(currentToolDir);
524 tcp->getRobot()->getRootNode()->toGlobalCoordinateSystem(targetPose);
526 debugRT.
getWriteBuffer().filteredForceInRoot = filteredForceInRoot;
530 tcp->getRobot()->getRootNode()->toGlobalCoordinateSystemVec(filteredForceInRoot);
552 jacobi.block<3, 8>(0, 0) = 0.001 * jacobi.block<3, 8>(0, 0);
557 Eigen::Vector3f targetTCPLinearVelocity;
558 targetTCPLinearVelocity << 0.001 * targetVel(0), 0.001 * targetVel(1),
559 0.001 * targetVel(2);
560 Eigen::Vector3f currentTCPLinearVelocity;
561 currentTCPLinearVelocity << 0.001 * currentTwist(0), 0.001 * currentTwist(1),
562 0.001 * currentTwist(2);
563 Eigen::Vector3f currentTCPPosition = currentPose.block<3, 1>(0, 3);
564 Eigen::Vector3f desiredPosition = targetPose.block<3, 1>(0, 3);
566 Eigen::Vector3f linearVel = adaptK.cwiseProduct(desiredPosition - currentTCPPosition);
580 Eigen::Vector3f tcpDesiredForce =
581 0.001 * linearVel + dpos.cwiseProduct(-currentTCPLinearVelocity);
583 Eigen::Vector3f currentTCPAngularVelocity;
584 currentTCPAngularVelocity << currentTwist(3), currentTwist(4), currentTwist(5);
586 Eigen::Matrix3f diffMat = targetPose.block<3, 3>(0, 0) * currentRotMat.inverse();
587 Eigen::Vector3f rpy = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
588 Eigen::Vector3f tcpDesiredTorque =
589 kori.cwiseProduct(rpy) + dori.cwiseProduct(-currentTCPAngularVelocity);
590 jointControlWrench << tcpDesiredForce, tcpDesiredTorque;
595 Eigen::VectorXf nullspaceTorque =
596 knull.cwiseProduct(nullSpaceJointsVec - qpos) - dnull.cwiseProduct(qvel);
597 Eigen::MatrixXf jtpinv = ik->computePseudoInverseJacobianMatrix(jacobi.transpose(), 2.0);
598 Eigen::VectorXf jointDesiredTorques = jacobi.transpose() * jointControlWrench +
599 (I - jacobi.transpose() * jtpinv) * nullspaceTorque;
602 for (
size_t i = 0; i < targets.size(); ++i)
604 targets.at(i)->torque = jointDesiredTorques(i);
606 if (!targets.at(i)->isValid())
608 targets.at(i)->torque = 0.0f;
612 if (fabs(targets.at(i)->torque) > fabs(cfg->maxJointTorque))
614 targets.at(i)->torque = fabs(cfg->maxJointTorque) *
615 (targets.at(i)->torque / fabs(targets.at(i)->torque));
628 dmpCtrl->learnDMPFromFiles(fileNames);
637 TrajectoryPtr dmpTraj = TrajectoryPtr::dynamicCast(trajectory);
641 dmpCtrl->learnDMPFromTrajectory(dmpTraj);
648 dmpCtrl->setSpeed(times);
655 dmpCtrl->setGoalPoseVec(goals);
662 dmpCtrl->setAmplitude(amp);
681 cfg->waitTimeForCalibration)
690 dmpCtrl->prepareExecution(dmpCtrl->eigen4f2vec(pose), goals);
691 dmpCtrl->setSpeed(tau);
703 std::string datafieldName;
704 std::string debugName =
"Periodic";
708 datafields[
"target_x"] =
new Variant(targetPoseDebug(0, 3));
709 datafields[
"target_y"] =
new Variant(targetPoseDebug(1, 3));
710 datafields[
"target_z"] =
new Variant(targetPoseDebug(2, 3));
713 datafields[
"current_x"] =
new Variant(currentPoseDebug(0, 3));
714 datafields[
"current_y"] =
new Variant(currentPoseDebug(1, 3));
715 datafields[
"current_z"] =
new Variant(currentPoseDebug(2, 3));
718 datafields[
"filteredforceInTool_x"] =
new Variant(filteredForce(0));
719 datafields[
"filteredforceInTool_y"] =
new Variant(filteredForce(1));
720 datafields[
"filteredforceInTool_z"] =
new Variant(filteredForce(2));
723 datafields[
"filteredtorqueInTool_x"] =
new Variant(filteredTorque(0));
724 datafields[
"filteredtorqueInTool_y"] =
new Variant(filteredTorque(1));
725 datafields[
"filteredtorqueInTool_z"] =
new Variant(filteredTorque(2));
729 datafields[
"filteredForceInRoot_x"] =
new Variant(filteredForceInRoot(0));
730 datafields[
"filteredForceInRoot_y"] =
new Variant(filteredForceInRoot(1));
731 datafields[
"filteredForceInRoot_z"] =
new Variant(filteredForceInRoot(2));
734 datafields[
"rotationAxis_x"] =
new Variant(rotationAxis(0));
735 datafields[
"rotationAxis_y"] =
new Variant(rotationAxis(1));
736 datafields[
"rotationAxis_z"] =
new Variant(rotationAxis(2));
739 datafields[
"reactForce_x"] =
new Variant(reactForce(0));
740 datafields[
"reactForce_y"] =
new Variant(reactForce(1));
741 datafields[
"reactForce_z"] =
new Variant(reactForce(2));
744 datafields[
"targetVel_x"] =
new Variant(targetVel(0));
745 datafields[
"targetVel_y"] =
new Variant(targetVel(1));
746 datafields[
"targetVel_z"] =
new Variant(targetVel(2));
747 datafields[
"targetVel_ro"] =
new Variant(targetVel(3));
748 datafields[
"targetVel_pi"] =
new Variant(targetVel(4));
749 datafields[
"targetVel_ya"] =
new Variant(targetVel(5));
752 datafields[
"currentTwist_x"] =
new Variant(currentTwist(0));
753 datafields[
"currentTwist_y"] =
new Variant(currentTwist(1));
754 datafields[
"currentTwist_z"] =
new Variant(currentTwist(2));
755 datafields[
"currentTwist_ro"] =
new Variant(currentTwist(3));
756 datafields[
"currentTwist_pi"] =
new Variant(currentTwist(4));
757 datafields[
"currentTwist_ya"] =
new Variant(currentTwist(5));
761 datafields[
"adaptK_x"] =
new Variant(adaptK(0));
762 datafields[
"adaptK_y"] =
new Variant(adaptK(1));
802 datafieldName =
"PeriodicDMP";
803 debugObs->setDebugChannel(datafieldName, datafields);
808 Eigen::Vector3f handPosition = globalPose.block<3, 1>(0, 3);
811 debugDrawer->setArrowVisu(
"Force",
815 DrawColor{0, 0, 1, 1},
816 10 * forceDir.norm(),
821 debugDrawer->setArrowVisu(
"Tool",
825 DrawColor{1, 0, 0, 1},
828 debugDrawer->setPoseVisu(
"target",
"targetPose",
new Pose(globalPose));