ControlPlatform.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2014-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package RobotSkillTemplates::PlatformGroup
19 * @author Mirko Waechter ( waechter at kit dot edu )
20 * @date 2015
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24
25#include "ControlPlatform.h"
26
29
31
33
34using namespace armarx;
35using namespace PlatformGroup;
36
37// DO NOT EDIT NEXT LINE
38ControlPlatform::SubClassRegistry ControlPlatform::Registry(ControlPlatform::GetName(),
40
41float
42signedMin(float newValue, float minAbsValue)
43{
44 return std::copysign(std::min<float>(fabs(newValue), minAbsValue), newValue);
45}
46
49 ControlPlatformGeneratedBase<ControlPlatform>(stateData)
50{
51}
52
53void
55{
56
57 // put your user code for the enter-point here
58 // execution time should be short (<100ms)
59 PlatformContext* context = getContext<PlatformContext>();
60
61 setTimeoutEvent(in.getTimeout(), createEventTimeout());
62
63 if (in.getUsePlatformNativeController())
64 {
65 ARMARX_INFO << "Using native Platform Controller";
66 Vector3Ptr currentTarget = in.getTargetPose();
67 Literal checkX(context->platformUnitObserverName + ".platformPose.positionX",
68 checks::approx,
69 {currentTarget->x, in.getPositionalAccuracy()});
70 Literal checkY(context->platformUnitObserverName + ".platformPose.positionY",
71 checks::approx,
72 {currentTarget->y, in.getPositionalAccuracy()});
73
74 Literal checkAngle(context->platformUnitObserverName + ".platformPose.rotation",
75 checks::approx,
76 {currentTarget->z, in.getOrientationalAccuracy()});
77 // for special case of orientations around 2*PI
78 float checkAngleValueOffset;
79
80 if (currentTarget->z > M_PI)
81 {
82 checkAngleValueOffset = -2 * M_PI;
83 }
84 else
85 {
86 checkAngleValueOffset = 2 * M_PI;
87 }
88
89 Literal checkAngle2(
90 context->platformUnitObserverName + ".platformPose.rotation",
91 checks::approx,
92 {(float)(currentTarget->z + checkAngleValueOffset), in.getOrientationalAccuracy()});
93
94 installConditionForPoseReached(checkX && checkY && (checkAngle || checkAngle2));
95 ARMARX_INFO << "Moving to " << in.getTargetPose()->x << ", " << in.getTargetPose()->y
96 << ", " << in.getTargetPose()->z << ", ";
97 context->platformUnitPrx->moveTo(in.getTargetPose()->x,
98 in.getTargetPose()->y,
99 in.getTargetPose()->z,
100 in.getPositionalAccuracy(),
101 in.getOrientationalAccuracy());
102 usleep(1000000);
103 context->platformUnitPrx->moveTo(in.getTargetPose()->x,
104 in.getTargetPose()->y,
105 in.getTargetPose()->z,
106 in.getPositionalAccuracy(),
107 in.getOrientationalAccuracy());
108
109 this->setUseRunFunction(false);
110 }
111 else
112 {
113 this->setUseRunFunction(true);
114 }
115}
116
117void
119{
120
121 MultiDimPIDController pidTrans(
122 in.getPTranslation(), in.getITranslation(), in.getDTranslation());
123 // PIDController pidY(in.getPTranslation(), in.getITranslation(), in.getDTranslation());
124 PIDController pidRot(in.getPOrientation(), in.getIOrientation(), in.getDOrientation());
125 // put your user code for the execution-phase here
126 // runs in seperate thread, thus can do complex operations
127 // should check constantly whether isRunningTaskStopped() returns true
128 PlatformContext* c = getContext<PlatformContext>();
129 DatafieldRefPtr posXRef =
130 new DatafieldRef(c->platformUnitObserverPrx, "platformPose", "positionX");
131 DatafieldRefPtr posYRef =
132 new DatafieldRef(c->platformUnitObserverPrx, "platformPose", "positionY");
133 DatafieldRefPtr oriRef =
134 new DatafieldRef(c->platformUnitObserverPrx, "platformPose", "rotation");
135
136
137 float maxTransVel = in.getMaxTranslationVelocity();
138 ARMARX_INFO << "orientation accuracy: " << in.getOrientationalAccuracy();
139 ARMARX_INFO << "translational accuracy: " << in.getPositionalAccuracy();
140
141
142 float targetX = in.getTargetPose()->x;
143 float targetY = in.getTargetPose()->y;
144 Eigen::Vector3f target{targetX, targetY, 0};
145 float targetOri = in.getTargetPose()->z;
146 // float curOri = oriRef->getDataField()->getFloat();
147
148 // bool reverseZeroCrossing = (targetOri - curOri > M_PI);
149 // bool ZeroCrossing= (targetOri - curOri < -M_PI);
150
151 // if(reverseZeroCrossing)
152 // {
153 // targetOri -= 2 * M_PI;
154 // }
155 // if(ZeroCrossing)
156 // {
157 // targetOri += 2 * M_PI;
158 // }
159
160 float startOri = oriRef->getDataField()->getFloat();
161
162
163 ARMARX_INFO << "Platform current pose: " << posXRef->getDataField()->getFloat() << ", "
164 << posYRef->getDataField()->getFloat() << ", "
165 << oriRef->getDataField()->getFloat();
166 ;
167 ARMARX_INFO << "Platform target pose: " << *in.getTargetPose();
168 ARMARX_INFO << "AdjustPlatform target angle: " << targetOri;
169 ARMARX_INFO << VAROUT(maxTransVel);
170
171 if (targetOri > M_PI)
172 {
173 targetOri = -2 * M_PI + targetOri;
174 }
175
176 if (startOri > M_PI)
177 {
178 startOri = -2 * M_PI + startOri;
179 }
180
181 float angleAbsDelta = targetOri - startOri;
182
183 // transform alpha to [-pi, pi)
184 while (angleAbsDelta < -M_PI)
185 {
186 angleAbsDelta += 2 * M_PI;
187 }
188
189 while (angleAbsDelta >= M_PI)
190 {
191 angleAbsDelta -= 2 * M_PI;
192 }
193
194
195 Eigen::Vector2f targetOriVec(sin(targetOri), cos(targetOri));
196 bool verify = in.getVerifyTargetPose();
197 IceUtil::Time targetReachedTime = IceUtil::Time::seconds(0);
198 float cycleTime = in.getCycleTime();
199
200 while (!isRunningTaskStopped()) // stop run function if returning true
201 {
202 // do your calculations
203 float posx = posXRef->getDataField()->getFloat();
204 float posy = posYRef->getDataField()->getFloat();
205 float ori = oriRef->getDataField()->getFloat();
206 // if(ZeroCrossing && ori < M_PI)
207 // ori += 2 * M_PI;
208
209 // if(reverseZeroCrossing && ori > M_PI)
210 // ori -= 2 * M_PI;
211
212 Eigen::Vector3f pos{posx, posy, 0.0f};
213
214 if (ori > M_PI)
215 {
216 ori = -2 * M_PI + ori;
217 }
218 // put your user code for the enter-point here
219 // execution time should be short (<100ms)
220 //PlatformContext* context = getContext<PlatformContext>();
221
222 float angleDelta = targetOri - ori;
223 ARMARX_INFO << deactivateSpam(1) << VAROUT(angleDelta);
224
225
226 // transform alpha to [-pi, pi)
227
228 while (angleDelta < -M_PI)
229 {
230 angleDelta += 2 * M_PI;
231 }
232
233 while (angleDelta >= M_PI)
234 {
235 angleDelta -= 2 * M_PI;
236 }
237
238
239 pidTrans.update(pos, target);
240 pidRot.update(angleDelta, 0);
241
242 Eigen::Vector2f newVel(pidTrans.getControlValue()[0], pidTrans.getControlValue()[1]);
243
244
245 float newVelocityRot = -signedMin(pidRot.getControlValue(), in.getMaxRotationalVelocity());
246 Eigen::Vector3f globalVel{newVel[0], newVel[1], 0};
247 Eigen::Matrix3f m;
248 m = Eigen::AngleAxisf(ori, Eigen::Vector3f::UnitZ());
249 Eigen::Vector3f localVel = m.inverse() * globalVel;
250 if (localVel.head(2).norm() > maxTransVel)
251 {
252 localVel.head(2) *= maxTransVel / localVel.head(2).norm();
253 }
254
255 // Eigen::Vector3f currentVelocity {velXRef->get<float>(), velXRef->get<float>(), 0};
256 // if((localVel-currentVelocity).norm()/(cycleTime*0.001) > maxAcc)
257 // localVel = localVel.norm()*(cycleTime*0.001*maxAcc);
258 if (std::isnan(localVel[0]) || std::isnan(localVel[1]) || std::isnan(newVelocityRot))
259 {
260 throw LocalException("A target velocity is NaN!");
261 }
262
263
264 // ARMARX_INFO << deactivateSpam(0.1) << VAROUT(pidRot.getControlValue());
265 // ARMARX_INFO << deactivateSpam(0.1) << VAROUT(newVelocityRot);
266
267 c->platformUnitPrx->move(localVel[0], localVel[1], newVelocityRot);
268 //ARMARX_IMPORTANT << "local x velocity: " << localVel[0] << " local y velocity: " << localVel[1] << " rotation vel: " << newVelocityRot;
269
270 if (fabs(pidTrans.previousError) < in.getPositionalAccuracy() &&
271 fabs(pidRot.previousError) < in.getOrientationalAccuracy())
272 {
273 if (!verify)
274 {
275 emitPoseReached();
276 }
277 else
278 {
279 if (targetReachedTime.toSeconds() == 0)
280 {
281 targetReachedTime = TimeUtil::GetTime();
282 }
283
284 ARMARX_INFO << deactivateSpam(0.1) << "error: " << pidTrans.previousError
285 << " x velocity: " << newVel[0] << " y velocity: " << newVel[1];
286 ARMARX_INFO << deactivateSpam(0.1) << "rot error: " << pidRot.previousError
287 << " rot velocity: " << newVelocityRot;
288
289
290 if ((TimeUtil::GetTime() - targetReachedTime).toMilliSecondsDouble() > 500)
291 {
292 emitPoseReached();
293 }
294 }
295 }
296 else
297 {
298 ARMARX_INFO << deactivateSpam(1) << "error: " << pidTrans.previousError
299 << " x velocity: " << newVel[0] << " y velocity: " << newVel[1];
300 ARMARX_INFO << deactivateSpam(1) << "rot error: " << pidRot.previousError
301 << " rot velocity: " << newVelocityRot;
302 }
303
304 usleep(cycleTime * 1000);
305 }
306
307
308 // Sync trans and rot:
309
310 // float orientationMultiplyer = in.getOrientationMultiplyerForPID();
311 // float maxTransVel = in.getMaxTranslationVelocity();
312
313 // MultiDimPIDController pidTransRot(in.getPTransRot(), in.getITransRot(), in.getDTransRot(), maxTransVel);
314
315 // PlatformContext* c = getContext<PlatformContext>();
316 // DatafieldRefPtr posXRef = new DatafieldRef(c->platformUnitObserverPrx, "platformPose", "positionX");
317 // DatafieldRefPtr posYRef = new DatafieldRef(c->platformUnitObserverPrx, "platformPose", "positionY");
318 // DatafieldRefPtr oriRef = new DatafieldRef(c->platformUnitObserverPrx, "platformPose", "rotation");
319
320
321 // float targetX = in.getTargetPose()->x;
322 // float targetY = in.getTargetPose()->y;
323 // float targetOri = in.getTargetPose()->z;
324
325
326 // float px = posXRef->getDataField()->getFloat();
327 // float py = posYRef->getDataField()->getFloat();
328
329 // float wholeDistance = std::sqrt(px * px + py * py);
330
331
332 // ARMARX_INFO << "Platform current pose: " << posXRef->getDataField()->getFloat() << ", " << posYRef->getDataField()->getFloat() << ", " << oriRef->getDataField()->getFloat();;
333 // ARMARX_INFO << "Platform target pose: " << *in.getTargetPose();
334 // ARMARX_INFO << "AdjustPlatform target angle: " << targetOri;
335 // ARMARX_INFO << VAROUT(maxTransVel);
336
337
338 // if (targetOri > M_PI)
339 // {
340 // targetOri = - 2 * M_PI + targetOri;
341 // }
342
343 // bool verify = in.getVerifyTargetPose();
344 // IceUtil::Time targetReachedTime = IceUtil::Time::seconds(0);
345 // float cycleTime = in.getCycleTime();
346
347 // while (!isRunningTaskStopped()) // stop run function if returning true
348 // {
349 // // do your calculations
350 // float posx = posXRef->getDataField()->getFloat();
351 // float posy = posYRef->getDataField()->getFloat();
352 // float ori = oriRef->getDataField()->getFloat();
353
354 // float currentDistance = std::sqrt(posx * posx + posy * posy);
355 // float percentageDone = currentDistance <= in.getPositionalAccuracy() ? 0 : currentDistance / wholeDistance;
356
357
358 // if (ori > M_PI)
359 // {
360 // ori = - 2 * M_PI + ori;
361 // }
362 // float angleDelta = targetOri - ori;
363
364 // // transform alpha to [-pi, pi)
365 // while (angleDelta < -M_PI)
366 // {
367 // angleDelta += 2 * M_PI;
368 // }
369
370 // while (angleDelta >= M_PI)
371 // {
372 // angleDelta -= 2 * M_PI;
373 // }
374
375
376 // float posAngle = angleDelta * (-1) * orientationMultiplyer;
377 // float targetAngle = posAngle * percentageDone;
378
379
380 // Eigen::Vector3f pos {posx, posy, posAngle};
381 // ARMARX_INFO << "CurrentPIDValues: " << pos;
382 // Eigen::Vector3f target {targetX, targetY, targetAngle};
383 // ARMARX_INFO << "targetPIDValues: " << target;
384 // pidTransRot.update(pos, target);
385
386 // Eigen::Vector3f newVel(pidTransRot.getControlValue()[0], pidTransRot.getControlValue()[1], pidTransRot.getControlValue()[2]);
387
388 // float newVelRot = signedMin(newVel[2] / (in.getPTransRot() * orientationMultiplyer), in.getMaxRotationalVelocity());
389
390 // Eigen::Vector3f globalVel {newVel[0], newVel[1], 0};
391 // Eigen::Matrix3f m;
392 // m = Eigen::AngleAxisf(ori, Eigen::Vector3f::UnitZ());
393 // Eigen::Vector3f localVel = m.inverse() * globalVel;
394 // if (localVel.norm() > maxTransVel)
395 // {
396 // localVel *= maxTransVel / localVel.norm();
397 // }
398
399 // if (std::isnan(localVel[0]) || std::isnan(localVel[1]) || std::isnan(newVelRot))
400 // {
401 // throw LocalException("A target velocity is NaN!");
402 // }
403
404 // c->platformUnitPrx->move(localVel[0],
405 // localVel[1],
406 // newVelRot);
407
408
409 // ARMARX_INFO << deactivateSpam(1) << "local x velocity: " << localVel[0] << " local y velocity: " << localVel[1] << " rotation vel: " << newVelRot;
410
411 // if (fabs(pidTransRot.previousError) < in.getPositionalAccuracy() && fabs(pidTransRot.previousError) < in.getOrientationalAccuracy() * orientationMultiplyer)
412 // {
413 // if (!verify)
414 // {
415 // emitPoseReached();
416 // }
417 // else
418 // {
419 // if (targetReachedTime.toSeconds() == 0)
420 // {
421 // targetReachedTime = TimeUtil::GetTime();
422 // }
423
424 // ARMARX_INFO << deactivateSpam(0.1) << "error: " << pidTransRot.previousError << " x velocity: " << localVel[0] << " y velocity: " << localVel[1] << " rot velocity: " << newVelRot;
425
426 // if ((TimeUtil::GetTime() - targetReachedTime).toMilliSecondsDouble() > 500)
427 // {
428 // emitPoseReached();
429 // }
430 // }
431 // }
432 // else
433 // {
434 // ARMARX_INFO << deactivateSpam(0.1) << "error: " << pidTransRot.previousError << " x velocity: " << localVel[0] << " y velocity: " << localVel[1] << " rot velocity: " << newVelRot;
435 // }
436
437 // usleep(cycleTime * 1000);
438 // }
439}
440
441void
443{
444 // put your user code for the exit point here
445 // execution time should be short (<100ms)
446 PlatformContext* c = getContext<PlatformContext>();
447 DatafieldRefPtr posXRef =
448 new DatafieldRef(c->platformUnitObserverPrx, "platformPose", "positionX");
449 DatafieldRefPtr posYRef =
450 new DatafieldRef(c->platformUnitObserverPrx, "platformPose", "positionY");
451 DatafieldRefPtr oriRef =
452 new DatafieldRef(c->platformUnitObserverPrx, "platformPose", "rotation");
453 float posX = posXRef->getDataField()->getFloat();
454 float posY = posYRef->getDataField()->getFloat();
455 float ori = oriRef->getDataField()->getFloat();
456 Vector3Ptr error = new Vector3(fabs(in.getTargetPose()->x - posX),
457 fabs(in.getTargetPose()->y - posY),
458 fabs(in.getTargetPose()->z - ori));
459 ARMARX_INFO << "Remaining platform error: " << *error;
460 out.setRemainingError(error);
461}
462
463void
465{
466 while (!isRunningTaskFinished())
467 {
468 ARMARX_INFO << deactivateSpam(1) << "Waiting for runfunction";
469 usleep(1000);
470 }
471 ARMARX_INFO << "Breaking state";
472 PlatformContext* c = getContext<PlatformContext>();
473 cleanUp();
474 if (in.getStopPlatformOnBreak())
475 {
476 c->platformUnitPrx->stopPlatform();
477 }
478}
479
480void
482{
483 while (!isRunningTaskFinished())
484 {
485 ARMARX_INFO << deactivateSpam(1) << "Waiting for runfunction";
486 usleep(1000);
487 }
488 ARMARX_INFO << "Exiting state";
489
490 cleanUp();
491 PlatformContext* c = getContext<PlatformContext>();
492 if (in.getStopPlatformOnExit())
493 {
494 c->platformUnitPrx->stopPlatform();
495 }
496}
497
498// DO NOT EDIT NEXT FUNCTION
float signedMin(float newValue, float minAbsValue)
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define M_PI
Definition MathTools.h:17
#define VAROUT(x)
constexpr T c
The DatafieldRef class is similar to the ChannelRef, but points to a specific Datafield instead of to...
Literals are part of the user front end of the ArmarX condition mechanism.
Definition Term.h:209
void update(const double deltaSec, const PIDVectorX &measuredValue, const PIDVectorX &targetValue)
double getControlValue() const
void update(double deltaSec, double measuredValue, double targetValue)
std::string platformUnitObserverName
PlatformUnitInterfacePrx platformUnitPrx
ControlPlatform(const XMLStateConstructorParams &stateData)
static XMLStateFactoryBasePtr CreateInstance(XMLStateConstructorParams stateData)
static IceUtil::Time GetTime(TimeMode timeMode=TimeMode::VirtualTime)
Get the current time.
Definition TimeUtil.cpp:42
The Vector3 class.
Definition Pose.h:113
Class for legacy to stay compatible with old statecharts.
Definition XMLState.h:147
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceInternal::Handle< Vector3 > Vector3Ptr
Definition Pose.h:165
MultiDimPIDControllerTemplate<> MultiDimPIDController
IceInternal::Handle< DatafieldRef > DatafieldRefPtr
Definition Observer.h:43
IceInternal::Handle< XMLStateFactoryBase > XMLStateFactoryBasePtr
Definition XMLState.h:64