38 constexpr
double COM_STIFFNESS = 5.;
44 auto & supportContact = ctl.supportContact();
45 auto & targetContact = ctl.targetContact();
48 isMakingFootContact_ =
false;
50 lastInterpolatorIter_ = ctl.planInterpolator.nbIter;
51 leftFootRatio_ = ctl.leftFootRatio();
52 releaseHeight_ = 0.05;
53 startWalking_ =
false;
54 if(supportContact.surfaceName ==
"RightFootCenter")
56 leftFootContact_ = targetContact;
57 rightFootContact_ = supportContact;
59 else if(supportContact.surfaceName ==
"LeftFootCenter")
61 leftFootContact_ = supportContact;
62 rightFootContact_ = targetContact;
66 LOG_ERROR_AND_THROW(std::invalid_argument,
"Unknown surface name: " << supportContact.surfaceName);
71 ctl.loadFootstepPlan(ctl.plan.name);
78 ctl.solver().addTask(ctl.pelvisTask);
79 ctl.solver().addTask(ctl.torsoTask);
84 logger().addLogEntry(
"support_xmax",
85 [&ctl]() {
return std::max(ctl.supportContact().xmax(), ctl.targetContact().xmax()); });
86 logger().addLogEntry(
"support_xmin",
87 [&ctl]() {
return std::min(ctl.supportContact().xmin(), ctl.targetContact().xmin()); });
88 logger().addLogEntry(
"support_ymax",
89 [&ctl]() {
return std::max(ctl.supportContact().ymax(), ctl.targetContact().ymax()); });
90 logger().addLogEntry(
"support_ymin",
91 [&ctl]() {
return std::min(ctl.supportContact().ymin(), ctl.targetContact().ymin()); });
92 logger().addLogEntry(
"support_zmax",
93 [&ctl]() {
return std::max(ctl.supportContact().zmax(), ctl.targetContact().zmax()); });
94 logger().addLogEntry(
"support_zmin",
95 [&ctl]() {
return std::min(ctl.supportContact().zmin(), ctl.targetContact().zmin()); });
96 logger().addLogEntry(
"walking_phase", []() {
return 3.; });
101 using namespace mc_rtc::gui;
102 gui()->removeElement({
"Walking",
"Main"},
"Pause walking");
103 gui()->addElement({
"Walking",
"Main"}, ComboInput(
"Footstep plan", ctl.planInterpolator.availablePlans(),
104 [&ctl]() {
return ctl.plan.name; },
105 [
this](
const std::string & name) {
updatePlan(name); }));
106 gui()->addElement({
"Walking",
"Main"}, Button((supportContact.id == 0) ?
"Start walking" :
"Resume walking",
107 [
this]() { startWalking(); }));
108 gui()->addElement({
"Standing"},
109 NumberInput(
"CoM target [0-1]", [
this]() {
return std::round(leftFootRatio_ * 10.) / 10.; },
110 [
this](
double leftFootRatio) {
updateTarget(leftFootRatio); }),
111 NumberInput(
"Free foot gain", [
this]() {
return std::round(freeFootGain_); },
112 [
this](
double gain) { freeFootGain_ =
clamp(gain, 5., 100.); }),
113 NumberInput(
"Release height [m]", [
this]() {
return std::round(releaseHeight_ * 100.) / 100.; },
114 [
this](
double height) { releaseHeight_ =
clamp(height, 0., 0.25); }),
115 Label(
"Left foot force [N]",
116 [&ctl]() {
return ctl.realRobot().forceSensor(
"LeftFootForceSensor").force().z(); }),
117 Label(
"Right foot force [N]",
118 [&ctl]() {
return ctl.realRobot().forceSensor(
"RightFootForceSensor").force().z(); }),
119 Button(
"Go to left foot", [
this]() {
updateTarget(1.); }),
120 Button(
"Go to middle", [
this]() {
updateTarget(0.5); }),
121 Button(
"Go to right foot", [
this]() {
updateTarget(0.); }),
137 logger().removeLogEntry(
"support_xmax");
138 logger().removeLogEntry(
"support_xmin");
139 logger().removeLogEntry(
"support_ymax");
140 logger().removeLogEntry(
"support_ymin");
141 logger().removeLogEntry(
"support_zmax");
142 logger().removeLogEntry(
"support_zmin");
143 logger().removeLogEntry(
"walking_phase");
147 gui()->removeCategory({
"Standing"});
148 gui()->removeElement({
"Walking",
"Main"},
"Footstep plan");
149 gui()->removeElement({
"Walking",
"Main"},
"Gait");
150 gui()->removeElement({
"Walking",
"Main"},
"Go to middle");
151 gui()->removeElement({
"Walking",
"Main"},
"Resume walking");
152 gui()->removeElement({
"Walking",
"Main"},
"Start walking");
160 if(isMakingFootContact_)
164 bool isLeftFootSeekingContact = (leftFootTask->admittance().couple().x() < 1e-10);
165 bool isRightFootSeekingContact = (rightFootTask->admittance().couple().x() < 1e-10);
168 if(isLeftFootSeekingContact && leftFootTouchdown)
172 if(isRightFootSeekingContact && rightFootTouchdown)
176 isLeftFootSeekingContact = (leftFootTask->admittance().couple().x() < 1e-10);
177 isRightFootSeekingContact = (rightFootTask->admittance().couple().x() < 1e-10);
178 if(!isLeftFootSeekingContact && !isRightFootSeekingContact)
180 isMakingFootContact_ =
false;
188 Eigen::Vector3d comTarget = copTarget_ + Eigen::Vector3d{0., 0., ctl.plan.comHeight()};
191 const Eigen::Vector3d & cop_f = copTarget_;
193 double K = COM_STIFFNESS;
194 double D = 2 * std::sqrt(K);
195 Eigen::Vector3d comdd = K * (comTarget - com_i) - D * comd_i;
196 Eigen::Vector3d n = ctl.supportContact().normal();
197 double lambda = n.dot(comdd -
world::gravity) / n.dot(com_i - cop_f);
201 ctl.leftFootRatio(leftFootRatio_);
202 ctl.stabilizer().run();
208 if(ctl.planInterpolator.nbIter > lastInterpolatorIter_)
210 ctl.loadFootstepPlan(ctl.planInterpolator.customPlanName());
211 lastInterpolatorIter_ = ctl.planInterpolator.nbIter;
218 gui()->removeElement({
"Walking",
"Main"},
"Resume walking");
219 gui()->removeElement({
"Walking",
"Main"},
"Start walking");
220 gui()->addElement({
"Walking",
"Main"}, mc_rtc::gui::Button(
"Start walking", [
this]() {
startWalking(); }));
222 planChanged_ =
false;
231 LOG_ERROR(
"Cannot update CoM target while in single support");
234 leftFootRatio =
clamp(leftFootRatio, 0., 1.,
"Standing target");
235 sva::PTransformd X_0_lfr =
236 sva::interpolate(rightFootContact_.anklePose(sole), leftFootContact_.anklePose(sole), leftFootRatio);
237 copTarget_ = X_0_lfr.translation();
238 leftFootRatio_ = leftFootRatio;
246 LOG_WARNING(
"Foot is already in contact");
251 footTask->stiffness(freeFootGain_);
252 footTask->targetPose(contact.
pose);
253 isMakingFootContact_ =
true;
268 constexpr
double MAX_FOOT_RELEASE_FORCE = 50.;
270 if(footTask->admittance().couple().x() < 1e-10)
272 LOG_WARNING(
"Foot contact is already released");
275 else if(footTask->measuredWrench().force().z() > MAX_FOOT_RELEASE_FORCE)
277 LOG_ERROR(
"Contact force is too high to release foot");
280 sva::PTransformd X_0_f = footTask->surfacePose();
281 sva::PTransformd X_f_t = Eigen::Vector3d{0., 0., releaseHeight_};
283 footTask->stiffness(freeFootGain_);
284 footTask->targetPose(X_f_t * X_0_f);
308 if(isMakingFootContact_)
317 ctl.mpc().contacts(ctl.supportContact(), ctl.targetContact(), ctl.nextContact());
318 ctl.mpc().phaseDurations(0., ctl.plan.initDSPDuration(), ctl.singleSupportDuration());
319 if(ctl.updatePreview())
321 ctl.nextDoubleSupportDuration(ctl.plan.initDSPDuration());
322 ctl.startLogSegment(ctl.plan.name);
323 output(
"DoubleSupport");
334 LOG_ERROR(
"No footstep in contact plan");
337 startWalking_ =
true;
338 gui()->addElement({
"Walking",
"Main"},
339 mc_rtc::gui::Button(
"Pause walking", [&ctl]() { ctl.pauseWalkingCallback(
true); }));
345 if(name.find(
"custom") != std::string::npos)
347 if(!ctl.planInterpolator.isShown)
349 ctl.planInterpolator.addGUIElements();
350 ctl.planInterpolator.isShown =
true;
352 if(name.find(
"backward") != std::string::npos)
354 ctl.planInterpolator.restoreBackwardTarget();
356 else if(name.find(
"forward") != std::string::npos)
358 ctl.planInterpolator.restoreForwardTarget();
360 else if(name.find(
"lateral") != std::string::npos)
362 ctl.planInterpolator.restoreLateralTarget();
364 ctl.loadFootstepPlan(ctl.planInterpolator.customPlanName());
368 if(ctl.planInterpolator.isShown)
370 ctl.planInterpolator.removeGUIElements();
371 ctl.planInterpolator.isShown =
false;
373 ctl.loadFootstepPlan(name);
double clamp(double v, double vMin, double vMax)
Clamp a value in a given interval.
ContactState contactState()
Get contact state.
Pendulum & pendulum()
Get pendulum reference.
void seekTouchdown(std::shared_ptr< mc_tasks::force::CoPTask > footTask)
Configure foot task for contact seeking.
Stabilizer & stabilizer()
This getter is only used for consistency with the rest of mc_rtc.
void addTasks(mc_solver::QPSolver &solver)
Add tasks to QP solver.
Enable stabilizer and keep CoM at a reference position.
std::shared_ptr< mc_rtc::gui::StateBuilder > gui()
Get GUI handle.
void checkPlanUpdates()
Check for footstep plan updates.
const Eigen::Vector3d & comd() const
CoM velocity in the world frame.
Stabilizer & stabilizer()
Get stabilizer.
bool releaseFootContact(std::shared_ptr< mc_tasks::force::CoPTask > footTask)
Release foot contact.
bool detectTouchdown(const std::shared_ptr< mc_tasks::force::CoPTask > footTask, const Contact &contact)
Detect foot touchdown based on both force and distance.
void startWalking()
Enable startWalking_ boolean and update GUI.
void makeLeftFootContact()
Make left foot contact.
std::shared_ptr< mc_tasks::force::CoPTask > leftFootTask
Left foot hybrid position/force control task.
std::shared_ptr< mc_tasks::force::CoPTask > rightFootTask
Right foot hybrid position/force control task.
void releaseRightFootContact()
Release right foot contact.
void integrateIPM(Eigen::Vector3d zmp, double lambda, double dt)
Integrate in floating-base inverted pendulum mode with constant inputs.
mc_rtc::Logger & logger()
Get logger.
void updatePlan(const std::string &name)
Change footstep plan.
const Eigen::Vector3d gravity
void updateTarget(double leftFootRatio)
Update target CoM and CoP.
void setContact(std::shared_ptr< mc_tasks::force::CoPTask > footTask, const Contact &contact)
Configure foot task for contact at a given location.
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.
const Eigen::Vector3d & com() const
CoM position in the world frame.
const Sole & sole() const
Get model sole properties.
void runState() override
Main state function, called if no transition at this cycle.
void makeRightFootContact()
Make right foot contact.
Controller & controller()
Get controller.
void makeFootContact(std::shared_ptr< mc_tasks::force::CoPTask > footTask, const Contact &contact)
Make foot contact.
void start() override
Start state.
bool checkTransitions() override
Check transitions at beginning of control cycle.
void releaseLeftFootContact()
Release left foot contact.
void teardown() override
Teardown state.