35 const Eigen::Vector3d e_z = {0., 0., 1.};
61 inline Eigen::Vector2d vecFromError(
const Eigen::Vector3d & error)
63 double x = -std::round(error.x() * 1000.);
64 double y = -std::round(error.y() * 1000.);
65 return Eigen::Vector2d{x, y};
71 : dcmIntegrator_(dt, 5.), dcmDerivator_(dt, 1.), pendulum_(pendulum),
72 controlRobot_(controlRobot), dt_(dt), mass_(controlRobot.mass())
78 logger.addLogEntry(
"stabilizer_contactState", [
this]() ->
double {
91 logger.addLogEntry(
"error_dcm_average", [
this]() {
return dcmAverageError_; });
92 logger.addLogEntry(
"error_dcm_pos", [
this]() {
return dcmError_; });
93 logger.addLogEntry(
"error_dcm_vel", [
this]() {
return dcmVelError_; });
94 logger.addLogEntry(
"error_dfz_force", [
this]() {
return dfzForceError_; });
95 logger.addLogEntry(
"error_dfz_height", [
this]() {
return dfzHeightError_; });
96 logger.addLogEntry(
"error_vdc", [
this]() {
return vdcHeightError_; });
97 logger.addLogEntry(
"error_zmp", [
this]() {
return zmpError_; });
98 logger.addLogEntry(
"perf_Stabilizer", [
this]() {
return runTime_; });
99 logger.addLogEntry(
"stabilizer_admittance_com", [
this]() {
return comAdmittance_; });
100 logger.addLogEntry(
"stabilizer_admittance_cop", [
this]() {
return copAdmittance_; });
101 logger.addLogEntry(
"stabilizer_admittance_dfz", [
this]() {
return dfzAdmittance_; });
102 logger.addLogEntry(
"stabilizer_dcmDerivator", [
this]() {
return dcmDerivator_.
eval(); });
103 logger.addLogEntry(
"stabilizer_dcmDerivator_raw", [
this]() {
return dcmDerivator_.
raw(); });
104 logger.addLogEntry(
"stabilizer_dcmDerivator_timeConstant", [
this]() {
return dcmDerivator_.
timeConstant(); });
105 logger.addLogEntry(
"stabilizer_dcmGains_derivative", [
this]() {
return dcmDerivGain_; });
106 logger.addLogEntry(
"stabilizer_dcmGains_integral", [
this]() {
return dcmIntegralGain_; });
107 logger.addLogEntry(
"stabilizer_dcmGains_proportional", [
this]() {
return dcmPropGain_; });
108 logger.addLogEntry(
"stabilizer_dcmIntegrator", [
this]() {
return dcmIntegrator_.
eval(); });
109 logger.addLogEntry(
"stabilizer_dcmIntegrator_timeConstant", [
this]() {
return dcmIntegrator_.
timeConstant(); });
110 logger.addLogEntry(
"stabilizer_dfz_damping", [
this]() {
return dfzDamping_; });
111 logger.addLogEntry(
"stabilizer_fdqp_weights_ankleTorque",
112 [
this]() {
return std::pow(fdqpWeights_.ankleTorqueSqrt, 2); });
113 logger.addLogEntry(
"stabilizer_fdqp_weights_forceRatio",
114 [
this]() {
return std::pow(fdqpWeights_.forceRatioSqrt, 2); });
115 logger.addLogEntry(
"stabilizer_fdqp_weights_netWrench", [
this]() {
return std::pow(fdqpWeights_.netWrenchSqrt, 2); });
116 logger.addLogEntry(
"stabilizer_vdc_frequency", [
this]() {
return vdcFrequency_; });
117 logger.addLogEntry(
"stabilizer_vdc_stiffness", [
this]() {
return vdcStiffness_; });
118 logger.addLogEntry(
"stabilizer_wrench", [
this]() {
return distribWrench_; });
119 logger.addLogEntry(
"stabilizer_zmp", [
this]() {
return zmp(); });
120 logger.addLogEntry(
"stabilizer_zmpcc_comAccel", [
this]() {
return zmpccCoMAccel_; });
121 logger.addLogEntry(
"stabilizer_zmpcc_comOffset", [
this]() {
return zmpccCoMOffset_; });
122 logger.addLogEntry(
"stabilizer_zmpcc_comVel", [
this]() {
return zmpccCoMVel_; });
123 logger.addLogEntry(
"stabilizer_zmpcc_error", [
this]() {
return zmpccError_; });
124 logger.addLogEntry(
"stabilizer_zmpcc_leakRate", [
this]() {
return zmpccIntegrator_.
rate(); });
129 using namespace mc_rtc::gui;
130 gui->addElement({
"Stabilizer",
"Main"}, Button(
"Disable stabilizer", [
this]() {
disable(); }),
131 Button(
"Reconfigure", [
this]() {
reconfigure(); }),
132 Button(
"Reset DCM integrator", [
this]() { dcmIntegrator_.setZero(); }),
133 ArrayInput(
"Foot admittance", {
"CoPx",
"CoPy"},
134 [
this]() -> Eigen::Vector2d {
135 return {copAdmittance_.x(), copAdmittance_.y()};
137 [
this](
const Eigen::Vector2d & a) {
141 ArrayInput(
"Foot force difference", {
"Admittance",
"Damping"},
142 [
this]() -> Eigen::Vector2d {
143 return {dfzAdmittance_, dfzDamping_};
145 [
this](
const Eigen::Vector2d & a) {
149 ArrayInput(
"DCM gains", {
"Prop.",
"Integral",
"Deriv."},
150 [
this]() -> Eigen::Vector3d {
151 return {dcmPropGain_, dcmIntegralGain_, dcmDerivGain_};
153 [
this](
const Eigen::Vector3d & gains) {
158 ArrayInput(
"DCM filters", {
"Integrator T [s]",
"Derivator T [s]"},
159 [
this]() -> Eigen::Vector2d {
160 return {dcmIntegrator_.timeConstant(), dcmDerivator_.timeConstant()};
162 [
this](
const Eigen::Vector2d & T) {
163 dcmIntegrator_.timeConstant(T(0));
164 dcmDerivator_.timeConstant(T(1));
166 gui->addElement({
"Stabilizer",
"Advanced"}, Button(
"Disable stabilizer", [
this]() {
disable(); }),
167 Button(
"Reconfigure", [
this]() {
reconfigure(); }),
168 Button(
"Reset CoM integrator", [
this]() { zmpccIntegrator_.setZero(); }),
169 Checkbox(
"Apply CoM admittance only in double support?", [
this]() {
return zmpccOnlyDS_; },
170 [
this]() { zmpccOnlyDS_ = !zmpccOnlyDS_; }),
171 ArrayInput(
"CoM admittance", {
"Ax",
"Ay"}, [
this]() {
return comAdmittance_; },
172 [
this](
const Eigen::Vector2d & a) {
176 NumberInput(
"CoM integrator leak rate [Hz]", [
this]() {
return zmpccIntegrator_.rate(); },
177 [
this](
double T) { zmpccIntegrator_.rate(T); }),
178 ArrayInput(
"DCM pole placement", {
"Pole1",
"Pole2",
"Pole3",
"Lag [Hz]"},
179 [
this]() -> Eigen::VectorXd {
return polePlacement_; },
180 [
this](
const Eigen::VectorXd & polePlacement) {
181 double alpha =
clamp(polePlacement(0), -20., -0.1);
182 double beta =
clamp(polePlacement(1), -20., -0.1);
183 double gamma =
clamp(polePlacement(2), -20., -0.1);
184 double lagFreq =
clamp(polePlacement(3), 1., 200.);
185 polePlacement_ = {alpha, beta, gamma, lagFreq};
187 double omega = pendulum_.omega();
188 double denom = pendulum_.omega() * lagFreq;
189 double T_integ = dcmIntegrator_.timeConstant();
193 (alpha * beta + beta * gamma + gamma * alpha + omega * lagFreq) / denom;
194 double zmpIntegralGain = -(alpha * beta * gamma) / denom;
195 double zmpDerivGain = -(alpha + beta + gamma + lagFreq - omega) / denom;
198 dcmPropGain_ = omega * (zmpPropGain - 1.);
199 dcmIntegralGain_ = omega * T_integ * zmpIntegralGain;
200 dcmDerivGain_ = omega * zmpDerivGain;
202 ArrayInput(
"Vertical drift compensation", {
"frequency",
"stiffness"},
203 [
this]() -> Eigen::Vector2d {
204 return {vdcFrequency_, vdcStiffness_};
206 [
this](
const Eigen::Vector2d & v) {
207 vdcFrequency_ =
clamp(v(0), 0., 10.);
208 vdcStiffness_ =
clamp(v(1), 0., 1e4);
210 ArrayInput(
"Wrench distribution weights", {
"Net wrench",
"Ankle torques",
"Force ratio"},
211 [
this]() -> Eigen::Vector3d {
212 double netWrench = std::pow(fdqpWeights_.netWrenchSqrt, 2);
213 double ankleTorque = std::pow(fdqpWeights_.ankleTorqueSqrt, 2);
214 double forceRatio = std::pow(fdqpWeights_.forceRatioSqrt, 2);
215 return {netWrench, ankleTorque, forceRatio};
217 [
this](
const Eigen::Vector3d & weights) {
218 fdqpWeights_.netWrenchSqrt = std::sqrt(weights(0));
219 fdqpWeights_.ankleTorqueSqrt = std::sqrt(weights(1));
220 fdqpWeights_.forceRatioSqrt = std::sqrt(weights(2));
222 gui->addElement({
"Stabilizer",
"Errors"}, Button(
"Disable stabilizer", [
this]() {
disable(); }),
223 Button(
"Reconfigure", [
this]() {
reconfigure(); }),
224 ArrayLabel(
"CoM offset [mm]", {
"x",
"y"}, [
this]() {
return vecFromError(zmpccCoMOffset_); }),
225 ArrayLabel(
"DCM average error [mm]", {
"x",
"y"}, [
this]() {
return vecFromError(dcmAverageError_); }),
226 ArrayLabel(
"DCM error [mm]", {
"x",
"y"}, [
this]() {
return vecFromError(dcmError_); }),
227 ArrayLabel(
"Foot force difference error", {
"force [N]",
"height [mm]"}, [
this]() {
228 Eigen::Vector3d dfzError = {dfzForceError_ / 1000., dfzHeightError_, 0.};
229 return vecFromError(dfzError);
235 comAdmittance_.setZero();
236 copAdmittance_.setZero();
238 dcmIntegralGain_ = 0.;
253 fdqpWeights_.configure(config_(
"fdqp_weights"));
254 if(config_.has(
"admittance"))
256 auto admittance = config_(
"admittance");
257 comAdmittance_ = admittance(
"com");
258 copAdmittance_ = admittance(
"cop");
259 dfzAdmittance_ = admittance(
"dfz");
260 dfzDamping_ = admittance(
"dfz_damping");
262 if(config_.has(
"dcm_tracking"))
264 auto dcmTracking = config_(
"dcm_tracking");
265 dcmPropGain_ = dcmTracking(
"gains")(
"prop");
266 dcmIntegralGain_ = dcmTracking(
"gains")(
"integral");
267 dcmDerivGain_ = dcmTracking(
"gains")(
"deriv");
268 dcmDerivator_.timeConstant(dcmTracking(
"derivator_time_constant"));
269 dcmIntegrator_.timeConstant(dcmTracking(
"integrator_time_constant"));
271 if(config_.has(
"tasks"))
273 auto tasks = config_(
"tasks");
276 tasks(
"com")(
"active_joints", comActiveJoints_);
277 tasks(
"com")(
"stiffness", comStiffness_);
278 tasks(
"com")(
"weight", comWeight_);
280 if(tasks.has(
"contact"))
282 double d = tasks(
"contact")(
"damping");
283 double k = tasks(
"contact")(
"stiffness");
284 contactDamping_ = sva::MotionVecd({d, d, d}, {d, d, d});
285 contactStiffness_ = sva::MotionVecd({k, k, k}, {k, k, k});
286 tasks(
"contact")(
"stiffness", contactStiffness_);
287 tasks(
"contact")(
"weight", contactWeight_);
289 if(tasks.has(
"swing_foot"))
291 tasks(
"swing_foot")(
"stiffness", swingFootStiffness_);
292 tasks(
"swing_foot")(
"weight", swingFootWeight_);
295 if(config_.has(
"vdc"))
297 auto vdc = config_(
"vdc");
298 vdcFrequency_ = vdc(
"frequency");
299 vdcStiffness_ = vdc(
"stiffness");
301 if(config_.has(
"zmpcc"))
303 auto zmpcc = config_(
"zmpcc");
304 zmpccIntegrator_.rate(zmpcc(
"integrator_leak_rate"));
310 unsigned robotIndex = robots.robotIndex();
312 comTask.reset(
new mc_tasks::CoMTask(robots, robotIndex));
313 comTask->selectActiveJoints(comActiveJoints_);
314 comTask->setGains(comStiffness_, 2 * comStiffness_.cwiseSqrt());
317 leftFootTask.reset(
new mc_tasks::force::CoPTask(
"LeftFootCenter", robots, robotIndex));
318 rightFootTask.reset(
new mc_tasks::force::CoPTask(
"RightFootCenter", robots, robotIndex));
324 dcmDerivator_.setZero();
326 dcmIntegrator_.setZero();
328 zmpccIntegrator_.setZero();
332 dcmAverageError_ = Eigen::Vector3d::Zero();
333 dcmError_ = Eigen::Vector3d::Zero();
334 dcmVelError_ = Eigen::Vector3d::Zero();
336 dfzHeightError_ = 0.;
337 distribWrench_ = {pendulum_.com().cross(staticForce), staticForce};
338 vdcHeightError_ = 0.;
339 zmpError_ = Eigen::Vector3d::Zero();
340 zmpccCoMAccel_ = Eigen::Vector3d::Zero();
341 zmpccCoMOffset_ = Eigen::Vector3d::Zero();
342 zmpccCoMVel_ = Eigen::Vector3d::Zero();
343 zmpccError_ = Eigen::Vector3d::Zero();
346 void Stabilizer::checkGains()
375 footTask->admittance(contactAdmittance());
376 footTask->setGains(contactStiffness_, contactDamping_);
377 footTask->targetPose(contact.
pose);
378 footTask->weight(contactWeight_);
379 if(footTask->surface() ==
"LeftFootCenter")
383 else if(footTask->surface() ==
"RightFootCenter")
389 LOG_ERROR(
"Unknown foot surface: " << footTask->surface());
396 footTask->stiffness(swingFootStiffness_);
397 footTask->weight(swingFootWeight_);
402 const sva::PTransformd X_0_s = footTask->surfacePose();
403 const sva::PTransformd & X_0_c = contact.
pose;
404 sva::PTransformd X_c_s = X_0_s * X_0_c.inv();
405 double xDist = std::abs(X_c_s.translation().x());
406 double yDist = std::abs(X_c_s.translation().y());
407 double zDist = std::abs(X_c_s.translation().z());
408 double Fz = footTask->measuredWrench().force().z();
409 return (xDist < 0.03 && yDist < 0.03 && zDist < 0.03 && Fz > 50.);
414 constexpr
double MAX_VEL = 0.01;
415 constexpr
double TOUCHDOWN_FORCE = 50.;
416 constexpr
double DESIRED_AFZ = MAX_VEL / TOUCHDOWN_FORCE;
417 if(footTask->measuredWrench().force().z() < TOUCHDOWN_FORCE)
419 auto a = footTask->admittance();
420 double AFz =
clamp(DESIRED_AFZ, 0., 1e-2,
"Contact seeking admittance");
421 footTask->admittance({a.couple(), {a.force().x(), a.force().y(), AFz}});
422 footTask->targetForce({0., 0., TOUCHDOWN_FORCE});
426 void Stabilizer::setSupportFootGains()
428 sva::MotionVecd vdcContactStiffness = {contactStiffness_.angular(), {vdcStiffness_, vdcStiffness_, vdcStiffness_}};
429 switch(contactState_)
433 leftFootTask->setGains(contactStiffness_, contactDamping_);
439 leftFootTask->setGains(vdcContactStiffness, contactDamping_);
443 rightFootTask->setGains(vdcContactStiffness, contactDamping_);
448 void Stabilizer::checkInTheAir()
450 double LFz =
leftFootTask->measuredWrench().force().z();
455 void Stabilizer::updateZMPFrame()
459 switch(contactState_)
462 zmpFrame_ = sva::interpolate(X_0_lc, X_0_rc, 0.5);
476 Eigen::Vector3d n = zmpFrame_.rotation().row(2);
477 Eigen::Vector3d p = zmpFrame_.translation();
478 const Eigen::Vector3d & force = wrench.force();
479 double normalForce = n.dot(force);
482 double lambda = std::pow(pendulum_.omega(), 2);
485 const Eigen::Vector3d & moment_0 = wrench.couple();
486 Eigen::Vector3d moment_p = moment_0 - p.cross(force);
487 return p + n.cross(moment_p) / normalForce;
492 auto startTime = std::chrono::high_resolution_clock::now();
495 setSupportFootGains();
497 auto desiredWrench = computeDesiredWrench();
498 switch(contactState_)
501 distributeWrench(desiredWrench);
512 updateCoMTaskZMPCC();
513 updateFootForceDifferenceControl();
514 auto endTime = std::chrono::high_resolution_clock::now();
515 runTime_ = std::chrono::duration<double, std::milli>(endTime - startTime).count();
519 const Eigen::Vector3d & comd,
520 const sva::ForceVecd & wrench,
521 double leftFootRatio)
523 leftFootRatio_ = leftFootRatio;
525 measuredCoMd_ = comd;
526 measuredWrench_ = wrench;
529 sva::ForceVecd Stabilizer::computeDesiredWrench()
531 double omega = pendulum_.omega();
532 Eigen::Vector3d comError = pendulum_.com() - measuredCoM_;
533 Eigen::Vector3d comdError = pendulum_.comd() - measuredCoMd_;
534 dcmError_ = comError + comdError / omega;
539 dcmDerivator_.setZero();
540 dcmIntegrator_.append(Eigen::Vector3d::Zero());
544 zmpError_ = pendulum_.zmp() - measuredZMP_;
546 dcmDerivator_.update(omega * (dcmError_ - zmpError_));
547 dcmIntegrator_.append(dcmError_);
549 dcmAverageError_ = dcmIntegrator_.eval();
550 dcmVelError_ = dcmDerivator_.eval();
552 Eigen::Vector3d desiredCoMAccel = pendulum_.comdd();
553 desiredCoMAccel += omega * (dcmPropGain_ * dcmError_ + comdError);
554 desiredCoMAccel += omega * dcmIntegralGain_ * dcmAverageError_;
555 desiredCoMAccel += omega * dcmDerivGain_ * dcmVelError_;
562 return {measuredCoM_.cross(desiredForce), desiredForce};
565 void Stabilizer::distributeWrench(
const sva::ForceVecd & desiredWrench)
593 constexpr
unsigned NB_VAR = 6 + 6;
594 constexpr
unsigned COST_DIM = 6 + NB_VAR + 1;
597 A.setZero(COST_DIM, NB_VAR);
601 auto A_net = A.block<6, 12>(0, 0);
602 auto b_net = b.segment<6>(0);
603 A_net.block<6, 6>(0, 0) = Eigen::Matrix6d::Identity();
604 A_net.block<6, 6>(0, 6) = Eigen::Matrix6d::Identity();
605 b_net = desiredWrench.vector();
608 auto A_lankle = A.block<6, 6>(6, 0);
609 auto A_rankle = A.block<6, 6>(12, 6);
611 A_lankle.diagonal() << 1., 1., 1e-4, 1e-3, 1e-3, 1e-4;
612 A_rankle.diagonal() << 1., 1., 1e-4, 1e-3, 1e-3, 1e-4;
613 A_lankle *= X_0_lankle.dualMatrix();
614 A_rankle *= X_0_rankle.dualMatrix();
617 double lfr = leftFootRatio_;
618 auto A_fratio = A.block<1, 12>(18, 0);
619 A_fratio.block<1, 6>(0, 0) = (1 - lfr) * X_0_lc.dualMatrix().bottomRows<1>();
620 A_fratio.block<1, 6>(0, 6) = -lfr * X_0_rc.dualMatrix().bottomRows<1>();
623 A_net *= fdqpWeights_.netWrenchSqrt;
624 b_net *= fdqpWeights_.netWrenchSqrt;
625 A_lankle *= fdqpWeights_.ankleTorqueSqrt;
626 A_rankle *= fdqpWeights_.ankleTorqueSqrt;
629 A_fratio *= fdqpWeights_.forceRatioSqrt;
632 Eigen::MatrixXd Q = A.transpose() * A;
633 Eigen::VectorXd c = -A.transpose() * b;
635 constexpr
unsigned NB_CONS = 16 + 16 + 2;
636 Eigen::Matrix<double, NB_CONS, NB_VAR> A_ineq;
637 Eigen::VectorXd b_ineq;
638 A_ineq.setZero(NB_CONS, NB_VAR);
639 b_ineq.setZero(NB_CONS);
641 A_ineq.block<16, 6>(0, 0) = wrenchFaceMatrix_ * X_0_lc.dualMatrix();
644 A_ineq.block<16, 6>(16, 6) = wrenchFaceMatrix_ * X_0_rc.dualMatrix();
647 A_ineq.block<1, 6>(32, 0) = -X_0_lc.dualMatrix().bottomRows<1>();
650 A_ineq.block<1, 6>(33, 6) = -X_0_rc.dualMatrix().bottomRows<1>();
653 qpSolver_.problem(NB_VAR, 0, NB_CONS);
654 Eigen::MatrixXd A_eq(0, 0);
655 Eigen::VectorXd b_eq;
658 bool solutionFound = qpSolver_.solve(Q, c, A_eq, b_eq, A_ineq, b_ineq,
false);
661 LOG_ERROR(
"DS force distribution QP: solver found no solution");
665 Eigen::VectorXd x = qpSolver_.result();
666 sva::ForceVecd w_l_0(x.segment<3>(0), x.segment<3>(3));
667 sva::ForceVecd w_r_0(x.segment<3>(6), x.segment<3>(9));
668 distribWrench_ = w_l_0 + w_r_0;
670 sva::ForceVecd w_l_lc = X_0_lc.dualMul(w_l_0);
671 sva::ForceVecd w_r_rc = X_0_rc.dualMul(w_r_0);
672 Eigen::Vector2d leftCoP = (e_z.cross(w_l_lc.couple()) / w_l_lc.force()(2)).head<2>();
673 Eigen::Vector2d rightCoP = (e_z.cross(w_r_rc.couple()) / w_r_rc.force()(2)).head<2>();
680 void Stabilizer::saturateWrench(
const sva::ForceVecd & desiredWrench,
681 std::shared_ptr<mc_tasks::force::CoPTask> & footTask)
683 constexpr
unsigned NB_CONS = 16;
684 constexpr
unsigned NB_VAR = 6;
699 const sva::PTransformd & X_0_c = footTask->targetPose();
701 Eigen::Matrix6d Q = Eigen::Matrix6d::Identity();
702 Eigen::Vector6d c = -desiredWrench.vector();
704 Eigen::MatrixXd A_ineq = wrenchFaceMatrix_ * X_0_c.dualMatrix();
705 Eigen::VectorXd b_ineq;
706 b_ineq.setZero(NB_CONS);
708 qpSolver_.problem(NB_VAR, 0, NB_CONS);
709 Eigen::MatrixXd A_eq(0, 0);
710 Eigen::VectorXd b_eq;
713 bool solutionFound = qpSolver_.solve(Q, c, A_eq, b_eq, A_ineq, b_ineq,
true);
716 LOG_ERROR(
"SS force distribution QP: solver found no solution");
720 Eigen::VectorXd x = qpSolver_.result();
721 sva::ForceVecd w_0(x.head<3>(), x.tail<3>());
722 sva::ForceVecd w_c = X_0_c.dualMul(w_0);
723 Eigen::Vector2d cop = (e_z.cross(w_c.couple()) / w_c.force()(2)).head<2>();
724 footTask->targetCoP(cop);
725 footTask->targetForce(w_c.force());
726 distribWrench_ = w_0;
729 void Stabilizer::updateCoMTaskZMPCC()
733 zmpccCoMAccel_.setZero();
734 zmpccCoMVel_.setZero();
735 zmpccIntegrator_.add(Eigen::Vector3d::Zero(), dt_);
740 zmpccError_ = distribZMP - measuredZMP_;
741 const Eigen::Matrix3d & R_0_c = zmpFrame_.rotation();
742 const Eigen::Transpose<const Eigen::Matrix3d> R_c_0 = R_0_c.transpose();
743 Eigen::Vector3d comAdmittance = {comAdmittance_.x(), comAdmittance_.y(), 0.};
744 Eigen::Vector3d newVel = -R_c_0 * comAdmittance.cwiseProduct(R_0_c * zmpccError_);
745 Eigen::Vector3d newAccel = (newVel - zmpccCoMVel_) / dt_;
746 zmpccIntegrator_.add(newVel, dt_);
747 zmpccCoMAccel_ = newAccel;
748 zmpccCoMVel_ = newVel;
750 zmpccCoMOffset_ = zmpccIntegrator_.eval();
751 comTask->com(pendulum_.com() + zmpccCoMOffset_);
752 comTask->refVel(pendulum_.comd() + zmpccCoMVel_);
753 comTask->refAccel(pendulum_.comdd() + zmpccCoMAccel_);
756 void Stabilizer::updateFootForceDifferenceControl()
761 dfzHeightError_ = 0.;
762 vdcHeightError_ = 0.;
768 double LFz_d =
leftFootTask->targetWrench().force().z();
770 double LFz =
leftFootTask->measuredWrench().force().z();
772 dfzForceError_ = (LFz_d - RFz_d) - (LFz - RFz);
774 double LTz_d =
leftFootTask->targetPose().translation().z();
775 double RTz_d =
rightFootTask->targetPose().translation().z();
776 double LTz =
leftFootTask->surfacePose().translation().z();
778 dfzHeightError_ = (LTz_d - RTz_d) - (LTz - RTz);
779 vdcHeightError_ = (LTz_d + RTz_d) - (LTz + RTz);
784 double dz_ctrl = dfzAdmittance_ * dfzForceError_ - dfzDamping_ * dfzHeightError_;
785 double dz_vdc = vdcFrequency_ * vdcHeightError_;
786 sva::MotionVecd velF = {{0., 0., 0.}, {0., 0., dz_ctrl}};
787 sva::MotionVecd velT = {{0., 0., 0.}, {0., 0., dz_vdc}};
static constexpr double MAX_DFZ_DAMPING
Maximum normalized damping in [Hz] for foot force difference control.
Contact rightFootContact
Current right foot contact.
double clamp(double v, double vMin, double vMax)
Clamp a value in a given interval.
static constexpr double MAX_DCM_I_GAIN
Maximum DCM average integral gain in [Hz].
Stabilizer(const mc_rbdyn::Robot &robot, const Pendulum &pendulum, double dt)
Initialize stabilizer.
double timeConstant() const
Get time constant of the filter.
void disable()
Disable all feedback components.
static constexpr double MIN_DSP_FZ
Minimum normal contact force in [N] for DSP, used to avoid low-force targets when close to contact sw...
void seekTouchdown(std::shared_ptr< mc_tasks::force::CoPTask > footTask)
Configure foot task for contact seeking.
void addLogEntries(mc_rtc::Logger &logger)
Log stabilizer entries.
static constexpr double MAX_FDC_RZ_VEL
Maximum z-axis angular velocity in [rad] / [s] for foot damping control.
const Eigen::Vector3d & raw() const
Get raw value of input signal.
const Eigen::Vector3d & eval() const
Evaluate the smoothed statistic.
void addTasks(mc_solver::QPSolver &solver)
Add tasks to QP solver.
void reconfigure()
Apply stored configuration.
State of the inverted pendulum model.
Contact leftFootContact
Current left foot contact.
static constexpr double MAX_FDC_RX_VEL
Maximum x-axis angular velocity in [rad] / [s] for foot damping control.
void run()
Update QP task targets.
double rate() const
Get leak rate.
static EIGEN_MAKE_ALIGNED_OPERATOR_NEW constexpr double MAX_AVERAGE_DCM_ERROR
Maximum average (integral) DCM error in [m].
void reset(const mc_rbdyn::Robots &robots)
Reset CoM and foot CoP tasks.
bool detectTouchdown(const std::shared_ptr< mc_tasks::force::CoPTask > footTask, const Contact &contact)
Detect foot touchdown based on both force and distance.
Eigen::Vector3d computeZMP(const sva::ForceVecd &wrench) const
Compute ZMP of a wrench in the output frame.
static constexpr double MAX_DFZ_ADMITTANCE
Maximum admittance in [s] / [kg] for foot force difference control.
static constexpr double MAX_ZMPCC_COM_OFFSET
Maximum CoM offset due to admittance control in [m].
static constexpr double MAX_DCM_D_GAIN
Maximum DCM derivative gain (no unit)
static constexpr double MAX_FDC_RY_VEL
Maximum y-axis angular velocity in [rad] / [s] for foot damping control.
std::shared_ptr< mc_tasks::CoMTask > comTask
CoM position task.
void addGUIElements(std::shared_ptr< mc_rtc::gui::StateBuilder > gui)
Add GUI panel.
std::shared_ptr< mc_tasks::force::CoPTask > leftFootTask
Left foot hybrid position/force control task.
static constexpr double MAX_COM_ADMITTANCE
Maximum admittance for CoM admittance control.
std::shared_ptr< mc_tasks::force::CoPTask > rightFootTask
Right foot hybrid position/force control task.
static constexpr double MAX_COP_ADMITTANCE
Maximum CoP admittance for foot damping control.
void clampInPlace(double &v, double vMin, double vMax)
Clamp a value in a given interval.
const Eigen::Vector3d gravity
Eigen::Vector3d zmp() const
ZMP target after wrench distribution.
void setContact(std::shared_ptr< mc_tasks::force::CoPTask > footTask, const Contact &contact)
Configure foot task for contact at a given location.
const Eigen::Vector3d & eval() const
Get output value where the stationary offset has been filtered.
void updateState(const Eigen::Vector3d &com, const Eigen::Vector3d &comd, const sva::ForceVecd &wrench, double leftFootRatio)
Update real-robot state.
Main controller namespace.
void removeTasks(mc_solver::QPSolver &solver)
Remove tasks from QP solver.
void setSwingFoot(std::shared_ptr< mc_tasks::force::CoPTask > footTask)
Configure foot task for swinging.
double timeConstant() const
Get time constant of the filter.
static constexpr double MAX_DCM_P_GAIN
Maximum DCM proportional gain in [Hz].
void configure(const mc_rtc::Configuration &)
Read configuration from dictionary.