NJointJSDMPController.cpp
Go to the documentation of this file.
2
3#include <boost/archive/text_iarchive.hpp>
4#include <boost/archive/text_oarchive.hpp>
5
6#include <Eigen/Dense>
7
8#include <VirtualRobot/Robot.h>
9
13
18
19#include <armarx/control/deprecated_njoint_mp_controller/joint_space/ControllerInterface.h>
20
21#include <dmp/representation/dmp/umidmp.h>
22
24{
25
26 NJointControllerRegistration<NJointJSDMPController>
28
29 std::string
30 NJointJSDMPController::getClassName(const Ice::Current&) const
31 {
32 return "NJointJSDMPController";
33 }
34
36 const armarx::NJointControllerConfigPtr& config,
38 {
39 ARMARX_INFO << "creating joint space dmp controller ... ";
41
42 cfg = NJointJointSpaceDMPControllerConfigPtr::dynamicCast(config);
43 ARMARX_CHECK_EXPRESSION(cfg) << "Needed type: NJointJointSpaceDMPControllerConfigPtr";
44
45 for (std::string jointName : cfg->jointNames)
46 {
47 ControlTargetBase* ct = useControlTarget(jointName, ControlModes::Velocity1DoF);
48 const SensorValueBase* sv = useSensorValue(jointName);
49 targets.insert(std::make_pair(jointName, ct->asA<ControlTarget1DoFActuatorVelocity>()));
50 positionSensors.insert(
51 std::make_pair(jointName, sv->asA<SensorValue1DoFActuatorPosition>()));
52 velocitySensors.insert(
53 std::make_pair(jointName, sv->asA<SensorValue1DoFActuatorVelocity>()));
54 }
55 if (cfg->jointNames.size() == 0)
56 {
57 ARMARX_ERROR << "cfg->jointNames.size() == 0";
58 }
59 ARMARX_INFO << "start creating dmpPtr ... "
60 << " baseMode: " << cfg->baseMode;
61
62 dmpPtr.reset(new DMP::UMIDMP(cfg->kernelSize, 100, cfg->baseMode, 1));
63 timeDuration = cfg->timeDuration;
64 phaseL = cfg->phaseL;
65 phaseK = cfg->phaseK;
66 phaseDist0 = cfg->phaseDist0;
67 phaseDist1 = cfg->phaseDist1;
68 phaseKp = cfg->phaseKp;
69 dimNames = cfg->jointNames;
70 ARMARX_INFO << "created dmpPtr ... ";
71
72 targetVels.resize(cfg->jointNames.size());
74 initData.targetJointVels.resize(cfg->jointNames.size());
75 for (size_t i = 0; i < cfg->jointNames.size(); ++i)
76 {
77 initData.targetJointVels[i] = 0;
78 targetVels[i] = 0;
79 }
80
81 reinitTripleBuffer(initData);
82
83
84 NJointJSDMPControllerSensorData initSensorData;
85 initSensorData.currentTime = 0;
86 initSensorData.deltaT = 0;
87 initSensorData.currentState.resize(cfg->jointNames.size());
88 controllerSensorData.reinitAllBuffers(initSensorData);
89
90 deltaT = 0;
91
92 qpos.resize(dimNames.size());
93 qvel.resize(dimNames.size());
94 }
95
96 void
98 {
99 if (!started || finished)
100 {
101 for (size_t i = 0; i < dimNames.size(); ++i)
102 {
103 targetVels[i] = 0;
104 }
105 }
106 else
107 {
108 currentState = controllerSensorData.getUpToDateReadBuffer().currentState;
109 double deltaT = controllerSensorData.getUpToDateReadBuffer().deltaT;
110
111 if (canVal > 1e-8)
112 {
113 double phaseStop = 0;
114 double mpcFactor = 1;
115
116 std::vector<double> currentPosition;
117 double error = 0;
118 currentPosition.resize(dimNames.size());
119
120 for (size_t i = 0; i < currentState.size(); i++)
121 {
122 DMP::DMPState currentPos = currentState[i];
123 currentPosition[i] = currentPos.pos;
124 error += pow(currentPos.pos - targetState[i], 2);
125 }
126
127 if (cfg->isPhaseStop)
128 {
129 double phaseDist;
130
131 if (isDisturbance)
132 {
133 phaseDist = phaseDist1;
134 }
135 else
136 {
137 phaseDist = phaseDist0;
138 }
139
140 error = sqrt(error);
141 phaseStop = phaseL / (1 + exp(-phaseK * (error - phaseDist)));
142 mpcFactor = 1 - (phaseStop / phaseL);
143
144 if (mpcFactor < 0.1)
145 {
146 isDisturbance = true;
147 }
148
149 if (mpcFactor > 0.9)
150 {
151 isDisturbance = false;
152 }
153 }
154
155 canVal -= tau * deltaT * 1 / (1 + phaseStop);
156 double dmpDeltaT = deltaT / timeDuration;
157
158 currentDMPState = dmpPtr->calculateDirectlyVelocity(
159 currentDMPState, canVal / timeDuration, dmpDeltaT, targetState);
160
161 for (size_t i = 0; i < currentDMPState.size(); ++i)
162 {
163 double vel0 = tau * currentDMPState[i].vel / timeDuration;
164 double vel1 = phaseKp * (targetState[i] - currentPosition[i]);
165 // double vel = mpcFactor * vel0 + (1 - mpcFactor) * vel1;
166 double vel = vel1 + vel0;
167 targetVels[i] = vel;
168 debugOutputData.getWriteBuffer().latestTargetVelocities[dimNames[i]] =
169 (float)vel;
170 debugOutputData.getWriteBuffer().latestTargets[dimNames[i]] =
171 (float)currentDMPState[i].pos;
172 }
173
174 debugOutputData.getWriteBuffer().currentCanVal = canVal;
175 debugOutputData.getWriteBuffer().mpcFactor = mpcFactor;
176 debugOutputData.commitWrite();
177 }
178 else
179 {
180 finished = true;
181 for (size_t i = 0; i < dimNames.size(); ++i)
182 {
183 targetVels[i] = 0;
184 }
185 }
186 }
187
189 getWriterControlStruct().targetJointVels = targetVels;
191 }
192
193 void
194 NJointJSDMPController::rtRun(const IceUtil::Time& sensorValuesTimestamp,
195 const IceUtil::Time& timeSinceLastIteration)
196 {
197 for (size_t i = 0; i < dimNames.size(); i++)
198 {
199 const auto& jointName = dimNames.at(i);
200 DMP::DMPState currentPos;
201 currentPos.pos = (positionSensors.count(jointName) == 1)
202 ? positionSensors[jointName]->position
203 : 0.0f;
204 currentPos.vel = (velocitySensors.count(jointName) == 1)
205 ? velocitySensors[jointName]->velocity
206 : 0.0f;
207 qpos[i] = currentPos.pos;
208 qvel[i] = currentPos.vel;
209 controllerSensorData.getWriteBuffer().currentState[i] = currentPos;
210 }
211 controllerSensorData.getWriteBuffer().deltaT = timeSinceLastIteration.toSecondsDouble();
212 controllerSensorData.getWriteBuffer().currentTime +=
213 timeSinceLastIteration.toSecondsDouble();
214 controllerSensorData.commitWrite();
215
216
217 rt2UserData.getWriteBuffer().qpos = qpos;
218 rt2UserData.getWriteBuffer().qvel = qvel;
219 rt2UserData.commitWrite();
220
221 Eigen::VectorXf targetJointVels = rtGetControlStruct().targetJointVels;
222 // ARMARX_INFO << targetJointVels;
223
224 for (size_t i = 0; i < dimNames.size(); ++i)
225 {
226
227 if (fabs(targetJointVels[i]) > cfg->maxJointVel)
228 {
229 targets[dimNames[i]]->velocity =
230 targetJointVels[i] < 0 ? -cfg->maxJointVel : cfg->maxJointVel;
231 }
232 else
233 {
234 targets[dimNames[i]]->velocity = targetJointVels[i];
235 }
236 }
237 }
238
239 void
240 NJointJSDMPController::learnDMPFromFiles(const Ice::StringSeq& fileNames, const Ice::Current&)
241 {
242 DMP::Vec<DMP::SampledTrajectoryV2> trajs;
243
244 DMP::DVec ratios;
245 for (size_t i = 0; i < fileNames.size(); ++i)
246 {
247 DMP::SampledTrajectoryV2 traj;
248 traj.readFromCSVFile(fileNames.at(i));
249 traj = DMP::SampledTrajectoryV2::normalizeTimestamps(traj, 0, 1);
250 trajs.push_back(traj);
251
252 if (i == 0)
253 {
254 ratios.push_back(1.0);
255 }
256 else
257 {
258 ratios.push_back(0.0);
259 }
260 }
261 dmpPtr->learnFromTrajectories(trajs);
262 dmpPtr->styleParas = dmpPtr->getStyleParasWithRatio(ratios);
263
264 ARMARX_INFO << "Learned DMP ... ";
265 }
266
267 void
268 NJointJSDMPController::runDMP(const Ice::DoubleSeq& goals, double times, const Ice::Current&)
269 {
270 while (!rt2UserData.updateReadBuffer())
271 {
272 usleep(100);
273 }
274
275 targetState.clear();
276 targetState.resize(dimNames.size());
277 currentState.clear();
278 currentState.resize(dimNames.size());
279 currentDMPState.clear();
280 currentDMPState.resize(dimNames.size());
281
282 std::vector<double> goalVec = goals;
283 for (size_t i = 0; i < dimNames.size(); i++)
284 {
285 DMP::DMPState currentPos;
286 currentPos.pos = rt2UserData.getReadBuffer().qpos[i];
287 currentPos.vel = rt2UserData.getReadBuffer().qvel[i];
288
289 currentState[i] = currentPos;
290 currentDMPState[i] = currentPos;
291
292 targetState.push_back(currentPos.pos);
293
294 if (rtGetRobot()->getRobotNode(dimNames[i])->isLimitless())
295 {
296 double tjv = goalVec[i];
297 double cjv = currentPos.pos;
298 double diff = std::fmod(tjv - cjv, 2 * M_PI);
299 if (fabs(diff) > M_PI)
300 {
301 if (signbit(diff))
302 {
303 diff = -2 * M_PI - diff;
304 }
305 else
306 {
307 diff = 2 * M_PI - diff;
308 }
309 tjv = cjv - diff;
310 }
311 else
312 {
313 tjv = cjv + diff;
314 }
315
316 goalVec[i] = tjv;
317 ARMARX_INFO << "dim name: " << dimNames[i]
318 << " current state: qpos: " << currentPos.pos
319 << " orig target: " << goals[i] << " current goal: " << tjv;
320 }
321 }
322
323 dmpPtr->prepareExecution(goalVec, currentDMPState, 1, 1);
324 canVal = timeDuration;
325 finished = false;
326 isDisturbance = false;
327
328 tau = times;
329 ARMARX_INFO << "run DMP";
330 started = true;
331 }
332
333 void
335 {
336 }
337
338 std::string
340 {
341 std::stringstream ss;
342 boost::archive::text_oarchive oa{ss};
343 oa << dmpPtr.get();
344 return ss.str();
345 }
346
347 std::vector<double>
348 NJointJSDMPController::createDMPFromString(const std::string& dmpString, const Ice::Current&)
349 {
350 std::stringstream ss;
351 ss.str(dmpString);
352 boost::archive::text_iarchive ia{ss};
353 DMP::UMIDMP* newDmpPtr;
354 ia >> newDmpPtr;
355 dmpPtr.reset(newDmpPtr);
356 return dmpPtr->defaultGoal;
357 }
358
359 void
360 NJointJSDMPController::setViaPoints(Ice::Double u, double viapoint, const Ice::Current&)
361 {
362 LockGuardType guard{controllerMutex};
363 dmpPtr->setViaPoint(u, viapoint);
364 }
365
366 void
367 NJointJSDMPController::setMPWeights(const DoubleSeqSeq& weights, const Ice::Current&)
368 {
369 dmpPtr->setWeights(weights);
370 }
371
372 DoubleSeqSeq
374 {
375 DMP::DVec2d res = dmpPtr->getWeights();
376 DoubleSeqSeq resvec;
377 for (size_t i = 0; i < res.size(); ++i)
378 {
379 std::vector<double> cvec;
380 for (size_t j = 0; j < res[i].size(); ++j)
381 {
382 cvec.push_back(res[i][j]);
383 }
384 resvec.push_back(cvec);
385 }
386
387 return resvec;
388 }
389
390 void
391 NJointJSDMPController::setSpeed(double times, const Ice::Current&)
392 {
393 LockGuardType guard(controllerMutex);
394 tau = times;
395 }
396
397 void
401
402 void
406
407 void
410 const DebugObserverInterfacePrx& debugObs)
411 {
412 StringVariantBaseMap datafields;
413 auto values = debugOutputData.getUpToDateReadBuffer().latestTargetVelocities;
414 for (auto& pair : values)
415 {
416 datafields[pair.first] = new Variant(pair.second);
417 }
418
419 values = debugOutputData.getUpToDateReadBuffer().latestTargets;
420 for (auto& pair : values)
421 {
422 datafields[pair.first + "_pos"] = new Variant(pair.second);
423 }
424
425 datafields["canVal"] = new Variant(debugOutputData.getUpToDateReadBuffer().currentCanVal);
426 datafields["mpcFactor"] = new Variant(debugOutputData.getUpToDateReadBuffer().mpcFactor);
427 debugObs->setDebugChannel("latestDMPTargetVelocities", datafields);
428 }
429
430 void
432 {
433 ARMARX_INFO << "init ...";
434 started = false;
435 runTask("NJointJSDMPController",
436 [&]
437 {
438 CycleUtil c(1);
439 getObjectScheduler()->waitForObjectStateMinimum(eManagedIceObjectStarted);
440 while (getState() == eManagedIceObjectStarted)
441 {
442 if (isControllerActive())
443 {
445 }
446 c.waitForCycleDuration();
447 }
448 });
449 }
450
451 void
455
456
457} // namespace armarx::control::deprecated_njoint_mp_controller::joint_space
#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 SensorValueBase class.
const T * asA() const
The Variant class is described here: Variants.
Definition Variant.h:224
virtual void onPublish(const SensorAndControl &, const DebugDrawerInterfacePrx &, const DebugObserverInterfacePrx &) override
void runDMP(const Ice::DoubleSeq &goals, double times, const Ice::Current &) override
void setMPWeights(const DoubleSeqSeq &weights, const Ice::Current &) override
void learnDMPFromFiles(const Ice::StringSeq &fileNames, const Ice::Current &) override
NJointJSDMPController(const RobotUnitPtr &robotUnit, const NJointControllerConfigPtr &config, const VirtualRobot::RobotPtr &)
void rtPostDeactivateController() override
This function is called after the controller is deactivated.
void rtRun(const IceUtil::Time &sensorValuesTimestamp, const IceUtil::Time &timeSinceLastIteration) override
TODO make protected and use attorneys.
std::vector< double > createDMPFromString(const std::string &dmpString, const Ice::Current &) override
void setViaPoints(Ice::Double u, double viapoint, const Ice::Current &) override
void rtPreActivateController() override
This function is called before the controller is activated.
#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_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
std::shared_ptr< class Robot > RobotPtr
Definition Bus.h:19
NJointControllerRegistration< NJointJSDMPController > registrationControllerNJointJSDMPController("NJointJSDMPController")
::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