NJointAdaptiveWipingController.cpp
Go to the documentation of this file.
2
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>
9
11
20
22{
25
27 const RobotUnitPtr& robUnit,
28 const armarx::NJointControllerConfigPtr& config,
30 {
32 cfg = NJointAdaptiveWipingControllerConfigPtr::dynamicCast(config);
33 ARMARX_CHECK_EXPRESSION(!cfg->nodeSetName.empty());
34 VirtualRobot::RobotNodeSetPtr rns = rtGetRobot()->getRobotNodeSet(cfg->nodeSetName);
35
36 ARMARX_CHECK_EXPRESSION(rns) << cfg->nodeSetName;
37 for (size_t i = 0; i < rns->getSize(); ++i)
38 {
39 std::string jointName = rns->getNode(i)->getName();
40 ControlTargetBase* ct = useControlTarget(jointName, ControlModes::Torque1DoF);
41 const SensorValueBase* sv = useSensorValue(jointName);
42 targets.push_back(ct->asA<ControlTarget1DoFActuatorTorque>());
43
44 const SensorValue1DoFActuatorVelocity* velocitySensor =
45 sv->asA<SensorValue1DoFActuatorVelocity>();
46 const SensorValue1DoFActuatorPosition* positionSensor =
47 sv->asA<SensorValue1DoFActuatorPosition>();
48
49 velocitySensors.push_back(velocitySensor);
50 positionSensors.push_back(positionSensor);
51 };
52
53 tcp = rns->getTCP();
54 // set tcp controller
55 nodeSetName = cfg->nodeSetName;
56 ik.reset(new VirtualRobot::DifferentialIK(
57 rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
58
59 tsvmp::TaskSpaceDMPControllerConfig taskSpaceDMPConfig;
60 taskSpaceDMPConfig.motionTimeDuration = cfg->timeDuration;
61 taskSpaceDMPConfig.DMPKernelSize = cfg->kernelSize;
62 taskSpaceDMPConfig.DMPAmplitude = cfg->dmpAmplitude;
63 taskSpaceDMPConfig.DMPMode = "Linear";
64 taskSpaceDMPConfig.DMPStyle = "Periodic";
65 taskSpaceDMPConfig.phaseStopParas.goDist = cfg->phaseDist0;
66 taskSpaceDMPConfig.phaseStopParas.backDist = cfg->phaseDist1;
67 taskSpaceDMPConfig.phaseStopParas.Kpos = cfg->phaseKpPos;
68 taskSpaceDMPConfig.phaseStopParas.Kori = cfg->phaseKpOri;
69 taskSpaceDMPConfig.phaseStopParas.mm2radi = cfg->posToOriRatio;
70 taskSpaceDMPConfig.phaseStopParas.maxValue = cfg->phaseL;
71 taskSpaceDMPConfig.phaseStopParas.slop = cfg->phaseK;
72 taskSpaceDMPConfig.phaseStopParas.Dpos = 0;
73 taskSpaceDMPConfig.phaseStopParas.Dori = 0;
74
75
76 dmpCtrl.reset(new tsvmp::TaskSpaceDMPController("periodicDMP", taskSpaceDMPConfig, false));
77
79 initData.targetTSVel.resize(6);
80 for (size_t i = 0; i < 6; ++i)
81 {
82 initData.targetTSVel(i) = 0;
83 }
84 reinitTripleBuffer(initData);
85
86 firstRun = true;
87 dmpRunning = false;
88
89
90 ARMARX_CHECK_EQUAL(cfg->Kpos.size(), 3);
91 ARMARX_CHECK_EQUAL(cfg->Dpos.size(), 3);
92 ARMARX_CHECK_EQUAL(cfg->Kori.size(), 3);
93 ARMARX_CHECK_EQUAL(cfg->Dori.size(), 3);
94
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];
99
100 kpf = cfg->Kpf;
101 // forcePID.reset(new PIDController(cfg->kpf, ));
102 knull.setZero(targets.size());
103 dnull.setZero(targets.size());
104
105 for (size_t i = 0; i < targets.size(); ++i)
106 {
107 knull(i) = cfg->Knull.at(i);
108 dnull(i) = cfg->Dnull.at(i);
109 }
110
111 nullSpaceJointsVec.resize(cfg->desiredNullSpaceJointValues.size());
112 for (size_t i = 0; i < cfg->desiredNullSpaceJointValues.size(); ++i)
113 {
114 nullSpaceJointsVec(i) = cfg->desiredNullSpaceJointValues.at(i);
115 }
116
117
118 const SensorValueBase* svlf =
119 robUnit->getSensorDevice(cfg->forceSensorName)->getSensorValue();
120 forceSensor = svlf->asA<SensorValueForceTorque>();
121
122
123 ARMARX_CHECK_EQUAL(cfg->ftOffset.size(), 6);
124
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];
128
129 handMass = cfg->handMass;
130 handCOM << cfg->handCOM[0], cfg->handCOM[1], cfg->handCOM[2];
131
132
133 filteredForce.setZero();
134 filteredTorque.setZero();
135
136 filteredForceInRoot.setZero();
137 filteredTorqueInRoot.setZero();
138
139 UserToRTData initUserData;
140 initUserData.targetForce = 0;
141 user2rtData.reinitAllBuffers(initUserData);
142
143 oriToolDir << 0, 0, 1;
144 gravityInRoot << 0, 0, -9.8;
145
146 qvel_filtered.setZero(targets.size());
147
148 ARMARX_CHECK_EQUAL(cfg->ws_x.size(), 2);
149 ARMARX_CHECK_EQUAL(cfg->ws_y.size(), 2);
150 ARMARX_CHECK_EQUAL(cfg->ws_z.size(), 2);
151 // only for ARMAR-6 (safe-guard)
152 ARMARX_CHECK_LESS(cfg->ws_x[0], cfg->ws_x[1]);
153 ARMARX_CHECK_LESS(cfg->ws_x[0], 1000);
154 ARMARX_CHECK_LESS(-200, cfg->ws_x[1]);
155
156 ARMARX_CHECK_LESS(cfg->ws_y[0], cfg->ws_y[1]);
157 ARMARX_CHECK_LESS(cfg->ws_y[0], 1200);
158 ARMARX_CHECK_LESS(0, cfg->ws_y[1]);
159
160 ARMARX_CHECK_LESS(cfg->ws_z[0], cfg->ws_z[1]);
161 ARMARX_CHECK_LESS(cfg->ws_z[0], 1800);
162 ARMARX_CHECK_LESS(300, cfg->ws_z[1]);
163
164 adaptK = kpos;
165 lastDiff = 0;
166 changeTimer = 0;
167 }
168
169 void
171 {
172 ARMARX_INFO << "init ...";
173
174
175 RTToControllerData initSensorData;
176 initSensorData.deltaT = 0;
177 initSensorData.currentTime = 0;
178 initSensorData.currentPose = tcp->getPoseInRootFrame();
179 initSensorData.currentTwist.setZero();
180 initSensorData.isPhaseStop = false;
181 rt2CtrlData.reinitAllBuffers(initSensorData);
182
183 RTToUserData initInterfaceData;
184 initInterfaceData.currentTcpPose = tcp->getPoseInRootFrame();
185 initInterfaceData.waitTimeForCalibration = 0;
186 rt2UserData.reinitAllBuffers(initInterfaceData);
187
188 started = false;
189
190 runTask("NJointAdaptiveWipingController",
191 [&]
192 {
193 CycleUtil c(1);
194 getObjectScheduler()->waitForObjectStateMinimum(eManagedIceObjectStarted);
195 while (getState() == eManagedIceObjectStarted)
196 {
197 if (isControllerActive())
198 {
200 }
201 c.waitForCycleDuration();
202 }
203 });
204 }
205
206 std::string
208 {
209 return "NJointAdaptiveWipingController";
210 }
211
212 void
214 {
215 if (!started)
216 {
217 return;
218 }
219
220 if (!dmpCtrl)
221 {
222 return;
223 }
224
225 Eigen::VectorXf targetVels(6);
226 bool isPhaseStop = rt2CtrlData.getUpToDateReadBuffer().isPhaseStop;
227 if (isPhaseStop)
228 {
229 targetVels.setZero();
230 }
231 else
232 {
233
234 double deltaT = rt2CtrlData.getUpToDateReadBuffer().deltaT;
235 Eigen::Matrix4f currentPose = rt2CtrlData.getUpToDateReadBuffer().currentPose;
236 Eigen::VectorXf currentTwist = rt2CtrlData.getUpToDateReadBuffer().currentTwist;
237
238 LockGuardType guard{controllerMutex};
239 dmpCtrl->flow(deltaT, currentPose, currentTwist);
240
241 targetVels = dmpCtrl->getTargetVelocity();
242
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);
252 VirtualRobot::MathTools::Quaternion currentQ =
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;
263 debugOutputData.getWriteBuffer().deltaT = deltaT;
264 debugOutputData.commitWrite();
265 }
266
267 getWriterControlStruct().targetTSVel = targetVels;
269
270 dmpRunning = true;
271 }
272
273 void
274 NJointAdaptiveWipingController::rtRun(const IceUtil::Time& sensorValuesTimestamp,
275 const IceUtil::Time& timeSinceLastIteration)
276 {
277 double deltaT = timeSinceLastIteration.toSecondsDouble();
278
279 Eigen::Matrix4f currentPose = tcp->getPoseInRootFrame();
280 rt2UserData.getWriteBuffer().currentTcpPose = currentPose;
281 rt2UserData.getWriteBuffer().waitTimeForCalibration += deltaT;
282 rt2UserData.commitWrite();
283
284 Eigen::Vector3f currentToolDir;
285 currentToolDir.setZero();
286 Eigen::MatrixXf jacobi =
287 ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All);
288
289 Eigen::VectorXf qpos(positionSensors.size());
290 Eigen::VectorXf qvel(velocitySensors.size());
291 for (size_t i = 0; i < positionSensors.size(); ++i)
292 {
293 qpos(i) = positionSensors[i]->position;
294 qvel(i) = velocitySensors[i]->velocity;
295 }
296
297 qvel_filtered = (1 - cfg->velFilter) * qvel_filtered + cfg->velFilter * qvel;
298 Eigen::VectorXf currentTwist = jacobi * qvel_filtered;
299
300 Eigen::VectorXf targetVel(6);
301 Eigen::Vector3f axis;
302 axis.setZero();
303 targetVel.setZero();
304 Eigen::Vector3f forceInToolFrame;
305 forceInToolFrame << 0, 0, 0;
306
307 Eigen::Vector3f torqueInToolFrame;
308 torqueInToolFrame << 0, 0, 0;
309
310 float angle = 0;
311 if (firstRun || !dmpRunning)
312 {
313 lastPosition = currentPose.block<2, 1>(0, 3);
314 targetPose = currentPose;
315 firstRun = false;
316 filteredForce.setZero();
317 Eigen::Vector3f currentForce = forceSensor->force - forceOffset;
318
319 Eigen::Matrix3f forceFrameOri = rtGetRobot()
320 ->getSensor(cfg->forceSensorName)
321 ->getRobotNode()
322 ->getPoseInRootFrame()
323 .block<3, 3>(0, 0);
324 Eigen::Vector3f gravityInForceFrame = forceFrameOri.transpose() * gravityInRoot;
325 Eigen::Vector3f handGravity = handMass * gravityInForceFrame;
326 currentForce = currentForce - handGravity;
327
328 currentForceOffset = 0.1 * currentForceOffset + 0.9 * currentForce;
329 origHandOri = currentPose.block<3, 3>(0, 0);
330 toolTransform = origHandOri.transpose();
331 targetVel.setZero();
332 }
333 else
334 {
335 // communicate with DMP controller
337 targetVel = rtGetControlStruct().targetTSVel;
338 targetVel(2) = 0;
339
340 // calculate force
341 Eigen::Vector3f currentForce = forceSensor->force - forceOffset - currentForceOffset;
342
343 Eigen::Matrix3f forceFrameOri = rtGetRobot()
344 ->getSensor(cfg->forceSensorName)
345 ->getRobotNode()
346 ->getPoseInRootFrame()
347 .block<3, 3>(0, 0);
348 Eigen::Vector3f gravityInForceFrame = forceFrameOri.transpose() * gravityInRoot;
349 Eigen::Vector3f handGravity = handMass * gravityInForceFrame;
350
351 currentForce = currentForce - handGravity;
352 filteredForce =
353 (1 - cfg->forceFilter) * filteredForce + cfg->forceFilter * currentForce;
354
355 Eigen::Vector3f currentTorque = forceSensor->torque - torqueOffset;
356 Eigen::Vector3f handTorque = handCOM.cross(gravityInForceFrame);
357 currentTorque = currentTorque - handTorque;
358 filteredTorque =
359 (1 - cfg->forceFilter) * filteredTorque + cfg->forceFilter * currentTorque;
360
361 for (size_t i = 0; i < 3; ++i)
362 {
363 if (fabs(filteredForce(i)) > cfg->forceDeadZone)
364 {
365 filteredForce(i) -=
366 (filteredForce(i) / fabs(filteredForce(i))) * cfg->forceDeadZone;
367 }
368 else
369 {
370 filteredForce(i) = 0;
371 }
372 }
373
374 filteredForceInRoot = forceFrameOri * filteredForce;
375 filteredTorqueInRoot = forceFrameOri * filteredTorque;
376 float targetForce = user2rtData.getUpToDateReadBuffer().targetForce;
377
378 Eigen::Matrix3f currentHandOri = currentPose.block<3, 3>(0, 0);
379 Eigen::Matrix3f currentToolOri = currentHandOri * toolTransform;
380
381 forceInToolFrame = currentToolOri.transpose() * filteredForceInRoot;
382 torqueInToolFrame = currentToolOri.transpose() * filteredTorqueInRoot;
383
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);
387
388 currentToolDir = currentToolOri * oriToolDir;
389
390 for (int i = 3; i < 6; ++i)
391 {
392 targetVel(i) = 0;
393 }
394
395 // rotation changes
396
397 if (filteredForceInRoot.norm() > fabs(cfg->minimumReactForce))
398 {
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
406 .normalized(); // / projectedFilteredForceInRoot.norm();
407 currentToolDir.normalize();
408
409 axis = currentToolDir.cross(desiredToolDir);
410 axis = axis.normalized();
411 angle = acosf(currentToolDir.dot(desiredToolDir));
412
413
414 if (fabs(angle) < M_PI / 2 && fabs(angle) > cfg->frictionCone)
415 {
416 // sigmoid function
417 float adaptedAngularKp = cfg->angularKp / (1 + exp(10 * (angle - M_PI / 4)));
418 float angularKp = fmin(adaptedAngularKp, cfg->angularKp);
419
420 // test axis
421 Eigen::Vector3f fixedAxis;
422 if (axis(1) > 0)
423 {
424 fixedAxis << 0.0, 1.0, 0.0;
425 }
426 else
427 {
428 fixedAxis << 0.0, -1.0, 0.0;
429 }
430 Eigen::AngleAxisf desiredToolRot(angle - cfg->frictionCone, fixedAxis);
431 Eigen::Matrix3f desiredRotMat = desiredToolRot * Eigen::Matrix3f::Identity();
432
433 Eigen::Vector3f angularDiff =
434 VirtualRobot::MathTools::eigen3f2rpy(desiredRotMat);
435
436 targetVel.tail<3>() = angularKp * angularDiff;
437
438 //Eigen::Vector3f desiredRPY = VirtualRobot::MathTools::eigen3f2rpy(desiredRotMat);
439 Eigen::Vector3f checkedToolDir = desiredRotMat * currentToolDir;
440 checkedToolDir.normalize();
441 }
442 }
443 // integrate for targetPose
444 }
445
446 bool isPhaseStop = false;
447
448 float diff = (targetPose.block<2, 1>(0, 3) - currentPose.block<2, 1>(0, 3)).norm();
449 if (diff > cfg->phaseDist0)
450 {
451 isPhaseStop = true;
452 }
453
454 float dTf = (float)deltaT;
455
456
457 if (filteredForceInRoot.block<2, 1>(0, 0).norm() > cfg->dragForceDeadZone)
458 {
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);
465 lastDiff = diff;
466 }
467 else
468 {
469 adaptK(0) = fmin(adaptK(0) + fabs(dTf * cfg->adaptCoeff), kpos(0));
470 adaptK(1) = fmin(adaptK(1) + fabs(dTf * cfg->adaptCoeff), kpos(1));
471 }
472 adaptK(2) = kpos(2);
473
474 // adaptive control with distance
475
476
477 targetPose.block<3, 1>(0, 3) =
478 targetPose.block<3, 1>(0, 3) + dTf * targetVel.block<3, 1>(0, 0);
479 Eigen::Matrix3f rotMat = VirtualRobot::MathTools::rpy2eigen3f(
480 dTf * targetVel(3), dTf * targetVel(4), dTf * targetVel(5));
481 targetPose.block<3, 3>(0, 0) = rotMat * targetPose.block<3, 3>(0, 0);
482
483 if (isPhaseStop)
484 {
485 Eigen::Vector2f currentXY = currentPose.block<2, 1>(0, 3);
486 if ((lastPosition - currentXY).norm() < cfg->changePositionTolerance)
487 {
488 changeTimer += deltaT;
489 }
490 else
491 {
492 lastPosition = currentPose.block<2, 1>(0, 3);
493 changeTimer = 0;
494 }
495
496 if (changeTimer > cfg->changeTimerThreshold)
497 {
498 targetPose(0, 3) = currentPose(0, 3);
499 targetPose(1, 3) = currentPose(1, 3);
500 isPhaseStop = false;
501 changeTimer = 0;
502 }
503 }
504 else
505 {
506 changeTimer = 0;
507 }
508
509
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];
512
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];
515
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];
518
519
520 debugRT.getWriteBuffer().currentToolDir =
521 tcp->getRobot()->getRootNode()->toGlobalCoordinateSystemVec(currentToolDir);
522 debugRT.getWriteBuffer().targetPose = targetPose;
523 debugRT.getWriteBuffer().globalPose =
524 tcp->getRobot()->getRootNode()->toGlobalCoordinateSystem(targetPose);
525 debugRT.getWriteBuffer().currentPose = currentPose;
526 debugRT.getWriteBuffer().filteredForceInRoot = filteredForceInRoot;
527 debugRT.getWriteBuffer().rotationAxis = axis;
528 debugRT.getWriteBuffer().filteredForce = forceInToolFrame;
529 debugRT.getWriteBuffer().globalFilteredForce =
530 tcp->getRobot()->getRootNode()->toGlobalCoordinateSystemVec(filteredForceInRoot);
531 debugRT.getWriteBuffer().targetVel = targetVel;
532 debugRT.getWriteBuffer().adaptK = adaptK;
533 debugRT.getWriteBuffer().isPhaseStop = isPhaseStop;
534 debugRT.getWriteBuffer().rotAngle = angle;
535 debugRT.getWriteBuffer().currentTwist = currentTwist;
536 debugRT.getWriteBuffer().filteredTorque = torqueInToolFrame;
537
538
539 debugRT.commitWrite();
540
541 rt2CtrlData.getWriteBuffer().currentPose = currentPose;
542 rt2CtrlData.getWriteBuffer().currentTwist = currentTwist;
543 rt2CtrlData.getWriteBuffer().deltaT = deltaT;
544 rt2CtrlData.getWriteBuffer().currentTime += deltaT;
545 rt2CtrlData.getWriteBuffer().isPhaseStop = isPhaseStop;
546 rt2CtrlData.commitWrite();
547
548 // Eigen::Matrix3f rotVel = VirtualRobot::MathTools::rpy2eigen3f(targetVel(3) * dTf, targetVel(4) * dTf, targetVel(5) * dTf);
549 // targetPose.block<3, 3>(0, 0) = rotVel * targetPose.block<3, 3>(0, 0);
550
551 // inverse dynamic controller
552 jacobi.block<3, 8>(0, 0) = 0.001 * jacobi.block<3, 8>(0, 0); // convert mm to m
553
554
555 Eigen::Vector6f jointControlWrench;
556 {
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);
565
566 Eigen::Vector3f linearVel = adaptK.cwiseProduct(desiredPosition - currentTCPPosition);
567
568 // if (isPhaseStop)
569 // {
570 // linearVel = ((float)cfg->phaseKpPos) * (desiredPosition - currentTCPPosition);
571 // for (size_t i = 0; i < 3; ++i)
572 // {
573 // linearVel(i) = fmin(cfg->maxLinearVel, linearVel(i));
574 // }
575 // }
576 // else
577 // {
578 // linearVel = kpos.cwiseProduct(desiredPosition - currentTCPPosition);
579 // }
580 Eigen::Vector3f tcpDesiredForce =
581 0.001 * linearVel + dpos.cwiseProduct(-currentTCPLinearVelocity);
582
583 Eigen::Vector3f currentTCPAngularVelocity;
584 currentTCPAngularVelocity << currentTwist(3), currentTwist(4), currentTwist(5);
585 Eigen::Matrix3f currentRotMat = currentPose.block<3, 3>(0, 0);
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;
591 }
592
593
594 Eigen::MatrixXf I = Eigen::MatrixXf::Identity(targets.size(), targets.size());
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;
600
601 // torque filter (maybe)
602 for (size_t i = 0; i < targets.size(); ++i)
603 {
604 targets.at(i)->torque = jointDesiredTorques(i);
605
606 if (!targets.at(i)->isValid())
607 {
608 targets.at(i)->torque = 0.0f;
609 }
610 else
611 {
612 if (fabs(targets.at(i)->torque) > fabs(cfg->maxJointTorque))
613 {
614 targets.at(i)->torque = fabs(cfg->maxJointTorque) *
615 (targets.at(i)->torque / fabs(targets.at(i)->torque));
616 }
617 }
618 }
619 }
620
621 void
623 const Ice::Current&)
624 {
625 ARMARX_INFO << "Learning DMP ... ";
626
627 LockGuardType guard{controllerMutex};
628 dmpCtrl->learnDMPFromFiles(fileNames);
629 }
630
631 void
633 const Ice::Current&)
634 {
635 ARMARX_INFO << "Learning DMP ... ";
637 TrajectoryPtr dmpTraj = TrajectoryPtr::dynamicCast(trajectory);
639
640 LockGuardType guard{controllerMutex};
641 dmpCtrl->learnDMPFromTrajectory(dmpTraj);
642 }
643
644 void
645 NJointAdaptiveWipingController::setSpeed(Ice::Double times, const Ice::Current&)
646 {
647 LockGuardType guard{controllerMutex};
648 dmpCtrl->setSpeed(times);
649 }
650
651 void
652 NJointAdaptiveWipingController::setGoals(const Ice::DoubleSeq& goals, const Ice::Current& ice)
653 {
654 LockGuardType guard{controllerMutex};
655 dmpCtrl->setGoalPoseVec(goals);
656 }
657
658 void
659 NJointAdaptiveWipingController::setAmplitude(Ice::Double amp, const Ice::Current&)
660 {
661 LockGuardType guard{controllerMutex};
662 dmpCtrl->setAmplitude(amp);
663 }
664
665 void
667 const Ice::Current&)
668 {
670 user2rtData.getWriteBuffer().targetForce = targetForce;
671 user2rtData.commitWrite();
672 }
673
674 void
675 NJointAdaptiveWipingController::runDMP(const Ice::DoubleSeq& goals,
676 Ice::Double tau,
677 const Ice::Current&)
678 {
679 firstRun = true;
680 while (firstRun || rt2UserData.getUpToDateReadBuffer().waitTimeForCalibration <
681 cfg->waitTimeForCalibration)
682 {
683 usleep(100);
684 }
685
686
687 Eigen::Matrix4f pose = rt2UserData.getUpToDateReadBuffer().currentTcpPose;
688
689 LockGuardType guard{controllerMutex};
690 dmpCtrl->prepareExecution(dmpCtrl->eigen4f2vec(pose), goals);
691 dmpCtrl->setSpeed(tau);
692
693 ARMARX_IMPORTANT << "run DMP";
694 started = true;
695 dmpRunning = false;
696 }
697
698 void
700 const DebugDrawerInterfacePrx& debugDrawer,
701 const DebugObserverInterfacePrx& debugObs)
702 {
703 std::string datafieldName;
704 std::string debugName = "Periodic";
705 StringVariantBaseMap datafields;
706
707 Eigen::Matrix4f targetPoseDebug = debugRT.getUpToDateReadBuffer().targetPose;
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));
711
712 Eigen::Matrix4f currentPoseDebug = debugRT.getUpToDateReadBuffer().currentPose;
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));
716
717 Eigen::Vector3f filteredForce = debugRT.getUpToDateReadBuffer().filteredForce;
718 datafields["filteredforceInTool_x"] = new Variant(filteredForce(0));
719 datafields["filteredforceInTool_y"] = new Variant(filteredForce(1));
720 datafields["filteredforceInTool_z"] = new Variant(filteredForce(2));
721
722 Eigen::Vector3f filteredTorque = debugRT.getUpToDateReadBuffer().filteredTorque;
723 datafields["filteredtorqueInTool_x"] = new Variant(filteredTorque(0));
724 datafields["filteredtorqueInTool_y"] = new Variant(filteredTorque(1));
725 datafields["filteredtorqueInTool_z"] = new Variant(filteredTorque(2));
726
727
728 Eigen::Vector3f filteredForceInRoot = debugRT.getUpToDateReadBuffer().filteredForceInRoot;
729 datafields["filteredForceInRoot_x"] = new Variant(filteredForceInRoot(0));
730 datafields["filteredForceInRoot_y"] = new Variant(filteredForceInRoot(1));
731 datafields["filteredForceInRoot_z"] = new Variant(filteredForceInRoot(2));
732
733 Eigen::Vector3f rotationAxis = debugRT.getUpToDateReadBuffer().rotationAxis;
734 datafields["rotationAxis_x"] = new Variant(rotationAxis(0));
735 datafields["rotationAxis_y"] = new Variant(rotationAxis(1));
736 datafields["rotationAxis_z"] = new Variant(rotationAxis(2));
737
738 Eigen::Vector3f reactForce = debugRT.getUpToDateReadBuffer().reactForce;
739 datafields["reactForce_x"] = new Variant(reactForce(0));
740 datafields["reactForce_y"] = new Variant(reactForce(1));
741 datafields["reactForce_z"] = new Variant(reactForce(2));
742
743 Eigen::VectorXf targetVel = debugRT.getUpToDateReadBuffer().targetVel;
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));
750
751 Eigen::VectorXf currentTwist = debugRT.getUpToDateReadBuffer().currentTwist;
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));
758
759
760 Eigen::Vector3f adaptK = debugRT.getUpToDateReadBuffer().adaptK;
761 datafields["adaptK_x"] = new Variant(adaptK(0));
762 datafields["adaptK_y"] = new Variant(adaptK(1));
763
764 datafields["canVal"] = new Variant(debugOutputData.getUpToDateReadBuffer().currentCanVal);
765 datafields["deltaT"] = new Variant(debugOutputData.getUpToDateReadBuffer().deltaT);
766
767 datafields["PhaseStop"] = new Variant(debugRT.getUpToDateReadBuffer().isPhaseStop);
768 datafields["rotAngle"] = new Variant(debugRT.getUpToDateReadBuffer().rotAngle);
769
770
771 // datafields["targetVel_rx"] = new Variant(targetVel(3));
772 // datafields["targetVel_ry"] = new Variant(targetVel(4));
773 // datafields["targetVel_rz"] = new Variant(targetVel(5));
774
775 // auto values = debugOutputData.getUpToDateReadBuffer().latestTargetVelocities;
776 // for (auto& pair : values)
777 // {
778 // datafieldName = pair.first + "_" + debugName;
779 // datafields[datafieldName] = new Variant(pair.second);
780 // }
781
782 // auto currentPose = debugOutputData.getUpToDateReadBuffer().currentPose;
783 // for (auto& pair : currentPose)
784 // {
785 // datafieldName = pair.first + "_" + debugName;
786 // datafields[datafieldName] = new Variant(pair.second);
787 // }
788
789 // datafieldName = "canVal_" + debugName;
790 // datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().currentCanVal);
791 // datafieldName = "mpcFactor_" + debugName;
792 // datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().mpcFactor);
793 // datafieldName = "error_" + debugName;
794 // datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().error);
795 // datafieldName = "posError_" + debugName;
796 // datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().posError);
797 // datafieldName = "oriError_" + debugName;
798 // datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().oriError);
799 // datafieldName = "deltaT_" + debugName;
800 // datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().deltaT);
801
802 datafieldName = "PeriodicDMP";
803 debugObs->setDebugChannel(datafieldName, datafields);
804
805
806 // draw force;
807 Eigen::Matrix4f globalPose = debugRT.getUpToDateReadBuffer().globalPose;
808 Eigen::Vector3f handPosition = globalPose.block<3, 1>(0, 3);
809 Eigen::Vector3f forceDir = debugRT.getUpToDateReadBuffer().globalFilteredForce;
810
811 debugDrawer->setArrowVisu("Force",
812 "currentForce",
813 new Vector3(handPosition),
814 new Vector3(forceDir),
815 DrawColor{0, 0, 1, 1},
816 10 * forceDir.norm(),
817 3);
818
819 // draw direction of the tool
820 Eigen::Vector3f currentToolDir = debugRT.getUpToDateReadBuffer().currentToolDir;
821 debugDrawer->setArrowVisu("Tool",
822 "Tool",
823 new Vector3(handPosition),
824 new Vector3(currentToolDir),
825 DrawColor{1, 0, 0, 1},
826 100,
827 3);
828 debugDrawer->setPoseVisu("target", "targetPose", new Pose(globalPose));
829 }
830
831 void
836
837
838} // namespace armarx::control::deprecated_njoint_mp_controller::adaptive
#define float
Definition 16_Level.h:22
#define M_PI
Definition MathTools.h:17
constexpr T c
Brief description of class JointControlTargetBase.
This util class helps with keeping a cycle time during a control cycle.
Definition CycleUtil.h:41
ArmarXObjectSchedulerPtr getObjectScheduler() const
int getState() const
Retrieve current state of the ManagedIceObject.
bool isControllerActive(const Ice::Current &=Ice::emptyCurrent) const final override
const SensorValueBase * useSensorValue(const std::string &sensorDeviceName) const
Get a const ptr to the given SensorDevice's SensorValue.
void runTask(const std::string &taskName, Task &&task)
Executes a given task in a separate thread from the Application ThreadPool.
const VirtualRobot::RobotPtr & useSynchronizedRtRobot(bool updateCollisionModel=false)
Requests a VirtualRobot for use in rtRun *.
const VirtualRobot::RobotPtr & rtGetRobot()
TODO make protected and use attorneys.
ControlTargetBase * useControlTarget(const std::string &deviceName, const std::string &controlMode)
Declares to calculate the ControlTarget for the given ControlDevice in the given ControlMode when rtR...
The Pose class.
Definition Pose.h:243
The SensorValueBase class.
const T * asA() const
The Variant class is described here: Variants.
Definition Variant.h:224
The Vector3 class.
Definition Pose.h:113
void rtRun(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration)
TODO make protected and use attorneys.
NJointAdaptiveWipingController(const RobotUnitPtr &, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &)
virtual void onPublish(const SensorAndControl &, const DebugDrawerInterfacePrx &, const DebugObserverInterfacePrx &)
#define ARMARX_CHECK_EXPRESSION(expression)
This macro evaluates the expression and if it turns out to be false it will throw an ExpressionExcept...
#define ARMARX_CHECK_LESS(lhs, rhs)
This macro evaluates whether lhs is less (<) than rhs and if it turns out to be false it will throw a...
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_IMPORTANT
The logging level for always important information, but expected behaviour (in contrast to ARMARX_WAR...
Definition Logging.h:190
Matrix< float, 6, 1 > Vector6f
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
NJointControllerRegistration< NJointAdaptiveWipingController > registrationControllerNJointAdaptiveWipingController("NJointAdaptiveWipingController")
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugObserverInterface > DebugObserverInterfacePrx
std::map< std::string, VariantBasePtr > StringVariantBaseMap
IceInternal::Handle< Trajectory > TrajectoryPtr
Definition Trajectory.h:52
IceUtil::Handle< class RobotUnit > RobotUnitPtr
Definition FTSensor.h:34
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugDrawerInterface > DebugDrawerInterfacePrx
detail::ControlThreadOutputBufferEntry SensorAndControl
double norm(const Point &a)
Definition point.hpp:102
double angle(const Point &a, const Point &b, const Point &c)
Definition point.hpp:109