30 #include <mc_rtc/constants.h>
32 #include <ExternalFootstepPlanner/Plan.h>
33 #include <ExternalFootstepPlanner/Request.h>
41 constexpr
double COM_STIFFNESS = 5.;
46 config(
"autoplay", autoplay_);
47 config(
"autoplay_plans", autoplay_plans_);
52 auto & ctl = controller();
53 ctl.startWalking = autoplay_;
58 double lambda = mc_rtc::constants::GRAVITY / ctl.robot().com().z();
59 ctl.pendulum().reset(lambda, ctl.robot().com(), ctl.robot().comVelocity(), ctl.robot().comAcceleration());
61 supportContact_ = ctl.supportContact();
62 targetContact_ = ctl.targetContact();
64 leftFootRatio_ = ctl.leftFootRatio();
65 ctl.isWalking =
false;
66 if(supportContact_.surfaceName ==
"RightFootCenter")
68 leftFootContact_ = targetContact_;
69 rightFootContact_ = supportContact_;
71 else if(supportContact_.surfaceName ==
"LeftFootCenter")
73 leftFootContact_ = supportContact_;
74 rightFootContact_ = targetContact_;
78 mc_rtc::log::error_and_throw<std::invalid_argument>(
"Unknown surface name: {}", supportContact_.surfaceName);
85 if(ctl.plan.name ==
"external")
87 ctl.plan.resetContacts(ctl.planInterpolator.getPlan(
"external").contacts());
89 ctl.loadFootstepPlan(ctl.plan.name);
92 ctl.setContacts({{ContactState::Left, leftFootContact_.pose}, {ContactState::Right, rightFootContact_.pose}});
96 ctl.updatePlan(ctl.plan.name);
100 mc_rtc::log::info(
"[Standing] Walking is paused");
102 updateTarget(leftFootRatio_);
104 logger().addLogEntry(
"walking_phase", []() {
return 3.; });
105 ctl.stopLogSegment();
107 if(ctl.startWalking && !ctl.pauseWalking)
109 auto plans = std::vector<std::string>{};
110 if(autoplay_plans_.size())
112 plans = autoplay_plans_;
116 plans = ctl.config()(
"autoplay_plans", std::vector<std::string>{});
118 if(plans.size() == 0)
120 ctl.startWalking =
false;
121 ctl.config().add(
"autoplay",
false);
125 std::string plan = plans[0];
126 plans.erase(plans.begin());
127 ctl.config().add(
"autoplay_plans", plans);
128 ctl.updatePlan(plan);
135 auto & gui_ = *gui();
136 gui_.removeElement({
"Walking",
"Main"},
"Pause walking");
137 gui_.removeElement({
"Walking",
"Main"},
"Resume walking");
138 gui_.removeElement({
"Walking",
"Main"},
"Start walking");
139 gui_.addElement({
"Walking",
"Main"},
141 "Footstep plan", ctl.planInterpolator.availablePlans(), [&ctl]() { return ctl.plan.name; },
142 [&ctl](
const std::string & name) { ctl.updatePlan(name); }));
143 gui_.addElement({
"Standing"},
145 "CoM target [0-1]", [
this]() {
return std::round(leftFootRatio_ * 10.) / 10.; },
146 [
this](
double leftFootRatio) { updateTarget(leftFootRatio); }),
147 Label(
"Left foot force [N]",
148 [&ctl]() {
return ctl.realRobot().forceSensor(
"LeftFootForceSensor").force().z(); }),
149 Label(
"Right foot force [N]",
150 [&ctl]() {
return ctl.realRobot().forceSensor(
"RightFootForceSensor").force().z(); }),
151 Button(
"Go to left foot", [
this]() { updateTarget(1.); }),
152 Button(
"Go to middle", [
this]() { updateTarget(0.5); }),
153 Button(
"Go to right foot", [
this]() { updateTarget(0.); }));
154 gui_.addElement({
"Walking",
"Main"},
155 Button(!controller().pauseWalking || (supportContact_.id == 0) ?
"Start walking" :
"Resume walking",
156 [
this]() { startWalking(); }));
164 logger().removeLogEntry(
"walking_phase");
168 gui()->removeCategory({
"Standing"});
169 gui()->removeElement({
"Walking",
"Main"},
"Footstep plan");
170 gui()->removeElement({
"Walking",
"Main"},
"Gait");
171 gui()->removeElement({
"Walking",
"Main"},
"Go to middle");
172 gui()->removeElement({
"Walking",
"Main"},
"Resume walking");
173 gui()->removeElement({
"Walking",
"Main"},
"Start walking");
181 auto & ctl = controller();
182 auto & pendulum = ctl.pendulum();
184 Eigen::Vector3d comTarget = copTarget_ + Eigen::Vector3d{0., 0., ctl.plan.comHeight()};
185 const Eigen::Vector3d & com_i = pendulum.com();
186 const Eigen::Vector3d & comd_i = pendulum.comd();
187 const Eigen::Vector3d & cop_f = copTarget_;
189 double K = COM_STIFFNESS;
190 double D = 2 * std::sqrt(K);
191 Eigen::Vector3d comdd = K * (comTarget - com_i) - D * comd_i;
192 Eigen::Vector3d n = supportContact_.normal();
193 double lambda = n.dot(comdd + mc_rtc::constants::gravity) / n.dot(com_i - cop_f);
194 Eigen::Vector3d zmp = com_i - (mc_rtc::constants::gravity + comdd) / lambda;
196 pendulum.integrateIPM(zmp, lambda, ctl.timeStep);
197 ctl.leftFootRatio(leftFootRatio_);
198 ctl.stabilizer()->target(pendulum.com(), pendulum.comd(), pendulum.comdd(), pendulum.zmp());
203 using Foot = mc_plugin::ExternalFootstepPlanner::Foot;
204 auto & ctl = controller();
206 if(ctl.externalFootstepPlanner.planningRequested())
210 const auto lf_start =
utils::SE2d{controller().robot().surfacePose(
"LeftFootCenter")};
211 const auto rf_start =
utils::SE2d{controller().robot().surfacePose(
"RightFootCenter")};
216 auto defaultFoot = Foot::Right;
217 if(supportContact_.surfaceName ==
"RightFootCenter")
219 defaultFoot = Foot::Left;
221 auto lf = controller().robot().surfacePose(
"LeftFootCenter") * controller().robot().posW().inv();
222 auto rf = controller().robot().surfacePose(
"RightFootCenter") * controller().robot().posW().inv();
223 Eigen::Vector3d ref = ctl.datastore().call<Eigen::Vector3d>(
"HybridPlanner::GetVelocity");
226 bool rf_front_lf = rf.translation().
x() > lf.translation().x() + 0.02;
227 bool lf_front_rf = lf.translation().x() > rf.translation().x() + 0.02;
230 defaultFoot = Foot::Right;
234 defaultFoot = Foot::Left;
237 else if(ref.x() < -0.02)
239 bool rf_front_lf = rf.translation().x() > lf.translation().x() + 0.02;
240 bool lf_front_rf = lf.translation().x() > rf.translation().x() + 0.02;
243 defaultFoot = Foot::Left;
247 defaultFoot = Foot::Right;
250 ctl.externalFootstepPlanner.requestPlan(
252 ctl.externalFootstepPlanner.allowedTimeStanding());
259 ctl.plan.resetContacts(ctl.externalFootstepPlanner.plan());
260 ctl.updatePlan(
"external");
266 auto & ctl = controller();
268 if(ctl.plan.name ==
"external")
270 handleExternalPlan();
272 else if(ctl.planInterpolator.checkPlanUpdated())
274 ctl.loadFootstepPlan(ctl.planInterpolator.customPlanName());
280 auto & sole = controller().sole();
281 if(!controller().stabilizer()->inDoubleSupport())
283 mc_rtc::log::error(
"Cannot update CoM target while in single support");
286 leftFootRatio =
clamp(leftFootRatio, 0., 1.,
"Standing target");
287 sva::PTransformd X_0_lfr =
288 sva::interpolate(rightFootContact_.anklePose(sole), leftFootContact_.anklePose(sole), leftFootRatio);
289 copTarget_ = X_0_lfr.translation();
290 leftFootRatio_ = leftFootRatio;
295 auto & ctl = controller();
297 if(!ctl.startWalking || ctl.pauseWalking)
302 ctl.mpc().contacts(supportContact_, targetContact_, ctl.nextContact());
303 ctl.mpc().phaseDurations(0., ctl.plan.initDSPDuration(), ctl.singleSupportDuration());
304 if(ctl.updatePreview())
306 ctl.nextDoubleSupportDuration(ctl.plan.initDSPDuration());
307 ctl.startLogSegment(ctl.plan.name);
308 ctl.isWalking =
true;
309 output(
"DoubleSupport");
317 auto & ctl = controller();
320 mc_rtc::log::error(
"No footstep in contact plan");
323 ctl.startWalking =
true;
326 gui()->removeElement({
"Walking",
"Main"},
"Resume walking");
327 ctl.pauseWalking =
false;
329 gui()->addElement({
"Walking",
"Main"}, mc_rtc::gui::Button(
"Pause walking", [&ctl]()
330 { ctl.pauseWalkingCallback(
false); }));
double clamp(double v, double vMin, double vMax)
void updateTarget(double leftFootRatio)
void configure(const mc_rtc::Configuration &) override
bool checkTransitions() override
void handleExternalPlan()