NJointPeriodicTSDMPForwardVelController.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/Robot.h>
7#include <VirtualRobot/RobotNodeSet.h>
8
10
17
19{
20 NJointControllerRegistration<NJointPeriodicTSDMPForwardVelController>
22 "NJointPeriodicTSDMPForwardVelController");
23
25 const RobotUnitPtr& robUnit,
26 const armarx::NJointControllerConfigPtr& config,
28 {
30 cfg = NJointPeriodicTSDMPControllerConfigPtr::dynamicCast(config);
31 ARMARX_CHECK_EXPRESSION(!cfg->nodeSetName.empty());
32 VirtualRobot::RobotNodeSetPtr rns = rtGetRobot()->getRobotNodeSet(cfg->nodeSetName);
33
34 ARMARX_CHECK_EXPRESSION(rns) << cfg->nodeSetName;
35 for (size_t i = 0; i < rns->getSize(); ++i)
36 {
37 std::string jointName = rns->getNode(i)->getName();
38 ControlTargetBase* ct = useControlTarget(jointName, ControlModes::Velocity1DoF);
39 const SensorValueBase* sv = useSensorValue(jointName);
40 targets.push_back(ct->asA<ControlTarget1DoFActuatorVelocity>());
41
42 const SensorValue1DoFActuatorVelocity* velocitySensor =
43 sv->asA<SensorValue1DoFActuatorVelocity>();
44 const SensorValue1DoFActuatorPosition* positionSensor =
45 sv->asA<SensorValue1DoFActuatorPosition>();
46
47 velocitySensors.push_back(velocitySensor);
48 positionSensors.push_back(positionSensor);
49 };
50
51 tcp = rns->getTCP();
52 // set tcp controller
53 tcpController.reset(new CartesianVelocityController(rns, tcp));
54 nodeSetName = cfg->nodeSetName;
55 ik.reset(new VirtualRobot::DifferentialIK(
56 rns, rns->getRobot()->getRootNode(), VirtualRobot::JacobiProvider::eSVDDamped));
57
58
59 tsvmp::TaskSpaceDMPControllerConfig taskSpaceDMPConfig;
60 taskSpaceDMPConfig.motionTimeDuration = cfg->timeDuration;
61 taskSpaceDMPConfig.DMPKernelSize = cfg->kernelSize;
62 taskSpaceDMPConfig.DMPAmplitude = cfg->dmpAmplitude;
63
64 taskSpaceDMPConfig.DMPMode = "Linear";
65 taskSpaceDMPConfig.DMPStyle = "Periodic";
66 taskSpaceDMPConfig.phaseStopParas.goDist = cfg->phaseDist0;
67 taskSpaceDMPConfig.phaseStopParas.backDist = cfg->phaseDist1;
68 taskSpaceDMPConfig.phaseStopParas.Kpos = cfg->phaseKpPos;
69 taskSpaceDMPConfig.phaseStopParas.Kori = cfg->phaseKpOri;
70 taskSpaceDMPConfig.phaseStopParas.mm2radi = cfg->posToOriRatio;
71 taskSpaceDMPConfig.phaseStopParas.maxValue = cfg->phaseL;
72 taskSpaceDMPConfig.phaseStopParas.slop = cfg->phaseK;
73 taskSpaceDMPConfig.phaseStopParas.Dpos = 0;
74 taskSpaceDMPConfig.phaseStopParas.Dori = 0;
75
76
77 dmpCtrl.reset(new tsvmp::TaskSpaceDMPController("periodicDMP", taskSpaceDMPConfig, false));
78
80 initData.targetPose = tcp->getPoseInRootFrame();
81 initData.targetTSVel.resize(6);
82 for (size_t i = 0; i < 6; ++i)
83 {
84 initData.targetTSVel(i) = 0;
85 }
86 reinitTripleBuffer(initData);
87
88 finished = false;
89 firstRun = true;
90
91
92 const SensorValueBase* svlf =
93 robUnit->getSensorDevice(cfg->forceSensorName)->getSensorValue();
94 forceSensor = svlf->asA<SensorValueForceTorque>();
95
96 forceOffset.setZero();
97 filteredForce.setZero();
98
99 UserToRTData initUserData;
100 initUserData.targetForce = 0;
101 user2rtData.reinitAllBuffers(initUserData);
102
103 oriToolDir << 0, 0, 1;
104
105 kpf = cfg->Kpf;
106 }
107
108 std::string
110 {
111 return "NJointPeriodicTSDMPForwardVelController";
112 }
113
114 void
116 {
117 if (!started)
118 {
119 return;
120 }
121
122 if (!rt2CtrlData.updateReadBuffer() || !dmpCtrl)
123 {
124 return;
125 }
126
127 double deltaT = rt2CtrlData.getReadBuffer().deltaT;
128 Eigen::Matrix4f currentPose = rt2CtrlData.getReadBuffer().currentPose;
129 Eigen::VectorXf currentTwist = rt2CtrlData.getReadBuffer().currentTwist;
130
131 LockGuardType guard{controllerMutex};
132 dmpCtrl->flow(deltaT, currentPose, currentTwist);
133
134 Eigen::VectorXf targetVels = dmpCtrl->getTargetVelocity();
135 Eigen::Matrix4f targetPose = dmpCtrl->getIntegratedPoseMat();
136
137 debugOutputData.getWriteBuffer().latestTargetVelocities["x_vel"] = targetVels(0);
138 debugOutputData.getWriteBuffer().latestTargetVelocities["y_vel"] = targetVels(1);
139 debugOutputData.getWriteBuffer().latestTargetVelocities["z_vel"] = targetVels(2);
140 debugOutputData.getWriteBuffer().latestTargetVelocities["roll_vel"] = targetVels(3);
141 debugOutputData.getWriteBuffer().latestTargetVelocities["pitch_vel"] = targetVels(4);
142 debugOutputData.getWriteBuffer().latestTargetVelocities["yaw_vel"] = targetVels(5);
143 debugOutputData.getWriteBuffer().currentPose["currentPose_x"] = currentPose(0, 3);
144 debugOutputData.getWriteBuffer().currentPose["currentPose_y"] = currentPose(1, 3);
145 debugOutputData.getWriteBuffer().currentPose["currentPose_z"] = currentPose(2, 3);
146 VirtualRobot::MathTools::Quaternion currentQ =
147 VirtualRobot::MathTools::eigen4f2quat(currentPose);
148 debugOutputData.getWriteBuffer().currentPose["currentPose_qw"] = currentQ.w;
149 debugOutputData.getWriteBuffer().currentPose["currentPose_qx"] = currentQ.x;
150 debugOutputData.getWriteBuffer().currentPose["currentPose_qy"] = currentQ.y;
151 debugOutputData.getWriteBuffer().currentPose["currentPose_qz"] = currentQ.z;
152 debugOutputData.getWriteBuffer().currentCanVal = dmpCtrl->debugData.canVal;
153 debugOutputData.getWriteBuffer().mpcFactor = dmpCtrl->debugData.mpcFactor;
154 debugOutputData.getWriteBuffer().error = dmpCtrl->debugData.poseError;
155 debugOutputData.getWriteBuffer().posError = dmpCtrl->debugData.posiError;
156 debugOutputData.getWriteBuffer().oriError = dmpCtrl->debugData.oriError;
157 debugOutputData.getWriteBuffer().deltaT = deltaT;
158 debugOutputData.commitWrite();
159
160 getWriterControlStruct().targetTSVel = targetVels;
161 getWriterControlStruct().targetPose = targetPose;
163
164 dmpRunning = true;
165 }
166
167 void
168 NJointPeriodicTSDMPForwardVelController::rtRun(const IceUtil::Time& sensorValuesTimestamp,
169 const IceUtil::Time& timeSinceLastIteration)
170 {
171 double deltaT = timeSinceLastIteration.toSecondsDouble();
172
173 Eigen::Matrix4f currentPose = tcp->getPoseInRootFrame();
174 rt2UserData.getWriteBuffer().currentTcpPose = currentPose;
175 rt2UserData.getWriteBuffer().waitTimeForCalibration += deltaT;
176 rt2UserData.commitWrite();
177
178 if (firstRun || !dmpRunning)
179 {
180 targetPose = currentPose;
181 for (size_t i = 0; i < targets.size(); ++i)
182 {
183 targets.at(i)->velocity = 0.0f;
184 }
185 firstRun = false;
186 filteredForce.setZero();
187
188 Eigen::Matrix3f currentHandOri = currentPose.block<3, 3>(0, 0);
189 toolTransform = currentHandOri.transpose();
190 // force calibration
191 if (!dmpRunning)
192 {
193 forceOffset =
194 (1 - cfg->forceFilter) * forceOffset + cfg->forceFilter * forceSensor->force;
195 }
196 }
197 else
198 {
199
200 Eigen::MatrixXf jacobi =
201 ik->getJacobianMatrix(tcp, VirtualRobot::IKSolver::CartesianSelection::All);
202
203 Eigen::VectorXf qvel;
204 qvel.resize(velocitySensors.size());
205 for (size_t i = 0; i < velocitySensors.size(); ++i)
206 {
207 qvel(i) = velocitySensors[i]->velocity;
208 }
209
210 Eigen::VectorXf tcptwist = jacobi * qvel;
211
212 rt2CtrlData.getWriteBuffer().currentPose = currentPose;
213 rt2CtrlData.getWriteBuffer().currentTwist = tcptwist;
214 rt2CtrlData.getWriteBuffer().deltaT = deltaT;
215 rt2CtrlData.getWriteBuffer().currentTime += deltaT;
216 rt2CtrlData.commitWrite();
217
218
219 // forward controller
221 Eigen::VectorXf targetVel = rtGetControlStruct().targetTSVel;
222 // Eigen::Matrix4f targetPose = rtGetControlStruct().targetPose;
223
224 // force detection
225 // filteredForce = (1 - cfg->forceFilter) * filteredForce + cfg->forceFilter * (forceSensor->force - forceOffset);
226 // Eigen::Vector3f filteredForceInRoot = rtGetRobot()->getRobotNode(cfg->forceFrameName)->toGlobalCoordinateSystemVec(filteredForce);
227 // filteredForceInRoot = rtGetRobot()->getRootNode()->toLocalCoordinateSystemVec(filteredForceInRoot);
228 // float targetForce = user2rtData.getUpToDateReadBuffer().targetForce;
229
230 // Eigen::Matrix3f currentHandOri = currentPose.block<3, 3>(0, 0);
231 // Eigen::Matrix3f currentToolOri = toolTransform * currentHandOri;
232 // targetVel.block<3, 1>(0, 0) = currentToolOri * targetVel.block<3, 1>(0, 0);
233 // Eigen::Vector3f currentToolDir = currentToolOri * oriToolDir;
234
235 // ARMARX_IMPORTANT << "original force: " << forceSensor->force;
236 // ARMARX_IMPORTANT << "filteredForce: " << filteredForce;
237 // ARMARX_IMPORTANT << "filteredForceInRoot: " << filteredForceInRoot;
238 // ARMARX_IMPORTANT << "forceOffset: " << forceOffset;
239 // ARMARX_IMPORTANT << "currentToolOri: " << currentToolOri;
240
241 for (size_t i = 3; i < 6; ++i)
242 {
243 targetVel(i) = 0;
244 }
245
246 // float forceCtrl = kpf * (targetForce - filteredForceInRoot.norm());
247 // Eigen::Vector3f desiredZVel = - forceCtrl * (currentToolDir / currentToolDir.norm());
248 // targetVel.block<3, 1>(0, 0) += desiredZVel;
249
250 // dead zone for force
251 // if (filteredForceInRoot.norm() > cfg->minimumReactForce)
252 // {
253 // // rotation changes
254 // Eigen::Vector3f axis = oriToolDir.cross(filteredForceInRoot);
255 // float angle = oriToolDir.dot(filteredForceInRoot);
256 // Eigen::AngleAxisf desiredToolOri(angle, axis);
257 // Eigen::Matrix3f desiredHandOri = toolTransform.transpose() * desiredToolOri;
258 // Eigen::Matrix3f desiredRotMat = desiredHandOri * currentHandOri.transpose();
259 // Eigen::Vector3f desiredRPY = VirtualRobot::MathTools::eigen3f2rpy(desiredRotMat);
260 // for (size_t i = 3; i < 6; ++i)
261 // {
262 // targetVel(i) = desiredRPY(i - 3);
263 // }
264 // }}
265
266 // ARMARX_IMPORTANT << "targetVel: " << targetVel;
267 // ARMARX_IMPORTANT << "targetPose: " << targetPose;
268
269 // targetPose.block<3, 1>(0, 3) += deltaT * targetVel.block<3, 1>(0, 0);
270 // Eigen::Matrix3f rotVel = VirtualRobot::MathTools::rpy2eigen3f(targetVel(3) * deltaT, targetVel(4) * deltaT, targetVel(5) * deltaT);
271 // targetPose.block<3, 3>(0, 0) = rotVel * targetPose.block<3, 3>(0, 0);
272
273 float dTf = (float)deltaT;
274 targetPose.block<3, 1>(0, 3) =
275 targetPose.block<3, 1>(0, 3) + dTf * targetVel.block<3, 1>(0, 0);
276 Eigen::Matrix3f rotVel = VirtualRobot::MathTools::rpy2eigen3f(
277 targetVel(3) * dTf, targetVel(4) * dTf, targetVel(5) * dTf);
278 targetPose.block<3, 3>(0, 0) = rotVel * targetPose.block<3, 3>(0, 0);
279
280 ARMARX_IMPORTANT << "targetVel: " << targetVel.block<3, 1>(0, 0);
281 ARMARX_IMPORTANT << "targetPose: " << targetPose;
282 ARMARX_IMPORTANT << "deltaT: " << deltaT;
283
284 Eigen::Matrix3f diffMat =
285 targetPose.block<3, 3>(0, 0) * currentPose.block<3, 3>(0, 0).inverse();
286 Eigen::Vector3f errorRPY = VirtualRobot::MathTools::eigen3f2rpy(diffMat);
287
288 Eigen::VectorXf rtTargetVel = targetVel;
289 rtTargetVel.block<3, 1>(0, 0) +=
290 cfg->Kpos * (targetPose.block<3, 1>(0, 3) - currentPose.block<3, 1>(0, 3));
291 rtTargetVel.block<3, 1>(3, 0) += cfg->Kori * errorRPY;
292
293 float normLinearVelocity = rtTargetVel.block<3, 1>(0, 0).norm();
294 if (normLinearVelocity > fabs(cfg->maxLinearVel))
295 {
296 rtTargetVel.block<3, 1>(0, 0) =
297 fabs(cfg->maxLinearVel) * rtTargetVel.block<3, 1>(0, 0) / normLinearVelocity;
298 }
299
300 float normAngularVelocity = rtTargetVel.block<3, 1>(3, 0).norm();
301 if (normAngularVelocity > fabs(cfg->maxAngularVel))
302 {
303 rtTargetVel.block<3, 1>(3, 0) =
304 fabs(cfg->maxAngularVel) * rtTargetVel.block<3, 1>(3, 0) / normAngularVelocity;
305 }
306
307
308 // cartesian vel controller
309
310 Eigen::VectorXf jnv = Eigen::VectorXf::Zero(tcpController->rns->getSize());
311 if (cfg->avoidJointLimitsKp > 0)
312 {
313 jnv += cfg->avoidJointLimitsKp * tcpController->calculateJointLimitAvoidance();
314 }
315
316 Eigen::VectorXf jointTargetVelocities = tcpController->calculate(
317 rtTargetVel, jnv, VirtualRobot::IKSolver::CartesianSelection::All);
318 for (size_t i = 0; i < targets.size(); ++i)
319 {
320 targets.at(i)->velocity = jointTargetVelocities(i);
321 if (!targets.at(i)->isValid())
322 {
323 targets.at(i)->velocity = 0.0f;
324 }
325 else
326 {
327 if (fabs(targets.at(i)->velocity) > fabs(cfg->maxJointVel))
328 {
329 targets.at(i)->velocity =
330 fabs(cfg->maxJointVel) *
331 (targets.at(i)->velocity / fabs(targets.at(i)->velocity));
332 }
333 }
334 }
335 }
336 }
337
338 void
340 const Ice::Current&)
341 {
342 ARMARX_INFO << "Learning DMP ... ";
343
344 LockGuardType guard{controllerMutex};
345 dmpCtrl->learnDMPFromFiles(fileNames);
346 }
347
348 void
349 NJointPeriodicTSDMPForwardVelController::setSpeed(Ice::Double times, const Ice::Current&)
350 {
351 LockGuardType guard{controllerMutex};
352 dmpCtrl->setSpeed(times);
353 }
354
355 void
357 const Ice::Current& ice)
358 {
359 LockGuardType guard{controllerMutex};
360 dmpCtrl->setGoalPoseVec(goals);
361 }
362
363 void
364 NJointPeriodicTSDMPForwardVelController::setAmplitude(Ice::Double amp, const Ice::Current&)
365 {
366 LockGuardType guard{controllerMutex};
367 dmpCtrl->setAmplitude(amp);
368 }
369
370 void
372 double tau,
373 const Ice::Current&)
374 {
375 firstRun = true;
376 while (firstRun || rt2UserData.getUpToDateReadBuffer().waitTimeForCalibration <
377 cfg->waitTimeForCalibration)
378 {
379 usleep(100);
380 }
381
382 Eigen::Matrix4f pose = rt2UserData.getUpToDateReadBuffer().currentTcpPose;
383 LockGuardType guard{controllerMutex};
384 dmpCtrl->prepareExecution(dmpCtrl->eigen4f2vec(pose), goals);
385 dmpCtrl->setSpeed(tau);
386 finished = false;
387
388 ARMARX_INFO << "run DMP";
389 started = true;
390 dmpRunning = false;
391 }
392
393 void
396 const DebugObserverInterfacePrx& debugObs)
397 {
398 std::string datafieldName;
399 std::string debugName = "Periodic";
400 StringVariantBaseMap datafields;
401 auto values = debugOutputData.getUpToDateReadBuffer().latestTargetVelocities;
402 for (auto& pair : values)
403 {
404 datafieldName = pair.first + "_" + debugName;
405 datafields[datafieldName] = new Variant(pair.second);
406 }
407
408 auto currentPose = debugOutputData.getUpToDateReadBuffer().currentPose;
409 for (auto& pair : currentPose)
410 {
411 datafieldName = pair.first + "_" + debugName;
412 datafields[datafieldName] = new Variant(pair.second);
413 }
414
415 datafieldName = "canVal_" + debugName;
416 datafields[datafieldName] =
417 new Variant(debugOutputData.getUpToDateReadBuffer().currentCanVal);
418 datafieldName = "mpcFactor_" + debugName;
419 datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().mpcFactor);
420 datafieldName = "error_" + debugName;
421 datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().error);
422 datafieldName = "posError_" + debugName;
423 datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().posError);
424 datafieldName = "oriError_" + debugName;
425 datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().oriError);
426 datafieldName = "deltaT_" + debugName;
427 datafields[datafieldName] = new Variant(debugOutputData.getUpToDateReadBuffer().deltaT);
428 datafieldName = "DMPController_" + debugName;
429
430 debugObs->setDebugChannel(datafieldName, datafields);
431 }
432
433 void
435 {
436 ARMARX_INFO << "init ...";
437
438 RTToControllerData initSensorData;
439 initSensorData.deltaT = 0;
440 initSensorData.currentTime = 0;
441 initSensorData.currentPose = tcp->getPoseInRootFrame();
442 initSensorData.currentTwist.setZero();
443 rt2CtrlData.reinitAllBuffers(initSensorData);
444
445 RTToUserData initInterfaceData;
446 initInterfaceData.currentTcpPose = tcp->getPoseInRootFrame();
447 rt2UserData.reinitAllBuffers(initInterfaceData);
448
449
450 started = false;
451 runTask("NJointPeriodicTSDMPForwardVelController",
452 [&]
453 {
454 CycleUtil c(1);
455 getObjectScheduler()->waitForObjectStateMinimum(eManagedIceObjectStarted);
456 while (getState() == eManagedIceObjectStarted)
457 {
458 if (isControllerActive())
459 {
461 }
462 c.waitForCycleDuration();
463 }
464 });
465 }
466
467 void
472
473
474} // namespace armarx::control::deprecated_njoint_mp_controller::task_space
#define float
Definition 16_Level.h:22
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...
void reinitTripleBuffer(const NJointPeriodicTSDMPForwardVelControllerControlData &initial)
The SensorValueBase class.
const T * asA() const
The Variant class is described here: Variants.
Definition Variant.h:224
void rtRun(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration)
TODO make protected and use attorneys.
NJointPeriodicTSDMPForwardVelController(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_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
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
NJointControllerRegistration< NJointPeriodicTSDMPForwardVelController > registrationControllerNJointPeriodicTSDMPForwardVelController("NJointPeriodicTSDMPForwardVelController")
::IceInternal::ProxyHandle<::IceProxy::armarx::DebugObserverInterface > DebugObserverInterfacePrx
std::map< std::string, VariantBasePtr > StringVariantBaseMap
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