BasicControllers.cpp
Go to the documentation of this file.
1/*
2* This file is part of ArmarX.
3*
4* ArmarX is free software; you can redistribute it and/or modify
5* it under the terms of the GNU General Public License version 2 as
6* published by the Free Software Foundation.
7*
8* ArmarX is distributed in the hope that it will be useful, but
9* WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program. If not, see <http://www.gnu.org/licenses/>.
15*
16* @package RobotAPI
17* @author Raphael Grimm ( raphael dot grimm at kit dot edu )
18* @date 2017
19* @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20* GNU General Public License
21*/
22
23#include "BasicControllers.h"
24
25#include <algorithm>
26
29
30#include "util/CtrlUtil.h"
31
32namespace armarx
33{
34 float
36 float maxDt,
37 const float currentV,
38 float targetV,
39 float maxV,
40 float acceleration,
41 float deceleration,
42 float directSetVLimit)
43 {
44 dt = std::min(std::abs(dt), std::abs(maxDt));
45 maxV = std::abs(maxV);
46 acceleration = std::abs(acceleration);
47 deceleration = std::abs(deceleration);
48 targetV = std::clamp(targetV, -maxV, maxV);
49
50 //we can have 3 cases:
51 // 1. we directly set v and ignore acc/dec (if |curr - target| <= limit)
52 // 2. we need to accelerate (if curr and target v have same sign and |curr| < |target|)
53 // 3. we need to decelerate (other cases)
54
55 //handle case 1
56 const float curverror = targetV - currentV;
57 if (std::abs(curverror) < directSetVLimit)
58 {
59 return targetV;
60 }
61
62 //handle case 2 + 3
63 const bool accelerate = sign(targetV) == sign(currentV) && // v in same direction
64 std::abs(targetV) > std::abs(currentV); // currently to slow
65
66 const float usedacc = accelerate ? acceleration : -deceleration;
67 const float maxDeltaV = std::abs(usedacc * dt);
68 if (maxDeltaV >= std::abs(curverror))
69 {
70 //we change our v too much with the used acceleration
71 //but we could reach our target with a lower acceleration ->set the target
72
73 return targetV;
74 }
75 const float deltaVel = std::clamp(sign(currentV) * usedacc * dt, -maxDeltaV, maxDeltaV);
76 const float nextV = currentV + deltaVel;
77 return nextV;
78 }
79
80 ////////////////////////////
81 //wip?
82 float
84 float maxDt,
85 float currentV,
86 float targetV,
87 float maxV,
88 float acceleration,
89 float deceleration,
90 float directSetVLimit,
91 float currentPosition,
92 float positionLimitLoSoft,
93 float positionLimitHiSoft,
94 float positionLimitLoHard,
95 float positionLimitHiHard)
96 {
97 if (currentPosition <= positionLimitLoHard || currentPosition >= positionLimitHiHard)
98 {
99 return std::nanf("1");
100 }
101
102 float softLimitViolation = 0;
103 if (currentPosition <= positionLimitLoSoft)
104 {
105 softLimitViolation = -1;
106 }
107 if (currentPosition >= positionLimitHiSoft)
108 {
109 softLimitViolation = 1;
110 }
111
112 const float upperDt = std::max(std::abs(dt), std::abs(maxDt));
113 dt = std::min(std::abs(dt), std::abs(maxDt));
114 maxV = std::abs(maxV);
115
116 //we can have 4 cases:
117 // 1. we need to decelerate now or we will violate the position limits (maybe we still will violate them, e.g. if we violated them initially)
118 // 2. we directly set v and ignore acc/dec (if |curr - target| <= limit)
119 // 3. we need to accelerate (if curr and target v have same sign and |curr| < |target|)
120 // 4. we need to decelerate (other cases)
121 float nextv;
122 //handle case 1
123 const float vsquared = currentV * currentV;
124 const float brakingDist =
125 sign(currentV) * vsquared / 2.f /
126 std::abs(deceleration); //the braking distance points in the direction of the velocity
127
128
129 const float posIfBrakingNow = currentPosition + brakingDist;
130 if (posIfBrakingNow <= positionLimitLoSoft || posIfBrakingNow >= positionLimitHiSoft)
131 {
132 //case 1. -> brake now! (we try to have v=0 at the limit)
133 const auto limit =
134 posIfBrakingNow <= positionLimitLoSoft ? positionLimitLoSoft : positionLimitHiSoft;
135 const float wayToGo = limit - currentPosition;
136
137 //decelerate!
138 // s = v²/(2a) <=> a = v²/(2s)
139 const float dec = std::abs(vsquared / 2.f / wayToGo);
140 const float vel = currentV - sign(currentV) * dec * upperDt;
141 nextv = std::clamp(vel, -maxV, maxV);
142 if (sign(currentV) != sign(nextv))
143 {
144 //stop now
145 nextv = 0;
146 }
147 }
148 else
149 {
150 //handle 2-3
152 dt, maxDt, currentV, targetV, maxV, acceleration, deceleration, directSetVLimit);
153 }
154 if (softLimitViolation == sign(nextv))
155 {
156 //the area between soft and hard limits is sticky
157 //the controller can only move out of it (not further in)
158 return 0;
159 }
160
161 //the next velocity will not violate the pos bounds harder than they are already
162 return nextv;
163 }
164
165 float
167 float maxDt,
168 float currentV,
169 float maxV,
170 float acceleration,
171 float deceleration,
172 float currentPosition,
173 float targetPosition,
174 float p)
175 {
176 dt = std::min(std::abs(dt), std::abs(maxDt));
177 maxV = std::abs(maxV);
178 acceleration = std::abs(acceleration);
179 deceleration = std::abs(deceleration);
180 const float signV = sign(currentV);
181 //we can have 3 cases:
182 // 1. we use a p controller and ignore acc/dec (if velocity target from p controller < velocity target from ramp controller)
183 // 2. we need to accelerate (or hold vel) (if e = (targetPosition - currentPosition)
184 // the brakingDistance have the same sign and brakingDistance < e
185 // and currentVel <= maxV)
186 // 3. we need to decelerate (other cases)
187
188 //handle case 1
189 const float positionError = targetPosition - currentPosition;
190 float newTargetVelPController = positionError * p;
191
192 //handle case 2-3
193 const float brakingDistance =
194 signV * currentV * currentV / 2.f /
195 deceleration; //the braking distance points in the direction of the velocity
196 const float posIfBrakingNow = currentPosition + brakingDistance;
197 const float posErrorIfBrakingNow = targetPosition - posIfBrakingNow;
198
199 const bool decelerate =
200 std::abs(currentV) > maxV || // we need to slow down (to stay in [-maxV,maxV]
201 // std::abs(posIfBrakingNow - targetPosition) <= pControlPosErrorLimit || // we want to hit the target
202 sign(posErrorIfBrakingNow) != signV; // we are moving away from the target
203 const float usedacc = decelerate ? -deceleration : acceleration;
204 const float maxDeltaV = std::abs(usedacc * dt);
205 const float deltaVel = std::clamp(signV * usedacc * dt, -maxDeltaV, maxDeltaV);
206
207 float newTargetVel = std::clamp(currentV + deltaVel, -maxV, maxV);
208 bool usePID = std::abs(newTargetVelPController) < std::abs(newTargetVel);
209 // ARMARX_INFO << deactivateSpam(0.01) << VAROUT(usePID) << VAROUT(dt) << VAROUT(decelerate) << VAROUT(usedacc) << VAROUT(maxDeltaV) << VAROUT(deltaVel) << VAROUT(newTargetVel) << VAROUT(newTargetVelPController)
210 // << VAROUT(currentPosition) << VAROUT(targetPosition);
211 if (usePID)
212 {
213 return newTargetVelPController;
214 }
215 else
216 {
217 return newTargetVel;
218 }
219 }
220
221 float
223 float maxDt,
224 float currentV,
225 float maxV,
226 float acceleration,
227 float deceleration,
228 float currentPosition,
229 float targetPosition,
230 float p,
231 float positionLimitLo,
232 float positionLimitHi
233
234 )
235 {
236 dt = std::min(std::abs(dt), std::abs(maxDt));
237 maxV = std::abs(maxV);
238 acceleration = std::abs(acceleration);
239 deceleration = std::abs(deceleration);
240 const float signV = sign(currentV);
241 //we can have 4 cases:
242 // 1. we need to decelerate now or we will violate the position limits (maybe we still will violate them)
243 // 2. we use a p controller and ignore acc/dec (if |currentPosition - targetPosition| <= pControlPosErrorLimit AND |currentPosition - targetPosition|*p < maxV)
244 // 4. we need to accelerate (or hold vel) (if e = (targetPosition - currentPosition)
245 // and the brakingDistance have the same sign and brakingDistance < e
246 // and currentVel <= maxV)
247 // 5. we need to decelerate (other cases)
248
249 //handle case 1
250 const float vsquared = currentV * currentV;
251 const float brakingDistance =
252 signV * vsquared / 2.f /
253 deceleration; //the braking distance points in the direction of the velocity
254 const float posIfBrakingNow = currentPosition + brakingDistance;
255 if (posIfBrakingNow <= positionLimitLo || posIfBrakingNow >= positionLimitHi)
256 {
257 //case 1. -> brake now! (we try to have v=0 at the limit)
258 const auto limit = brakingDistance > 0 ? positionLimitHi : positionLimitLo;
259 const float wayToGo = std::abs(limit - currentPosition);
260 // s = v²/(2a) <=> a = v²/(2s)
261 const float dec = std::abs(vsquared / 2.f / wayToGo);
262 const float vel = currentV - signV * dec * dt;
263 return vel;
264 }
265
266 //handle case 2-3
268 dt,
269 maxDt,
270 currentV,
271 maxV,
272 acceleration,
273 deceleration,
274 currentPosition,
275 std::clamp(targetPosition, positionLimitLo, positionLimitHi),
276 p);
277 }
278
279 ////////////////////////////
280 //wip
281
282
283 float
285 float dt,
286 float maxDt,
287 float currentV,
288 float maxV,
289 float acceleration,
290 float deceleration,
291 float currentPosition,
292 float targetPosition,
293 float pControlPosErrorLimit,
294 float p,
295 float& direction,
296 float positionPeriodLo,
297 float positionPeriodHi)
298 {
299 currentPosition = periodicClamp(currentPosition, positionPeriodLo, positionPeriodHi);
300 targetPosition = periodicClamp(targetPosition, positionPeriodLo, positionPeriodHi);
301
302 const float brakingDist = brakingDistance(currentV, deceleration);
303 const float posIfBrakingNow = currentPosition + brakingDist;
304 const float posIfBrakingNowError = targetPosition - posIfBrakingNow;
305 const float posError = targetPosition - currentPosition;
306 if (std::abs(posIfBrakingNowError) <= pControlPosErrorLimit ||
307 std::abs(posError) <= pControlPosErrorLimit)
308 {
309 //this allows slight overshooting (in the limits of the p controller)
311 maxDt,
312 currentV,
313 maxV,
314 acceleration,
315 deceleration,
316 currentPosition,
317 targetPosition,
318 p);
319 }
320
321 //we transform the problem with periodic bounds into
322 //a problem with position bounds
323 const float positionPeriodLength = std::abs(positionPeriodHi - positionPeriodLo);
324
325 //we shift the positions such that 0 == target
326 currentPosition =
327 periodicClamp(currentPosition - targetPosition, 0.f, positionPeriodLength);
328 //how many times will we go ovet the target if we simply bake now?
329 const float overshoot = std::trunc((currentPosition + brakingDist) / positionPeriodLength);
330
331 if (true || direction == 0)
332 {
333 //determine the direction to go (1 == pos vel, -1 == neg vel)
334 direction = (periodicClamp(currentPosition + brakingDist, 0.f, positionPeriodLength) >=
335 positionPeriodLength / 2)
336 ? 1
337 : -1;
338 }
339 //shift the target away from 0
340 targetPosition = (overshoot - std::min(0.f, -direction)) *
341 positionPeriodLength; // - direction * pControlPosErrorLimit;
342
343 //move
345 maxDt,
346 currentV,
347 maxV,
348 acceleration,
349 deceleration,
350 currentPosition,
351 targetPosition,
352 p);
353 }
354
355 bool
357 {
358 return maxV > 0 && acceleration > 0 && deceleration > 0 && targetV <= maxV &&
359 targetV >= -maxV;
360 }
361
362 float
364 {
365 const float useddt = std::min(std::abs(dt), std::abs(maxDt));
366
367 //we can have 3 cases:
368 // 1. we directly set v and ignore acc/dec (if |curr - target| <= limit)
369 // 2. we need to accelerate (if curr and target v have same sign and |curr| < |target|)
370 // 3. we need to decelerate (other cases)
371 //handle case 1
372 const float curverror = targetV - currentV;
373 if (std::abs(curverror) < directSetVLimit)
374 {
375 return targetV;
376 }
377
378 //handle case 2 + 3
379 const bool accelerate = sign(targetV) == sign(currentV) && // v in same direction
380 std::abs(targetV) > std::abs(currentV); // currently to slow
381
382 const float usedacc = accelerate ? acceleration : -deceleration;
383 const float maxDeltaV = std::abs(usedacc * useddt);
384 if (maxDeltaV >= std::abs(curverror))
385 {
386 //we change our v too much with the used acceleration
387 //but we could reach our target with a lower acceleration ->set the target
388
389 return targetV;
390 }
391 const float deltaVel = std::clamp(sign(currentV) * usedacc * useddt, -maxDeltaV, maxDeltaV);
392 const float nextV = currentV + deltaVel;
393 return nextV;
394 }
395
396 bool
401
404 {
405 const double useddt = std::min(std::abs(dt), std::abs(maxDt));
406
407 //we can have 3 cases:
408 // 1. we directly set v and ignore acc/dec (if |curr - target| <= limit)
409 // 2. we need to accelerate (if curr and target v have same sign and |curr| < |target|)
410 // 3. we need to decelerate (other cases)
411 //handle case 1
412 const double clampedTargetV = math::MathUtils::LimitTo(targetV, maxV);
413 const double curverror = clampedTargetV - currentV;
414 if (std::abs(curverror) < directSetVLimit)
415 {
416 // double nextAcc = (clampedTargetV - currentV) / useddt; // calculated acc is unstable!!!
417 // double nextJerk = (nextAcc - currentAcc) / useddt;
418 Output result{clampedTargetV, 0, 0};
419
420 return result;
421 }
422
423 //handle case 2 + 3
424 // const bool accelerate = sign(clampedTargetV) == sign(currentV) && // v in same direction
425 // std::abs(clampedTargetV) > std::abs(currentV); // currently to slow
426 const auto goalDir = math::MathUtils::Sign(clampedTargetV - currentV);
427 // calculate if we need to increase or decrease acc
428 bool increaseAcc = true;
429 if (goalDir == math::MathUtils::Sign(currentAcc))
430 {
431 // double t_to_v = ctrlutil::t_to_v(clampedTargetV - currentV, currentAcc, goalDir * jerk);
432 // double acc_at_t = ctrlutil::a(t_to_v, std::abs(currentAcc), -jerk);
433 // increaseJerk = acc_at_t < 0.0;
434
435 double t_to_zero_acc = std::abs(currentAcc) / jerk;
436 double v_at_t = ctrlutil::v(t_to_zero_acc, currentV, currentAcc, -goalDir * jerk);
437 increaseAcc = math::MathUtils::Sign(v_at_t - clampedTargetV) != goalDir;
438 // ARMARX_INFO << VAROUT(t_to_zero_acc) << VAROUT(v_at_t) << VAROUT(increaseAcc);
439 }
440 // v = a*a/(2j)
441 const double adjustedJerk =
442 std::abs(currentAcc * currentAcc / (2 * (clampedTargetV - currentV)));
443 double usedJerk = increaseAcc
444 ? goalDir * jerk
445 : -goalDir * ((std::abs(currentV) > 0.01 && !std::isnan(adjustedJerk))
446 ? adjustedJerk
447 : jerk);
448 // double t_to_target_v = ctrlutil::t_to_v(clampedTargetV - currentV, currentAcc, usedJerk);
449 // double v_at_t2 = ctrlutil::v(t_to_target_v, currentV, currentAcc, usedJerk);
450 // ctrlutil::t_to_v(currentV, currentAcc, jerk);
451 // const double usedacc = currentAcc + useddt * usedJerk;
452 // const double maxDeltaVSimple = usedacc * useddt;
453
454 const double maxDeltaV = std::abs(ctrlutil::v(useddt, 0, currentAcc, usedJerk));
455 if (maxDeltaV >= std::abs(curverror))
456 {
457 //we change our v too much with the used acceleration
458 //but we could reach our target with a lower acceleration ->set the target
459 double nextAcc = (clampedTargetV - currentV) / useddt;
460 double nextJerk = (nextAcc - currentAcc) / useddt;
461 // ARMARX_INFO << "overshooting! " << VAROUT(clampedTargetV) << VAROUT(nextAcc) << VAROUT(nextJerk);
462 Output result{clampedTargetV, nextAcc, nextJerk};
463 return result;
464 }
465 // const double deltaVel = boost::algorithm::clamp(sign(currentV) * usedacc * useddt, -maxDeltaV, maxDeltaV);
466 const double nextV = ctrlutil::v(useddt, currentV, currentAcc, usedJerk);
467 const double nextAcc = ctrlutil::a(useddt, currentAcc, usedJerk);
468 // ARMARX_INFO << VAROUT(clampedTargetV) << VAROUT(nextV) << VAROUT(nextAcc) << VAROUT(usedJerk);
469 Output result{nextV, nextAcc, usedJerk};
470 return result;
471 }
472
473 float
475 {
476 const float curverror = std::abs(targetV - currentV);
477 if (curverror < directSetVLimit)
478 {
479 return maxDt;
480 }
481 return curverror / ((targetV > currentV) ? acceleration : deceleration);
482 }
483
484 bool
486 {
488 // positionLimitLoHard < positionLimitLoSoft &&
490 // positionLimitHiSoft < positionLimitHiHard;
491 }
492
493 float
495 {
496 // if (currentPosition <= positionLimitLoHard || currentPosition >= positionLimitHiHard)
497 // {
498 // ARMARX_INFO << deactivateSpam(1) << "Hard limit violation. " << VAROUT(currentPosition) << VAROUT(positionLimitLoHard) << VAROUT(positionLimitHiHard);
499 // return std::nanf("1");
500 // }
501
502 float softLimitViolation = 0;
504 {
505 softLimitViolation = -1;
506 }
508 {
509 softLimitViolation = 1;
510 }
511
512 const float upperDt = std::max(std::abs(dt), std::abs(maxDt));
513
514 //we can have 4 cases:
515 // 1. we need to decelerate now or we will violate the position limits (maybe we still will violate them, e.g. if we violated them initially)
516 // 2. we directly set v and ignore acc/dec (if |curr - target| <= limit)
517 // 3. we need to accelerate (if curr and target v have same sign and |curr| < |target|)
518 // 4. we need to decelerate (other cases)
519 float nextv;
520 //handle case 1
521 const float vsquared = currentV * currentV;
522 const float brakingDist =
523 sign(currentV) * vsquared / 2.f /
524 std::abs(deceleration); //the braking distance points in the direction of the velocity
525
526 const float posIfBrakingNow = currentPosition + brakingDist;
527 // ARMARX_INFO << deactivateSpam(1) << VAROUT(currentPosition) << VAROUT(positionLimitLoSoft) << VAROUT(positionLimitHiSoft) << VAROUT(posIfBrakingNow);
528 if ((posIfBrakingNow <= positionLimitLoSoft && currentV < 0) ||
529 (posIfBrakingNow >= positionLimitHiSoft && currentV > 0))
530 {
531 //case 1. -> brake now! (we try to have v=0 at the limit)
532 const auto limit =
534 const float wayToGo = limit - currentPosition;
535
536 //decelerate!
537 // s = v²/(2a) <=> a = v²/(2s)
538 const float dec = std::abs(vsquared / 2.f / wayToGo);
539 const float vel = currentV - sign(currentV) * dec * upperDt;
540 nextv = std::clamp(vel, -maxV, maxV);
541 // ARMARX_INFO << deactivateSpam(1) << "clamped new Vel: " << VAROUT(nextv);
542 if (sign(currentV) != sign(nextv))
543 {
544 // ARMARX_INFO << deactivateSpam(1) << "wrong sign: stopping"; //stop now
545 nextv = 0;
546 }
547 }
548 else
549 {
550 //handle 2-3
552 // ARMARX_INFO << deactivateSpam(1) << "Desired target Vel: " << targetV << " " << VAROUT(nextv);
553 }
554 if (softLimitViolation == sign(nextv) && nextv != 0)
555 {
556 //the area between soft and hard limits is sticky
557 //the controller can only move out of it (not further in)
558 // ARMARX_DEBUG << deactivateSpam(1) << "Soft limit violation. " << softLimitViolation << VAROUT(nextv);
559 return 0;
560 }
561
562 //the next velocity will not violate the pos bounds harder than they are already
563 return nextv;
564 }
565
568 {
569#ifdef DEBUG_POS_CTRL
570 buffer = boost::circular_buffer<HelpStruct>(20);
571#endif
572 pid.reset(new PIDController(1, 0, 0));
573 pid->threadSafe = false;
574 }
575
576 float
578 {
579 /* s = v_0*v_0/(2*a) -> sqrt(s*2*a) = v_0;
580
581 K_p * error = v_0; -> v_0/error = K_p;
582 */
583 auto v_0 = std::sqrt(pControlPosErrorLimit * 2 * deceleration);
584 return v_0 / pControlPosErrorLimit;
585 }
586
587 bool
589 {
590 return maxV > 0 && acceleration > 0 && deceleration > 0 &&
591 // pControlPosErrorLimit > 0 &&
592 // pControlVelLimit > 0 &&
593 pid->Kp > 0;
594 }
595
596 float
598 {
599 const float useddt = std::min(std::abs(dt), std::abs(maxDt));
600 const float signV = sign(currentV);
601 //we can have 3 cases:
602 // 1. we use a p controller and ignore acc/dec (if |currentPosition - targetPosition| <= pControlPosErrorLimit AND |currentV| < pControlVelLimit)
603 // 2. we need to accelerate (or hold vel) (if e = (targetPosition - currentPosition)
604 // the brakingDistance have the same sign and brakingDistance < e
605 // and currentVel <= maxV)
606 // 3. we need to decelerate (other cases)
607
608 //handle case 1
609 const float positionError = targetPosition - currentPosition;
610 pid->update((double)useddt, (double)currentPosition, (double)targetPosition);
611 float newTargetVelPController = pid->getControlValue();
612
613 //handle case 2-3
614 const float brakingDistance =
615 signV * currentV * currentV / 2.f /
616 deceleration; //the braking distance points in the direction of the velocity
617 const float posIfBrakingNow = currentPosition + brakingDistance;
618 const float posErrorIfBrakingNow = targetPosition - posIfBrakingNow;
619 const bool hardBrakingNeeded = std::abs(brakingDistance) > std::abs(positionError);
620 const float safePositionError =
621 (std::abs(positionError) < 0.0001) ? (sign(positionError) * 0.0001) : positionError;
622 const float usedDeceleration = hardBrakingNeeded
623 ? std::abs(currentV * currentV / 2.f / safePositionError)
624 : deceleration;
625
626 const bool decelerate =
627 std::abs(currentV) > maxV || // we need to slow down (to stay in [-maxV,maxV]
628 hardBrakingNeeded ||
629 sign(posErrorIfBrakingNow) != signV; // we are moving away from the target
630
631 const float usedacc = decelerate ? -usedDeceleration : acceleration;
632 const float deltaVel = signV * usedacc * useddt;
633 float newTargetVelRampCtrl = std::clamp(currentV + deltaVel, -maxV, maxV);
634 bool PIDActive = /*std::abs(newTargetVelPController) < std::abs(newTargetVelRampCtrl)
635 || std::abs(newTargetVelPController) < pControlVelLimit ||*/
636 std::abs(positionError) < pControlPosErrorLimit;
637 // if (currentlyPIDActive != PIDActive && PIDActive)
638 // {
639 // ARMARX_INFO << "Switching to PID mode: " << VAROUT(positionError) << VAROUT(newTargetVelPController) << VAROUT(newTargetVelRampCtrl);
640 // }
641 this->currentlyPIDActive = PIDActive;
642 float finalTargetVel =
643 (currentlyPIDActive) ? newTargetVelPController : newTargetVelRampCtrl;
644 if (std::abs(positionError) < accuracy)
645 {
646 return 0.0; // if close to target set zero velocity to avoid oscillating around target
647 }
648 // if (hardBrakingNeeded)
649 // {
650 // ARMARX_INFO /*<< deactivateSpam(0.1)*/ << "Hard braking! " << VAROUT(positionError) << VAROUT(brakingDistance) << VAROUT(finalTargetVel) << VAROUT(currentV);
651 // }
652 // if (decelerate)
653 // {
654 // ARMARX_INFO /*<< deactivateSpam(0.1)*/ << "Decelerating! " << VAROUT(targetPosition) << VAROUT(currentPosition) << VAROUT(positionError) << VAROUT(brakingDistance) << VAROUT(finalTargetVel) << VAROUT(currentV) <<
655 // VAROUT(usedacc) << VAROUT(deltaVel) << VAROUT(useddt);
656 // }
657#ifdef DEBUG_POS_CTRL
658 buffer.push_back({currentPosition,
659 newTargetVelPController,
660 newTargetVelRampCtrl,
661 currentV,
662 positionError,
663 IceUtil::Time::now().toMicroSeconds()});
664
665 // if (PIDModeActive != usePID)
666 if (buffer.size() > 0 &&
667 sign(positionError) * sign(buffer[buffer.size() - 2].currentError) < 0 &&
668 eventHappeningCounter < 0)
669 {
670 eventHappeningCounter = 10;
671 ARMARX_IMPORTANT << "HIGH VELOCITY DETECTED";
672 }
673 if (eventHappeningCounter == 0)
674 {
675 ARMARX_IMPORTANT << "BUFFER CONTENT";
676 for (auto& elem : buffer)
677 {
678 ARMARX_INFO << VAROUT(elem.currentPosition) << VAROUT(elem.targetVelocityPID)
679 << VAROUT(elem.targetVelocityRAMP) << VAROUT(elem.currentV)
680 << VAROUT(elem.currentError) << VAROUT(elem.timestamp);
681 }
682 ARMARX_IMPORTANT << VAROUT(newTargetVelPController) << VAROUT(newTargetVelRampCtrl)
683 << VAROUT(currentPosition) << VAROUT(usePID) << VAROUT(positionError);
684 }
685 if (eventHappeningCounter >= 0)
686 {
687 eventHappeningCounter--;
688 }
689
690 ARMARX_INFO << deactivateSpam(5) << VAROUT(newTargetVelPController)
691 << VAROUT(newTargetVelRampCtrl) << VAROUT(currentPosition) << VAROUT(usePID)
692 << VAROUT(positionError) << VAROUT(targetPosition) << VAROUT(currentV)
693 << VAROUT(deltaVel) << VAROUT(useddt) << VAROUT(usedacc);
694 PIDModeActive = usePID;
695#endif
696
697 return finalTargetVel;
698 }
699
700 float
702 {
703 // const float brakingDistance = sign(currentV) * currentV * currentV / 2.f / deceleration;
704 const float posError = targetPosition - currentPosition;
705 const float posIfBrakingNow = currentPosition + brakingDistance(currentV, deceleration);
706 //we are near the goal if we break now
707 // if (std::abs(posIfBrakingNow - targetPosition) <= pControlPosErrorLimit && currentV <= pControlVelLimit)
708 // {
709 // return std::sqrt(2 * std::abs(brakingDistance(currentV, deceleration)) / deceleration);
710 // }
711 const float posErrorIfBrakingNow = targetPosition - posIfBrakingNow;
712
713 float t = 0;
714 float curVel = currentV;
715 float curPos = currentPosition;
716 auto curPosEr = [&] { return targetPosition - curPos; };
717 // auto curBrake = [&] {return std::abs(brakingDistance(curVel, deceleration));};
718
719 //check for overshooting of target
720 if (sign(posError) != sign(posErrorIfBrakingNow))
721 {
723 curVel = 0;
724 curPos = posIfBrakingNow;
725 }
726 // //check for to high v
727 // if (std::abs(curVel) > maxV)
728 // {
729 // const float dv = curVel - maxV;
730 // float dt = dv / deceleration;
731 // t += dt;
732 // // curPos += 0.5f / deceleration * dv * dv * sign(curVel);
733 // curPos += 0.5 * deceleration * dt * dt + curVel * dt * sign(curVel);
734 // curVel = maxV;
735 // }
736 //curBrake()<=curPosEr() && curVel <= maxV
737 // auto tr = trapeze(curVel, acceleration, maxV, deceleration, 0, curPosEr());
738 auto tr = trapeze(curVel,
739 std::abs(curVel) > maxV ? deceleration : acceleration,
740 maxV,
742 0,
743 curPosEr());
744
745 return t + tr.at(0).dt + tr.at(1).dt + tr.at(2).dt;
746 }
747
748 bool
756
757 float
759 {
760 const float useddt = std::min(std::abs(dt), std::abs(maxDt));
761 const float signV = sign(currentV);
762 //we can have 4 cases:
763 // 1. we need to decelerate now or we will violate the position limits (maybe we still will violate them)
764 // 2. we use a p controller and ignore acc/dec (if |currentPosition - targetPosition| <= pControlPosErrorLimit AND |currentPosition - targetPosition|*p < maxV)
765 // 4. we need to accelerate (or hold vel) (if e = (targetPosition - currentPosition)
766 // and the brakingDistance have the same sign and brakingDistance < e
767 // and currentVel <= maxV)
768 // 5. we need to decelerate (other cases)
769 //handle case 1
770 const float vsquared = currentV * currentV;
771 const float brakingDistance =
772 signV * vsquared / 2.f /
773 deceleration; //the braking distance points in the direction of the velocity
774 const float posIfBrakingNow = currentPosition + brakingDistance;
775 float direction = targetPosition < currentPosition ? -1 : 1;
776 // ARMARX_INFO << deactivateSpam(0.5) << VAROUT(direction) << VAROUT(brakingDistance) << VAROUT(currentPosition) << VAROUT(targetPosition);
777 if ((posIfBrakingNow <= positionLimitLo && direction < 1) ||
778 (posIfBrakingNow >= positionLimitHi && direction > 1))
779 {
780 //case 1. -> brake now! (we try to have v=0 at the limit)
781 const auto limit = brakingDistance > 0 ? positionLimitHi : positionLimitLo;
782 const float wayToGo = std::abs(limit - currentPosition);
783 // s = v²/(2a) <=> a = v²/(2s)
784 const float dec = std::abs(vsquared / 2.f / wayToGo);
785 const float vel = currentV - signV * dec * useddt;
786 // ARMARX_INFO << /*deactivateSpam(0.1) <<*/ "Braking now! " << VAROUT(vel) << VAROUT(wayToGo) << VAROUT(limit);
787 return vel;
788 }
789
790 //handle case 2-3
792 }
793
794 std::array<deltas, 3>
795 trapeze(float v0, float acc, float vMax, float dec, float vt, float dx)
796 {
797 acc = std::abs(acc);
798 vMax = std::abs(vMax);
799 dec = std::abs(dec);
800 auto calc = [&](float vmax)
801 {
802 const deltas dacc = accelerateToVelocity(v0, acc, vmax);
803 const deltas ddec = accelerateToVelocity(vmax, dec, vt);
804 const float dxMax = dacc.dx + ddec.dx;
805 if (sign(dxMax) == sign(dx))
806 {
807 if (std::abs(dxMax) <= dx)
808 {
809 deltas mid;
810 mid.dx = dxMax - dx;
811 mid.dv = vMax;
812 mid.dt = std::abs(mid.dx / mid.dv);
813 return std::make_pair(true, std::array<deltas, 3>{dacc, mid, ddec});
814 }
815 //we need a lower vMax (vx)
816 //in all following formulas # elem {0,t}
817 //a0=acc , at = dec
818 //vx=v0+dv0 = vt + dvt -> dv# = vx-v#
819 //dx=dx0+dxt
820 //dx#=dv#^2/2/a#+dv#/a#*v#
821 //dx#=(vx-v#)^2/2/a#+(vx-v#)/a#*v#
822 //dx#=vx^2*(1/2/a#) + vx*(v#/2 - v#/a#) + (v#^2/2/a# - v#^2/2)
823 //dx=vx^2*(1/2/a0+1/2/at) + vx*(v0/2 - v0/a0 + vt/2 - vt/at) + (v0^2/2/a0 - v0^2/2 +vt^2/2/at - vt^2/2)
824 //0 =vx^2*(1/2/a0+1/2/at) + vx*(v0/2 - v0/a0 + vt/2 - vt/at) + (v0^2/2/a0 - v0^2/2 +vt^2/2/at - vt^2/2 -dx)
825 //div = (1/2/a0 + 1/2/at )
826 //p = (v0/2 - v0/a0 + vt/2 - vt/at )/div
827 //q = (v0^2/2/a0 - v0^2/2 + vt^2/2/at - vt^2/2 -dx)/div
828 // -> vx1/2 = pq(p,q)
829 const float a0 = acc;
830 const float at = dec;
831 const float div = (1.f / 2.f / a0 + 1.f / 2.f / at);
832 const float p = (v0 / 2.f - v0 / a0 + vt / 2.f - vt / at) / div;
833 const float q =
834 (v0 * v0 / 2.f * (1.f / a0 - 1.f) + vt * vt / 2.f * (1.f / at - 1.f) - dx) /
835 div;
836 const auto vxs = pq(p, q);
837 //one or both of the results may be invalid
838 bool vx1Valid = std::isfinite(vxs.first) && std::abs(vxs.first) <= std::abs(vmax);
839 bool vx2Valid = std::isfinite(vxs.second) && std::abs(vxs.second) <= std::abs(vmax);
840 switch (vx1Valid + vx2Valid)
841 {
842 case 0:
843 return std::make_pair(false, std::array<deltas, 3>());
844 case 1:
845 {
846 float vx = vx1Valid ? vxs.first : vxs.second;
847 const deltas daccvx = accelerateToVelocity(v0, acc, vx);
848 const deltas ddecvx = accelerateToVelocity(vx, dec, vt);
849 deltas mid;
850 mid.dx = 0;
851 mid.dv = vx;
852 mid.dt = 0;
853 return std::make_pair(true, std::array<deltas, 3>{daccvx, mid, ddecvx});
854 }
855 case 2:
856 {
857 const deltas daccvx1 = accelerateToVelocity(v0, acc, vxs.first);
858 const deltas ddecvx1 = accelerateToVelocity(vxs.first, dec, vt);
859 const deltas daccvx2 = accelerateToVelocity(v0, acc, vxs.second);
860 const deltas ddecvx2 = accelerateToVelocity(vxs.second, dec, vt);
861 deltas mid;
862 mid.dx = 0;
863 mid.dt = 0;
864 if (daccvx1.dt + ddecvx1.dt < daccvx2.dt + ddecvx2.dt)
865 {
866 mid.dv = vxs.first;
867 return std::make_pair(true,
868 std::array<deltas, 3>{daccvx1, mid, ddecvx1});
869 }
870 mid.dv = vxs.second;
871 return std::make_pair(true, std::array<deltas, 3>{daccvx2, mid, ddecvx2});
872 }
873 default:
874 throw std::logic_error{"unreachable code (bool + bool neither 0,1,2)"};
875 }
876 }
877 return std::make_pair(false, std::array<deltas, 3>());
878 };
879
880 const auto plusVMax = calc(vMax);
881 const auto negVMax = calc(-vMax);
882 switch (plusVMax.first + negVMax.first)
883 {
884 case 0:
885 throw std::invalid_argument("could not find a trapez to reach the goal");
886 case 1:
887 return plusVMax.first ? plusVMax.second : negVMax.second;
888 case 2:
889 {
890 const float dt1 =
891 plusVMax.second.at(0).dt + plusVMax.second.at(1).dt + plusVMax.second.at(2).dt;
892 const float dt2 =
893 negVMax.second.at(0).dt + negVMax.second.at(1).dt + negVMax.second.at(2).dt;
894 return dt1 < dt2 ? plusVMax.second : negVMax.second;
895 }
896 default:
897 throw std::logic_error{"unreachable code (bool + bool neither 0,1,2)"};
898 }
899 }
900
901 float
903 {
904 //run should be static, but we need to adapt the parabs for the subcontroler -> have the subcontroler as value;
906 *this; // slice parent class from this
908 // ARMARX_INFO << deactivateSpam(1) << VAROUT(currentPosition) << VAROUT(sub.currentPosition) << VAROUT(positionPeriodLo) << VAROUT(positionPeriodHi);
910
911 const float brakingDist = brakingDistance(currentV, deceleration);
912 // const float posIfBrakingNow = currentPosition + brakingDist;
913 // const float posIfBrakingNowError = targetPosition - posIfBrakingNow;
914 // const float posError = targetPosition - currentPosition;
915 // if (
916 // std::abs(posIfBrakingNowError) <= pControlPosErrorLimit ||
917 // std::abs(posError) <= pControlPosErrorLimit
918 // )
919 // {
920 // //this allows slight overshooting (in the limits of the p controller)
921 // return PositionThroughVelocityControllerWithAccelerationBounds::run();
922 // }
923
924 //we transform the problem with periodic bounds into
925 //a problem with position bounds
926 const float positionPeriodLength = std::abs(positionPeriodHi - positionPeriodLo);
927
928 //we shift the positions such that 0 == target
930 -positionPeriodLength * 0.5f,
931 positionPeriodLength * 0.5f);
932 //how many times will we go over the target if we simply brake now?
933 const float overshoot = std::trunc((currentPosition + brakingDist) / positionPeriodLength);
934
935 ///TODO check if there may be a case requiring the direction
936 float direction = 0;
937 if (direction == 0)
938 {
939 //determine the direction to go (1 == pos vel, -1 == neg vel)
940 direction = (periodicClamp(currentPosition + brakingDist,
941 -positionPeriodLength * 0.5f,
942 positionPeriodLength * 0.5f) <= 0)
943 ? 1
944 : -1;
945 }
946 //shift the target away from 0
947 sub.targetPosition =
948 (overshoot * -direction) * positionPeriodLength; // - direction * pControlPosErrorLimit;
949
950 //move
951 return sub.run();
952 }
953
954 double
959
960 bool
965
966 void
968 {
969 if (std::abs(value - targetPosition) > 0.0001)
970 {
972 }
973 targetPosition = value;
974 }
975
980
981 bool
983 {
984 return maxV > 0 && acceleration > 0 && deceleration > 0 && jerk > 0 &&
985 // pControlPosErrorLimit > 0 &&
986 // pControlVelLimit > 0 &&
987 p > 0;
988 }
989
992 {
994 const double useddt = std::min(std::abs(dt), std::abs(maxDt));
995 const double signV = sign(currentV);
996 //we can have 3 cases:
997 // 1. we use a p controller and ignore acc/dec (if |currentPosition - targetPosition| <= pControlPosErrorLimit AND |currentV| < pControlVelLimit)
998 // 2. we need to accelerate (or hold vel) (if e = (targetPosition - currentPosition)
999 // the brakingDistance have the same sign and brakingDistance < e
1000 // and currentVel <= maxV)
1001 // 3. we need to decelerate (other cases)
1002
1003 //handle case 1
1004 const double positionError = targetPosition - currentPosition;
1005 double newTargetVelPController = (positionError * p) * 0.5 + currentV * 0.5;
1006
1007 //handle case 2-3
1009 if (brData.dt2 < 0)
1010 {
1012 }
1014 // State currentState;
1015 double usedAbsJerk;
1016 State newState;
1017 Output output;
1018 std::tie(newState, output) = calcState();
1019 usedAbsJerk = output.jerk;
1020 // double newJerk = output.jerk;
1021 // double newAcceleration = output.acceleration;
1022 // ARMARX_INFO << "state: " << (int)state << " new state: " << (int)newState;
1023 state = newState;
1024 const double brakingDistance =
1025 brData.dt2 >= 0
1026 ? brData.s_total
1027 : signV * currentV * currentV / 2.f /
1028 deceleration; //the braking distance points in the direction of the velocity
1029 const double posIfBrakingNow = currentPosition + brakingDistance;
1030 const double posErrorIfBrakingNow = targetPosition - posIfBrakingNow;
1031 const bool hardBrakingNeeded = std::abs(brakingDistance) > std::abs(positionError);
1032 // const double usedJerk = jerk;//currentState==State::DecAccDecJerk?std::abs(ctrlutil::jerk(ctrlutil::t_to_v(currentV, -signV*currentAcc, signV*jerk), positionError, currentV, currentAcc))
1033 // :jerk;
1034 const double jerkDir =
1035 (newState == State::DecAccIncJerk || newState == State::IncAccDecJerk) ? -1.0f : 1.0f;
1036 const double usedJerk = goalDir * jerkDir * usedAbsJerk;
1037 const double deltaAcc = usedJerk * useddt;
1038 const double newAcceleration =
1039 (newState == State::Keep)
1040 ? currentAcc
1041 : (newState == State::DecAccDecJerk ? output.acceleration : currentAcc + deltaAcc);
1042 result.acceleration = newAcceleration;
1043 result.jerk = usedJerk;
1044
1045 const double usedDeceleration =
1046 hardBrakingNeeded ? -std::abs(currentV * currentV / 2.f /
1047 math::MathUtils::LimitTo(positionError, 0.0001))
1048 : newAcceleration;
1049 (void)usedDeceleration;
1050
1051 const bool decelerate =
1052 std::abs(currentV) > maxV || // we need to slow down (to stay in [-maxV,maxV]
1053 hardBrakingNeeded ||
1054 sign(posErrorIfBrakingNow) != signV; // we are moving away from the target
1055 (void)decelerate;
1056
1057 const double deltaVel =
1058 ctrlutil::v(useddt, 0, newAcceleration, usedJerk); //signV * newAcceleration * useddt;
1059 (void)deltaVel;
1060
1061 double newTargetVelRampCtrl =
1062 ctrlutil::v(useddt,
1063 currentV,
1064 currentAcc,
1065 usedJerk); //boost::algorithm::clamp(currentV + deltaVel, -maxV, maxV);
1066 newTargetVelRampCtrl = std::clamp(newTargetVelRampCtrl, -maxV, maxV);
1067 bool usePID = std::abs(newTargetVelPController) < std::abs(newTargetVelRampCtrl); //||
1068 // std::abs(newTargetVelPController) < pControlVelLimit &&
1069 //std::abs(positionError) < pControlPosErrorLimit;
1070 usePID |= state == State::PCtrl;
1071 usePID &= usePIDAtEnd;
1072 if (usePID)
1073 {
1075 }
1076 double finalTargetVel = usePID ? newTargetVelPController : newTargetVelRampCtrl;
1077 ARMARX_INFO << VAROUT(usePID) << VAROUT(result.jerk) << VAROUT(newTargetVelPController)
1078 << VAROUT(currentV);
1079 // ARMARX_INFO << VAROUT(currentV) << VAROUT(currentAcc) << VAROUT(usedJerk) << VAROUT(newAcceleration) << VAROUT(deltaVel) << VAROUT(finalTargetVel) << " new distance: " << (targetPosition - ctrlutil::s(dt, currentPosition, currentV, currentAcc, usedJerk));
1080 if (std::abs(positionError) < accuracy)
1081 {
1082 finalTargetVel =
1083 0.0f; // if close to target set zero velocity to avoid oscillating around target
1084 }
1085
1086#ifdef DEBUG_POS_CTRL
1087 buffer.push_back({currentPosition,
1088 newTargetVelPController,
1089 newTargetVelRampCtrl,
1090 currentV,
1091 positionError,
1092 IceUtil::Time::now().toMicroSeconds()});
1093
1094 // if (PIDModeActive != usePID)
1095 if (buffer.size() > 0 &&
1096 sign(positionError) * sign(buffer[buffer.size() - 2].currentError) < 0 &&
1097 eventHappeningCounter < 0)
1098 {
1099 eventHappeningCounter = 10;
1100 ARMARX_IMPORTANT << "HIGH VELOCITY DETECTED";
1101 }
1102 if (eventHappeningCounter == 0)
1103 {
1104 ARMARX_IMPORTANT << "BUFFER CONTENT";
1105 for (auto& elem : buffer)
1106 {
1107 ARMARX_INFO << VAROUT(elem.currentPosition) << VAROUT(elem.targetVelocityPID)
1108 << VAROUT(elem.targetVelocityRAMP) << VAROUT(elem.currentV)
1109 << VAROUT(elem.currentError) << VAROUT(elem.timestamp);
1110 }
1111 ARMARX_IMPORTANT << VAROUT(newTargetVelPController) << VAROUT(newTargetVelRampCtrl)
1112 << VAROUT(currentPosition) << VAROUT(usePID) << VAROUT(positionError);
1113 }
1114 if (eventHappeningCounter >= 0)
1115 {
1116 eventHappeningCounter--;
1117 }
1118
1119 ARMARX_INFO << deactivateSpam(5) << VAROUT(newTargetVelPController)
1120 << VAROUT(newTargetVelRampCtrl) << VAROUT(currentPosition) << VAROUT(usePID)
1121 << VAROUT(positionError) << VAROUT(targetPosition) << VAROUT(currentV)
1122 << VAROUT(deltaVel) << VAROUT(useddt) << VAROUT(usedacc);
1123 PIDModeActive = usePID;
1124#endif
1125 result.velocity = finalTargetVel;
1126 return result;
1127 }
1128
1129 double
1131 {
1132 throw LocalException("NYI");
1133 return 0;
1134 }
1135
1136 double
1138 {
1139 /* s = v_0*v_0/(2*a) -> sqrt(s*2*a) = v_0;
1140
1141 K_p * error = v_0; -> v_0/error = K_p;
1142 */
1143 auto v_0 = std::sqrt(pControlPosErrorLimit * 2 * deceleration);
1144 return v_0 / pControlPosErrorLimit;
1145 }
1146
1150 {
1151 // auto integratedChange = [](v0)
1152
1153 // double newJerk = this->jerk;
1154 // double newAcc = currentAcc;
1155 // double newVel = currentV;
1156 State newState = state;
1157 double a0 = currentAcc, newJerk = jerk, t;
1158 Output result = {currentV, a0, newJerk};
1159
1160 const auto brData = ctrlutil::braking_distance_with_wedge(currentV, currentAcc, newJerk);
1162 const auto curVDir = math::MathUtils::Sign(currentV);
1163 const auto straightBrakingDistance =
1165 const double brakingDistance = brData.dt2 < 0 ? straightBrakingDistance : brData.s_total;
1166 const double distance = std::abs(targetPosition - currentPosition);
1167 const double t_to_stop =
1168 ctrlutil::t_to_v(currentV, -curVDir * currentAcc, curVDir * newJerk);
1169 const auto calculatedJerk =
1170 std::abs(ctrlutil::jerk(t_to_stop, distance, currentV, currentAcc));
1171 double tmp_t, tmp_acc, tmp_jerk;
1172 // std::tie( tmp_t, tmp_acc, tmp_jerk) = ctrlutil::calcAccAndJerk(targetPosition-(currentPosition+brData.s1), brData.v1);
1173 std::tie(tmp_t, tmp_acc, tmp_jerk) =
1175 const double posWhenBrakingWithCustomJerk =
1176 ctrlutil::s(tmp_t, currentPosition + brData.s1, brData.v1, tmp_acc, curVDir * tmp_jerk);
1177 // const double brakingDistanceWithCustomJerk = ctrlutil::s(tmp_t, 0, currentV, tmp_acc, curVDir * tmp_jerk);
1178 const double posWhenBrakingWithFixedJerk = ctrlutil::s(
1179 brData.dt2, currentPosition + brData.s1, brData.v1, brData.a1, curVDir * jerk);
1180 (void)calculatedJerk, (void)posWhenBrakingWithCustomJerk, (void)posWhenBrakingWithFixedJerk;
1181
1183 << VAROUT((int)state) << VAROUT(distance)
1184 << VAROUT(
1185 brakingDistance); //VAROUT(straightBrakingDistance) << VAROUT(brData.dt1) << VAROUT(brData.dt2) << VAROUT(brData.s_total) << VAROUT(calculatedJerk);
1186
1187 // if(brData.dt2 < 0)
1188 // {
1189 // ARMARX_INFO << "distance with fixed jerk: " << ctrlutil::brakingDistance(currentV, currentAcc, newJerk)
1190 // << " distance with custom jerk: " << ctrlutil::brakingDistance(currentV, currentAcc, calculatedJerk)
1191 // << " vel after: " << ctrlutil::v(t_to_stop, currentV, currentAcc, -curVDir * newJerk) << " vel after next step: " << ctrlutil::v(dt, currentV, currentAcc, -curVDir * newJerk);
1192 //// << " acc at stop: " << ctrlutil::a(t_to_stop, currentAcc, -curVDir *newJerk);
1193 // jerk = 0.95*calculatedJerk;
1194 // state = State::DecAccDecJerk;
1195 // return;
1196 // }
1199 std::abs(currentAcc) < 0.1)) // we are accelerating
1201 2 // we are decelerating -> dont switch to accelerating to easily
1202 || curVDir != goalDir)) // we are moving away from goal
1203 {
1204 if (std::abs(maxV - currentV) < 0.1 && std::abs(currentAcc) < 0.1)
1205 {
1206 newState = State::Keep;
1207 newJerk = 0;
1208 return std::make_pair(newState, result);
1209 }
1210 // calculate if we need to increase or decrease acc
1211 double t_to_max_v =
1212 ctrlutil::t_to_v(goalDir * maxV - currentV, currentAcc, goalDir * newJerk);
1213 double acc_at_t = ctrlutil::a(t_to_max_v, std::abs(currentAcc), -newJerk);
1214 if (acc_at_t < 0.1)
1215 {
1216 newState = State::IncAccIncJerk;
1217 return std::make_pair(newState, result);
1218 }
1219 else
1220 {
1221 newState = State::IncAccDecJerk;
1222 return std::make_pair(newState, result);
1223 }
1224 }
1225 else
1226 {
1227 // calculate if we need to increase or decrease acc
1228 double t_to_0 = ctrlutil::t_to_v(currentV, -curVDir * currentAcc, curVDir * newJerk);
1229 double tmpV = ctrlutil::v(t_to_0, 0, currentAcc, -curVDir * newJerk);
1230 double vAfterBraking = ctrlutil::v(t_to_0, currentV, currentAcc, -curVDir * newJerk);
1231 double accAfterBraking = ctrlutil::a(t_to_0, currentAcc, curVDir * newJerk);
1232 const double posWhenBrakingNow =
1233 ctrlutil::s(t_to_0, currentPosition, currentV, currentAcc, -curVDir * newJerk);
1234 const double simpleBrakingDistance =
1235 ctrlutil::s(t_to_0, 0, currentV, currentAcc, -curVDir * newJerk);
1236 (void)tmpV, (void)vAfterBraking, (void)accAfterBraking, (void)posWhenBrakingNow,
1237 (void)simpleBrakingDistance;
1238 double acc_at_t = ctrlutil::a(t_to_0, std::abs(currentAcc), -newJerk);
1239
1240 std::tie(t, a0, newJerk) =
1242 double at = ctrlutil::a(t, a0, newJerk);
1243 double vt = ctrlutil::v(t, currentV, a0, newJerk);
1244 double st = ctrlutil::s(t, targetPosition - currentPosition, currentV, a0, newJerk);
1245 (void)at, (void)vt, (void)st;
1246
1247 if (this->state <= State::Keep)
1248 {
1249 newState = State::DecAccIncJerk;
1250 return std::make_pair(newState, result);
1251 }
1252 else if ((state == State::DecAccIncJerk && acc_at_t > 1) ||
1254 {
1255 result.jerk = newJerk;
1256 result.acceleration = currentAcc + (a0 - currentAcc) * 0.5 + dt * newJerk;
1257 newState = State::DecAccDecJerk;
1258 return std::make_pair(newState, result);
1259 }
1260 else
1261 {
1262 return std::make_pair(newState, result);
1263 }
1264 }
1265 throw LocalException();
1266 }
1267
1268 void
1270 {
1271 currentTime = 0;
1272
1273 fixedMinJerkState.reset();
1274 // pid.reset();
1275 currentP_Phase2 = -1;
1276 currentP_Phase3 = -1;
1277 }
1278
1279 double
1284
1285 // MinJerkPositionController::Output MinJerkPositionController::run()
1286 // {
1287 // auto min_jerk_calc_jerk = [&](double tf, double s0, double v0, double a0, double xf = 0, double t0 = 0.0)
1288 // {
1289 // double D = tf - t0;
1290 // return 60.0 / (D * D * D) * (xf - s0) - 36.0 / (D * D) * v0 - 9.0 / D * a0;
1291 // };
1292
1293
1294 // auto min_jerk = [&](double t, double tf, double s0, double v0, double a0, double xf = 0, double t0 = 0.0)
1295 // {
1296 // double D = tf - t0;
1297 // BOOST_ASSERT(D != 0.0);
1298 // double D2 = D * D;
1299 // double tau = (t - t0) / D;
1300 // double b0 = s0;
1301 // double b1 = D * v0;
1302 // double b2 = D2 * a0 / 2;
1303
1304 // double b3 = (-3 * D2) / 2 * a0 - 6 * D * v0 + 10 * (xf - s0);
1305 // double b4 = (3 * D2) / 2 * a0 + 8 * D * v0 - 15 * (xf - s0);
1306 // double b5 = (-D2) / 2 * a0 - 3 * D * v0 + 6 * (xf - s0);
1307
1308 // double tau2 = tau * tau;
1309 // double tau3 = tau2 * tau;
1310 // double tau4 = tau3 * tau;
1311 // double tau5 = tau4 * tau;
1312 // double st = b0 + b1 * tau + b2 * tau2 + b3 * tau3 + b4 * tau4 + b5 * tau5;
1313 // double vt = b1 / D + 2 * b2 / D * tau + 3 * b3 / D * tau2 + 4 * b4 / D * tau3 + 5 * b5 / D * tau4;
1314 // double at = 2 * b2 / D2 + 6 * b3 / D2 * tau + 12 * b4 / D2 * tau2 + 20 * b5 / D2 * tau3;
1315 // return State{t, st, vt, at};
1316 // };
1317
1318 // double remainingTime = finishTime - currentTime;
1319 // double signedDistance = targetPosition - currentPosition;
1320 // if (remainingTime <= 0.0)
1321 // {
1322 // // if(!pid)
1323 // // {
1324 // // double Kd = (currentV - distance * p) /(-currentV);
1325 // // ARMARX_INFO << VAROUT(Kd);
1326 // // pid.reset(new PIDController(1, 0, Kd));
1327 // // }
1328 // if (currentP_Phase3 < 0)
1329 // {
1330 // currentP_Phase3 = std::abs(currentV / signedDistance);
1331 // ARMARX_DEBUG << "optimal P: " << currentP_Phase3;
1332 // }
1333
1334
1335 // currentP_Phase3 = currentP_Phase3 * p_adjust_ratio + p * (1.0 - p_adjust_ratio);
1336 // double newVel = signedDistance * currentP_Phase3;
1337 // double newAcc = (newVel - currentV) / dt;
1338 // double newJerk = (newAcc - currentAcc) / dt;
1339 // double newPos = currentPosition + newVel * dt;
1340 // Output result {newPos, newVel, newAcc, newJerk};
1341 // currentTime += dt;
1342 // // State s = min_jerk(currentTime, finishTime, fixedMinJerkState->s0, fixedMinJerkState->v0, fixedMinJerkState->a0, targetPosition, fixedMinJerkState->t0);
1343 // ARMARX_DEBUG << VAROUT(remainingTime) << VAROUT(signedDistance) << VAROUT(signedDistance * currentP_Phase3) << VAROUT(currentP_Phase3);// << VAROUT(s.s) << VAROUT(s.v) << VAROUT(s.a);
1344 // return result;
1345 // }
1346
1347 // if (std::abs(signedDistance) < phase2SwitchDistance && remainingTime < phase2SwitchMaxRemainingTime)
1348 // {
1349 // if (!fixedMinJerkState)
1350 // {
1351 // fixedMinJerkState.reset(new FixedMinJerkState{currentTime, currentPosition, currentV, currentAcc});
1352 // currentP_Phase2 = 0;
1353 // }
1354 // // std::vector<State> states;
1355 // // double t = currentTime;
1356 // // while(t < finishTime)
1357 // // {
1358 // // State s = min_jerk(t, finishTime, fixedMinJerkState->s0, fixedMinJerkState->v0, fixedMinJerkState->a0, targetPosition, fixedMinJerkState->t0);
1359 // // t += dt;
1360 // // states.push_back(s);
1361 // // }
1362 // currentTime += dt;
1363 // State s = min_jerk(currentTime, finishTime, fixedMinJerkState->s0, fixedMinJerkState->v0, fixedMinJerkState->a0, targetPosition, fixedMinJerkState->t0);
1364 // currentP_Phase2 = currentP_Phase2 * p_adjust_ratio + p * (1.0 - p_adjust_ratio);
1365 // double newVel = (s.s - currentPosition) * currentP_Phase2 + s.v;
1366 // ARMARX_DEBUG << VAROUT(s.s) << VAROUT(s.v) << VAROUT(newVel);
1367 // double newAcc = (newVel - currentV) / dt;
1368 // double newJerk = (newAcc - currentAcc) / dt;
1369 // double newPos = currentPosition + newVel * dt;
1370 // Output result {newPos, newVel, newAcc, newJerk};
1371 // return result;
1372 // }
1373
1374
1375 // double jerk = min_jerk_calc_jerk(remainingTime, currentPosition, currentV, currentAcc, targetPosition);
1376 // double newAcc = currentAcc + jerk * dt;
1377 // double newVelocity = ctrlutil::v(dt, currentV, currentAcc, jerk);
1378 // double accAtEnd = ctrlutil::a(remainingTime, currentAcc, jerk);
1379
1380 // std::vector<State> states;
1381 // std::vector<State> states2;
1382 // //#define debug
1383 //#ifdef debug
1384 // {
1385 // double dt = 0.001;
1386 // double t = 1;
1387 // double simS = currentPosition, simV = currentV, simAcc = currentAcc;
1388 // while (t > 0)
1389 // {
1390 // double jerk = min_jerk_calc_jerk(t, simS, simV, simAcc, targetPosition);
1391 // simAcc = simAcc + jerk * dt;
1392 // simV = ctrlutil::v(dt, simV, simAcc, 0);
1393 // simS += dt * simV;
1394 // t -= dt;
1395 // states.push_back(State{t, simS, simV, simAcc, jerk});
1396 // }
1397 // }
1398 // {
1399 // double dt = 0.001;
1400
1401 // double t = 1;
1402 // double simS = currentPosition, simV = currentV, simAcc = currentAcc;
1403 // while (t > 0)
1404 // {
1405 // double jerk = min_jerk_calc_jerk(t, simS, simV, simAcc, targetPosition);
1406 // simS += ctrlutil::s(dt, 0, simV, simAcc, jerk);
1407 // simV = ctrlutil::v(dt, simV, simAcc, jerk);
1408 // simAcc = simAcc + jerk * dt;
1409 // t -= dt;
1410 // states2.push_back(State{t, simS, simV , simAcc, jerk});
1411 // }
1412 // }
1413 //#endif
1414 // ARMARX_DEBUG << VAROUT(currentTime) << VAROUT(remainingTime) << VAROUT(jerk) << VAROUT(accAtEnd) << VAROUT(signedDistance) << " delta acc: " << jerk* dt;
1415 // currentTime += dt;
1416
1417
1418 // double newPos = ctrlutil::s(dt, currentPosition, currentV, currentAcc, jerk);
1419 // Output result { newPos, newVelocity, newAcc, jerk};
1420 // return result;
1421
1422 // }
1423
1424 bool
1430
1433 {
1434 const double useddt = std::min(std::abs(dt), std::abs(maxDt));
1435 (void)useddt;
1436
1437 // if (currentPosition <= positionLimitLoHard || currentPosition >= positionLimitHiHard)
1438 // {
1439 // ARMARX_INFO << deactivateSpam(1) << "Hard limit violation. " << VAROUT(currentPosition) << VAROUT(positionLimitLoHard) << VAROUT(positionLimitHiHard);
1440 // return std::nanf("1");
1441 // }
1442
1443 double softLimitViolation = 0;
1445 {
1446 softLimitViolation = -1;
1447 }
1449 {
1450 softLimitViolation = 1;
1451 }
1452
1453 const double upperDt = std::max(std::abs(dt), std::abs(maxDt));
1454
1455 //we can have 4 cases:
1456 // 1. we need to decelerate now or we will violate the position limits (maybe we still will violate them, e.g. if we violated them initially)
1457 // 2. we directly set v and ignore acc/dec (if |curr - target| <= limit)
1458 // 3. we need to accelerate (if curr and target v have same sign and |curr| < |target|)
1459 // 4. we need to decelerate (other cases)
1460 double nextv;
1461 //handle case 1
1462 const double vsquared = currentV * currentV;
1463 const double brakingDist =
1464 sign(currentV) * vsquared / 2.f /
1465 std::abs(deceleration); //the braking distance points in the direction of the velocity
1466
1467 const double posIfBrakingNow = currentPosition + brakingDist;
1468 // ARMARX_INFO << deactivateSpam(0.1) << VAROUT(currentPosition) << VAROUT(positionLimitLoSoft) << VAROUT(positionLimitHiSoft) << VAROUT(posIfBrakingNow) << VAROUT(currentV);
1469 if ((posIfBrakingNow <= positionLimitLoSoft && currentV < 0) ||
1470 (posIfBrakingNow >= positionLimitHiSoft && currentV > 0))
1471 {
1472 //case 1. -> brake now! (we try to have v=0 at the limit)
1473 const auto limit =
1475 const double wayToGo = limit - currentPosition;
1476
1477 //decelerate!
1478 // s = v²/(2a) <=> a = v²/(2s)
1479 const double dec = std::abs(vsquared / 2.0 / wayToGo);
1480 const double vel = currentV - sign(currentV) * dec * upperDt;
1481 nextv = std::clamp<double>(vel, -maxV, maxV);
1482 // ARMARX_INFO /*<< deactivateSpam(0.1)*/ << "clamped new Vel: " << VAROUT(nextv) << VAROUT(currentV);
1483 if (sign(currentV) != sign(nextv))
1484 {
1485 // ARMARX_INFO << deactivateSpam(1) << "wrong sign: stopping"; //stop now
1486 nextv = 0;
1487 }
1488 }
1489 else
1490 {
1491 //handle 2-3
1493 // ARMARX_INFO << deactivateSpam(1) << "Desired target Vel: " << targetV << " " << VAROUT(nextv);
1494 }
1495 if (softLimitViolation == sign(nextv) && nextv != 0)
1496 {
1497 //the area between soft and hard limits is sticky
1498 //the controller can only move out of it (not further in)
1499 // ARMARX_INFO << deactivateSpam(1) << "Soft limit violation. " << softLimitViolation << VAROUT(nextv);
1500 nextv = 0;
1501 }
1502 // double nextAcc = (nextv - currentV) / useddt; // doesnt work with calculated acc!!
1503 // double nextJerk = (nextAcc - currentAcc) / useddt;
1504 //the next velocity will not violate the pos bounds harder than they are already
1505 return Output{nextv, 0, 0};
1506 }
1507
1508 void
1510 {
1511 if (std::abs(targetPosition - newTargetPosition) > 0.0001)
1512 {
1513 reset();
1514 double distance = newTargetPosition - currentPosition;
1515 double rawFinishTime = 0.0;
1516 double decelerationTime = std::abs(currentV / desiredDeceleration);
1517 // calculate the time it should take to reach the goal (ToDo: find exact time)
1519 std::abs(currentV) > 0.0 &&
1520 ctrlutil::s(decelerationTime, 0, std::abs(currentV), -desiredDeceleration, 0) >
1521 std::abs(distance))
1522 // && ctrlutil::brakingDistance(currentV, currentAcc, desiredJerk) < distance)
1523 {
1524 // ARMARX_INFO << "branch 1: " << VAROUT(currentV) << VAROUT(desiredDeceleration) << VAROUT(distance);
1525 rawFinishTime = decelerationTime;
1526 }
1527 else
1528 {
1529 // ARMARX_INFO << "branch 2: " << VAROUT(currentV) << VAROUT(desiredDeceleration) << VAROUT(distance);
1530 double accelerationTime = std::abs(
1532 double decelerationTime = std::abs(maxV / desiredDeceleration);
1533 rawFinishTime = std::max(decelerationTime + accelerationTime,
1534 std::abs(distance / (maxV * 0.75)));
1535 }
1536 double estimatedTime = ctrlutil::t_to_v_with_wedge_acc(
1537 std::abs(distance), std::abs(currentV), std::abs(desiredDeceleration));
1538 double minTime = 0.8;
1539 if (!std::isnan(estimatedTime))
1540 {
1541 finishTime = std::max(estimatedTime, minTime);
1542 }
1543 else
1544 {
1545 finishTime = std::max(rawFinishTime, minTime);
1546 }
1547 targetPosition = newTargetPosition;
1548 // ARMARX_INFO << "New finish time: " << finishTime << " " << VAROUT(rawFinishTime) << VAROUT(estimatedTime);
1549 }
1550 }
1551
1554 {
1555 auto min_jerk_calc_jerk =
1556 [&](double tf, double s0, double v0, double a0, double xf = 0, double t0 = 0.0)
1557 {
1558 double D = tf - t0;
1559 return 60.0 / (D * D * D) * (xf - s0) - 36.0 / (D * D) * v0 - 9.0 / D * a0;
1560 };
1561
1562
1563 auto min_jerk = [&](double t,
1564 double tf,
1565 double s0,
1566 double v0,
1567 double a0,
1568 double xf = 0,
1569 double t0 = 0.0)
1570 {
1571 double D = tf - t0;
1572 ARMARX_CHECK(D != 0.0);
1573 double D2 = D * D;
1574 double tau = (t - t0) / D;
1575 double b0 = s0;
1576 double b1 = D * v0;
1577 double b2 = D2 * a0 / 2;
1578
1579 double b3 = (-3 * D2) / 2 * a0 - 6 * D * v0 + 10 * (xf - s0);
1580 double b4 = (3 * D2) / 2 * a0 + 8 * D * v0 - 15 * (xf - s0);
1581 double b5 = (-D2) / 2 * a0 - 3 * D * v0 + 6 * (xf - s0);
1582
1583 double tau2 = tau * tau;
1584 double tau3 = tau2 * tau;
1585 double tau4 = tau3 * tau;
1586 double tau5 = tau4 * tau;
1587 double st = b0 + b1 * tau + b2 * tau2 + b3 * tau3 + b4 * tau4 + b5 * tau5;
1588 double vt = b1 / D + 2 * b2 / D * tau + 3 * b3 / D * tau2 + 4 * b4 / D * tau3 +
1589 5 * b5 / D * tau4;
1590 double at = 2 * b2 / D2 + 6 * b3 / D2 * tau + 12 * b4 / D2 * tau2 + 20 * b5 / D2 * tau3;
1591 return State{t, st, vt, at};
1592 };
1593
1594 double remainingTime = finishTime - currentTime;
1595 double signedDistance = targetPosition - currentPosition;
1596 if (remainingTime <= 0.0)
1597 {
1598 // if(!pid)
1599 // {
1600 // double Kd = (currentV - distance * p) /(-currentV);
1601 // ARMARX_INFO << VAROUT(Kd);
1602 // pid.reset(new PIDController(1, 0, Kd));
1603 // }
1604 if (currentP_Phase3 < 0)
1605 {
1606 if (signedDistance == 0.0f)
1607 {
1609 }
1610 else
1611 {
1612 currentP_Phase3 = std::abs(currentV / signedDistance);
1614 }
1615 // ARMARX_INFO << deactivateSpam(0.1) << "optimal P: " << currentP_Phase3 << VAROUT(currentV) << VAROUT(signedDistance);
1616 }
1617
1618
1620 double newVel = signedDistance * currentP_Phase3;
1621 double newAcc = (newVel - currentV) / dt;
1622 double newJerk = (newAcc - currentAcc) / dt;
1623 double newPos = currentPosition + newVel * dt;
1624
1625 Output result{newPos, newVel, newAcc, newJerk};
1626 currentTime += dt;
1627 // State s = min_jerk(currentTime, finishTime, fixedMinJerkState->s0, fixedMinJerkState->v0, fixedMinJerkState->a0, targetPosition, fixedMinJerkState->t0);
1628 // ARMARX_INFO << deactivateSpam(0.1) << VAROUT(remainingTime) << VAROUT(signedDistance) << VAROUT(signedDistance * currentP_Phase3) << VAROUT(currentP_Phase3);// << VAROUT(s.s) << VAROUT(s.v) << VAROUT(s.a);
1629 return result;
1630 }
1631
1632 if (std::abs(signedDistance) < phase2SwitchDistance &&
1633 remainingTime < phase2SwitchMaxRemainingTime)
1634 {
1635 if (!fixedMinJerkState)
1636 {
1637 fixedMinJerkState.reset(
1639 currentP_Phase2 = 0;
1640 }
1641 // std::vector<State> states;
1642 // double t = currentTime;
1643 // while(t < finishTime)
1644 // {
1645 // State s = min_jerk(t, finishTime, fixedMinJerkState->s0, fixedMinJerkState->v0, fixedMinJerkState->a0, targetPosition, fixedMinJerkState->t0);
1646 // t += dt;
1647 // states.push_back(s);
1648 // }
1649 currentTime += dt;
1650 State s = min_jerk(currentTime,
1651 finishTime,
1656 fixedMinJerkState->t0);
1657 double newVelocity = (s.s - (currentPosition + s.v * dt)) * currentP_Phase2 + s.v;
1658 double newAcc = (newVelocity - currentV) / dt;
1659 double newJerk = (newAcc - currentAcc) / dt;
1660 double newPos = ctrlutil::s(dt,
1662 currentV,
1663 currentAcc,
1664 newJerk); //currentPosition + newVelocity * dt;
1665 // ARMARX_INFO /*<< deactivateSpam(0.1) */ << VAROUT(currentP_Phase2) << VAROUT(currentPosition) << VAROUT(signedDistance) << VAROUT(s.s) << VAROUT(s.v) << VAROUT(newVelocity) << VAROUT(newAcc) << VAROUT(newJerk) << VAROUT(s.a);
1667 Output result{newPos, newVelocity, newAcc, newJerk};
1668 return result;
1669 }
1670
1671
1672 double jerk = min_jerk_calc_jerk(
1674 double newAcc = currentAcc + jerk * dt;
1675 double newVelocity = ctrlutil::v(dt, currentV, currentAcc, jerk);
1676 double accAtEnd =
1677 ctrlutil::a(remainingTime,
1678 currentAcc,
1679 jerk); // assumes that fixed jerk would be used, which is not the case here
1680 (void)accAtEnd;
1681
1682 std::vector<State> states;
1683 std::vector<State> states2;
1684 //#define debug
1685#ifdef debug
1686 {
1687 double dt = 0.001;
1688 double t = 1;
1689 double simS = currentPosition, simV = currentV, simAcc = currentAcc;
1690 while (t > 0)
1691 {
1692 double jerk = min_jerk_calc_jerk(t, simS, simV, simAcc, targetPosition);
1693 simAcc = simAcc + jerk * dt;
1694 simV = ctrlutil::v(dt, simV, simAcc, 0);
1695 simS += dt * simV;
1696 t -= dt;
1697 states.push_back(State{t, simS, simV, simAcc, jerk});
1698 }
1699 }
1700 {
1701 double dt = 0.001;
1702
1703 double t = 1;
1704 double simS = currentPosition, simV = currentV, simAcc = currentAcc;
1705 while (t > 0)
1706 {
1707 double jerk = min_jerk_calc_jerk(t, simS, simV, simAcc, targetPosition);
1708 simS += ctrlutil::s(dt, 0, simV, simAcc, jerk);
1709 simV = ctrlutil::v(dt, simV, simAcc, jerk);
1710 simAcc = simAcc + jerk * dt;
1711 t -= dt;
1712 states2.push_back(State{t, simS, simV, simAcc, jerk});
1713 }
1714 }
1715#endif
1716 // ARMARX_INFO << /*deactivateSpam(0.1) <<*/ VAROUT(currentTime) << VAROUT(remainingTime) << VAROUT(jerk) << VAROUT(accAtEnd) << VAROUT(signedDistance) << " new acc: " << newAcc << VAROUT(currentV);
1717 currentTime += dt;
1718
1719
1720 double newPos = ctrlutil::s(dt, currentPosition, currentV, currentAcc, jerk);
1721 Output result{newPos, newVelocity, newAcc, jerk};
1722 return result;
1723 }
1724} // namespace armarx
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
Definition Logging.cpp:75
#define VAROUT(x)
constexpr T dt
std::unique_ptr< FixedMinJerkState > fixedMinJerkState
static int Sign(double value)
Definition MathUtils.h:37
static double LimitTo(double value, double absThreshold)
Definition MathUtils.h:71
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#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
#define q
WedgeBrakingData braking_distance_with_wedge(double v0, double a0, double j)
Definition CtrlUtil.h:157
double t_to_v_with_wedge_acc(double v, double a0, double j)
Definition CtrlUtil.h:64
double s(double t, double s0, double v0, double a0, double j)
Definition CtrlUtil.h:33
double a(double t, double a0, double j)
Definition CtrlUtil.h:45
std::tuple< double, double, double > calcAccAndJerk(double s0, double v0)
Definition CtrlUtil.h:147
double t_to_v(double v, double a, double j)
Definition CtrlUtil.h:51
double brakingDistance(double v0, double a0, double j)
Definition CtrlUtil.h:76
double jerk(double t, double s0, double v0, double a0)
Definition CtrlUtil.h:141
double v(double t, double v0, double a0, double j)
Definition CtrlUtil.h:39
This file offers overloads of toIce() and fromIce() functions for STL container types.
float positionThroughVelocityControlWithAccelerationAndPositionBounds(float dt, float maxDt, float currentV, float maxV, float acceleration, float deceleration, float currentPosition, float targetPosition, float p, float positionLimitLo, float positionLimitHi)
float velocityControlWithAccelerationBounds(float dt, float maxDt, const float currentV, float targetV, float maxV, float acceleration, float deceleration, float directSetVLimit)
std::array< deltas, 3 > trapeze(float v0, float acc, float vMax, float dec, float vt, float dx)
deltas accelerateToVelocity(float v0, float acc, float vt)
float positionThroughVelocityControlWithAccelerationBoundsAndPeriodicPosition(float dt, float maxDt, float currentV, float maxV, float acceleration, float deceleration, float currentPosition, float targetPosition, float pControlPosErrorLimit, float p, float &direction, float positionPeriodLo, float positionPeriodHi)
std::pair< T, T > pq(T p, T q)
T periodicClamp(T value, T periodLo, T periodHi)
T sign(T t)
Definition algorithm.h:214
float brakingDistance(float v0, float deceleration)
float velocityControlWithAccelerationAndPositionBounds(float dt, float maxDt, float currentV, float targetV, float maxV, float acceleration, float deceleration, float directSetVLimit, float currentPosition, float positionLimitLoSoft, float positionLimitHiSoft, float positionLimitLoHard, float positionLimitHiHard)
float positionThroughVelocityControlWithAccelerationBounds(float dt, float maxDt, float currentV, float maxV, float acceleration, float deceleration, float currentPosition, float targetPosition, float p)
bool isfinite(const std::vector< T, Ts... > &v)
Definition algorithm.h:366
Point sub(const Point &x, const Point &y)
Definition point.hpp:46
double distance(const Point &a, const Point &b)
Definition point.hpp:95