diff --git a/source/RobotAPI/components/units/RobotUnit/BasicControllers.cpp b/source/RobotAPI/components/units/RobotUnit/BasicControllers.cpp index bd0acc86a97481e879929c6156a50f52cab0fd24..996f653e2e0772385606c3a7fb4abaafdbd64ba3 100644 --- a/source/RobotAPI/components/units/RobotUnit/BasicControllers.cpp +++ b/source/RobotAPI/components/units/RobotUnit/BasicControllers.cpp @@ -1183,6 +1183,184 @@ namespace armarx + double jerk = min_jerk_calc_jerk(remainingTime, currentPosition, currentV, currentAcc, targetPosition); + double newAcc = currentAcc + jerk * dt; + double newVelocity = ctrlutil::v(dt, currentV, currentAcc, jerk); + double accAtEnd = ctrlutil::a(remainingTime, currentAcc, jerk); + + std::vector<State> states; + std::vector<State> states2; + //#define debug +#ifdef debug + { + double dt = 0.001; + double t = 1; + double simS = currentPosition, simV = currentV, simAcc = currentAcc; + while (t > 0) + { + double jerk = min_jerk_calc_jerk(t, simS, simV, simAcc, targetPosition); + simAcc = simAcc + jerk * dt; + simV = ctrlutil::v(dt, simV, simAcc, 0); + simS += dt * simV; + t -= dt; + states.push_back(State{t, simS, simV, simAcc, jerk}); + } + } + { + double dt = 0.001; + + double t = 1; + double simS = currentPosition, simV = currentV, simAcc = currentAcc; + while (t > 0) + { + double jerk = min_jerk_calc_jerk(t, simS, simV, simAcc, targetPosition); + simS += ctrlutil::s(dt, 0, simV, simAcc, jerk); + simV = ctrlutil::v(dt, simV, simAcc, jerk); + simAcc = simAcc + jerk * dt; + t -= dt; + states2.push_back(State{t, simS, simV, simAcc, jerk}); + } + } +#endif + ARMARX_DEBUG << VAROUT(currentTime) << VAROUT(remainingTime) << VAROUT(jerk) << VAROUT(accAtEnd) << VAROUT(signedDistance) << " delta acc: " << jerk* dt; + currentTime += dt; + + + + Output result { newVelocity, newAcc, jerk}; + return result; + + } + + void MinJerkPositionController::reset() + { + currentTime = 0; + + fixedMinJerkState.reset(); +// pid.reset(); + currentP_Phase2 = -1; + currentP_Phase3 = -1; + } + + double MinJerkPositionController::getTargetPosition() const + { + return targetPosition; + } + + void MinJerkPositionController::setTargetPosition(double newTargetPosition) + { + if (std::abs(targetPosition - newTargetPosition) > 0.0001) + { + reset(); + double distance = newTargetPosition - currentPosition; + + double decelerationTime = std::abs(currentV / desiredDeceleration); + // calculate the time it should take to reach the goal (ToDo: find exact time) + if (math::MathUtils::Sign(currentV) == math::MathUtils::Sign(distance) + && std::abs(currentV) > 0.0 + && ctrlutil::s(decelerationTime, 0, std::abs(currentV), desiredDeceleration, 0) > distance) + // && ctrlutil::brakingDistance(currentV, currentAcc, desiredJerk) < distance) + { + finishTime = decelerationTime; + } + else + { + double accelerationTime = std::abs((math::MathUtils::Sign(distance)*maxV-currentV) / desiredDeceleration); + double decelerationTime = std::abs(maxV / desiredDeceleration); + finishTime = std::max(decelerationTime+accelerationTime, std::abs(distance / (maxV*0.75))); + } + targetPosition = newTargetPosition; + ARMARX_INFO << "New finish time: " << finishTime; + } + + + } + + MinJerkPositionController::Output MinJerkPositionController::run() + { + auto min_jerk_calc_jerk = [&](double tf, double s0, double v0, double a0, double xf = 0, double t0 = 0.0) + { + double D = tf - t0; + return 60.0 / (D * D * D) * (xf - s0) - 36.0 / (D * D) * v0 - 9.0 / D * a0; + }; + + + auto min_jerk = [&](double t, double tf, double s0, double v0, double a0, double xf = 0, double t0 = 0.0) + { + double D = tf - t0; + BOOST_ASSERT(D != 0.0); + double D2 = D * D; + double tau = (t - t0) / D; + double b0 = s0; + double b1 = D * v0; + double b2 = D2 * a0 / 2; + + double b3 = (-3 * D2) / 2 * a0 - 6 * D * v0 + 10 * (xf - s0); + double b4 = (3 * D2) / 2 * a0 + 8 * D * v0 - 15 * (xf - s0); + double b5 = (-D2) / 2 * a0 - 3 * D * v0 + 6 * (xf - s0); + + double tau2 = tau * tau; + double tau3 = tau2 * tau; + double tau4 = tau3 * tau; + double tau5 = tau4 * tau; + double st = b0 + b1 * tau + b2 * tau2 + b3 * tau3 + b4 * tau4 + b5 * tau5; + double vt = b1 / D + 2*b2 / D * tau + 3*b3 / D * tau2 + 4*b4 / D * tau3 + 5*b5 / D * tau4; + double at = 2*b2 / D2 + 6*b3 / D2 * tau + 12*b4 / D2 * tau2 + 20*b5 / D2 * tau3; + return State{t, st, vt, at}; + }; + + double remainingTime = finishTime - currentTime; + double signedDistance = targetPosition - currentPosition; + if (remainingTime <= 0.0) + { +// if(!pid) +// { +// double Kd = (currentV - distance * p) /(-currentV); +// ARMARX_INFO << VAROUT(Kd); +// pid.reset(new PIDController(1, 0, Kd)); +// } + if(currentP_Phase3 < 0) + { + currentP_Phase3 = std::abs(currentV / signedDistance); + ARMARX_DEBUG << "optimal P: " << currentP_Phase3; + } + + + currentP_Phase3 = currentP_Phase3 * p_adjust_ratio + p * (1.0-p_adjust_ratio); + Output result {signedDistance * currentP_Phase3, 0, 0}; + currentTime += dt; +// State s = min_jerk(currentTime, finishTime, fixedMinJerkState->s0, fixedMinJerkState->v0, fixedMinJerkState->a0, targetPosition, fixedMinJerkState->t0); + ARMARX_DEBUG << VAROUT(remainingTime) << VAROUT(signedDistance) << VAROUT(signedDistance * currentP_Phase3) << VAROUT(currentP_Phase3);// << VAROUT(s.s) << VAROUT(s.v) << VAROUT(s.a); + return result; + } + + if(std::abs(signedDistance) < phase2SwitchDistance && remainingTime < phase2SwitchMaxRemainingTime) + { + if(!fixedMinJerkState) + { + fixedMinJerkState.reset(new FixedMinJerkState{currentTime, currentPosition, currentV, currentAcc}); + currentP_Phase2 = 0; + } +// std::vector<State> states; +// double t = currentTime; +// while(t < finishTime) +// { +// State s = min_jerk(t, finishTime, fixedMinJerkState->s0, fixedMinJerkState->v0, fixedMinJerkState->a0, targetPosition, fixedMinJerkState->t0); +// t += dt; +// states.push_back(s); +// } + currentTime += dt; + State s = min_jerk(currentTime, finishTime, fixedMinJerkState->s0, fixedMinJerkState->v0, fixedMinJerkState->a0, targetPosition, fixedMinJerkState->t0); + currentP_Phase2 = currentP_Phase2 * p_adjust_ratio + p * (1.0-p_adjust_ratio); + double newVelocity = (s.s - currentPosition) * currentP_Phase2 + s.v; + ARMARX_DEBUG << VAROUT(s.s) << VAROUT(s.v) << VAROUT(newVelocity); + Output result { newVelocity, 0, 0}; + return result; + } + + + + double jerk = min_jerk_calc_jerk(remainingTime, currentPosition, currentV, currentAcc, targetPosition); double newAcc = currentAcc + jerk * dt; double newVelocity = ctrlutil::v(dt, currentV, currentAcc, jerk);