28 #include <mc_rbdyn/rpy_utils.h>
29 #include <mc_rtc/gui.h>
44 sva::PTransformd makeHorizontal(sva::PTransformd pose)
46 const Eigen::Matrix3d R = pose.rotation();
47 const Eigen::Vector3d p = pose.translation();
48 Eigen::Vector3d rpy = mc_rbdyn::rpyFromMat(R);
49 return {mc_rbdyn::rpyToMat(0., 0., rpy(2)), {p.x(), p.y(), 0.}};
56 config(
"com_height", comHeight_);
57 config(
"contacts", contacts_);
58 config(
"double_support_duration", doubleSupportDuration_);
59 config(
"final_dsp_duration", finalDSPDuration_);
60 config(
"init_dsp_duration", initDSPDuration_);
61 config(
"landing_duration", landingDuration_);
62 config(
"landing_pitch", landingPitch_);
63 config(
"single_support_duration", singleSupportDuration_);
64 config(
"swing_height", swingHeight_);
65 config(
"takeoff_duration", takeoffDuration_);
66 config(
"takeoff_pitch", takeoffPitch_);
67 config(
"torso_pitch", torsoPitch_);
76 config.add(
"com_height", comHeight_);
77 config.add(
"contacts", contacts_);
78 config.add(
"double_support_duration", doubleSupportDuration_);
79 config.add(
"final_dsp_duration", finalDSPDuration_);
80 config.add(
"init_dsp_duration", initDSPDuration_);
81 config.add(
"landing_duration", landingDuration_);
82 config.add(
"landing_pitch", landingPitch_);
83 config.add(
"single_support_duration", singleSupportDuration_);
84 config.add(
"swing_height", swingHeight_);
85 config.add(
"takeoff_duration", takeoffDuration_);
86 config.add(
"takeoff_pitch", takeoffPitch_);
89 config.add(
"torso_pitch", torsoPitch_);
99 for(
unsigned i = 0; i < contacts_.size(); i++)
101 auto & contact = contacts_[i];
103 if(contact.halfLength < 1e-4)
107 if(contact.halfWidth < 1e-4)
111 if(contact.surfaceName.length() < 1)
113 mc_rtc::log::error(
"Footstep plan has no surface name for contact {}", i);
120 nextFootstep_ = startIndex + 1;
121 supportContact_ = contacts_[startIndex > 0 ? startIndex - 1 : 0];
122 targetContact_ = contacts_[startIndex];
128 prevContact_ = supportContact_;
129 supportContact_ = targetContact_;
130 unsigned targetFootstep = nextFootstep_++;
131 targetContact_ = (targetFootstep < contacts_.size()) ? contacts_[targetFootstep] : prevContact_;
132 nextContact_ = (nextFootstep_ < contacts_.size()) ? contacts_[nextFootstep_] : supportContact_;
137 assert(nextFootstep_ >= 1);
138 sva::PTransformd poseDrift = actualTargetPose * targetContact_.
pose.inv();
139 const Eigen::Vector3d & posDrift = poseDrift.translation();
140 sva::PTransformd xyDrift = Eigen::Vector3d{posDrift.x(), posDrift.y(), 0.};
141 for(
unsigned i = nextFootstep_ - 1; i < contacts_.size(); i++)
143 contacts_[i] = xyDrift * contacts_[i];
145 targetContact_.
pose = xyDrift * targetContact_.
pose;
151 nextContact_ = targetContact_;
152 targetContact_ = supportContact_;
153 supportContact_ = prevContact_;
155 if(nextFootstep_ >= contacts_.size())
158 prevContact_ = nextContact_;
164 sva::PTransformd X_0_c = contacts_[0].pose;
165 const std::string & surfaceName = contacts_[0].surfaceName;
166 const sva::PTransformd & X_0_fb = robot.posW();
167 sva::PTransformd X_s_0 = robot.surfacePose(surfaceName).inv();
168 sva::PTransformd X_s_fb = X_0_fb * X_s_0;
169 return X_s_fb * X_0_c;
173 const sva::PTransformd & X_0_rf,
176 sva::PTransformd X_0_mid = sva::interpolate(X_0_lf, X_0_rf, 0.5);
177 sva::PTransformd X_0_old = sva::interpolate(contacts_[0].pose, contacts_[1].pose, 0.5);
178 sva::PTransformd X_delta = makeHorizontal(X_0_old.inv() * X_0_mid);
179 for(
unsigned i = 2; i < contacts_.size(); i++)
182 const sva::PTransformd & X_0_c = contacts_[i].pose;
183 contacts_[i].pose = X_0_c * X_delta;
185 if(contacts_[0].surfaceName ==
"LeftFootCenter" && contacts_[1].surfaceName ==
"RightFootCenter")
187 contacts_[0].pose = makeHorizontal(X_0_lf);
188 contacts_[1].pose = makeHorizontal(X_0_rf);
190 else if(contacts_[0].surfaceName ==
"RightFootCenter" && contacts_[1].surfaceName ==
"LeftFootCenter")
192 contacts_[0].pose = makeHorizontal(X_0_rf);
193 contacts_[1].pose = makeHorizontal(X_0_lf);
197 mc_rtc::log::error(
"Invalid footstep plan: initial surfaces are \"{}\" and \"{}\"", contacts_[0].surfaceName,
198 contacts_[1].surfaceName);
200 sva::PTransformd X_0_rise = Eigen::Vector3d{0., 0., initHeight};
201 for(
unsigned i = 0; i < contacts_.size(); i++)
203 contacts_[i].pose = contacts_[i].pose * X_0_rise;
205 X_0_init_ = X_delta * X_0_rise;
212 gui.addElement({
"Walking"}, mc_rtc::gui::NumberInput(
213 "Torso Pitch [deg]", [
this]() {
return mc_rtc::constants::toDeg(torsoPitch_); },
214 [
this](
double p) {
torsoPitch(mc_rtc::constants::toRad(p)); }));
216 auto footStepPolygon = [](
const Contact & contact)
218 std::vector<Eigen::Vector3d> polygon;
219 polygon.push_back(contact.vertex0());
220 polygon.push_back(contact.vertex1());
221 polygon.push_back(contact.vertex2());
222 polygon.push_back(contact.vertex3());
226 auto contactsPolygons = [
this, footStepPolygon](
const std::string & surfaceName)
228 std::vector<std::vector<Eigen::Vector3d>> polygons;
230 for(
unsigned i = 0; i <
contacts.size(); i++)
233 if(contact.surfaceName == surfaceName)
237 constexpr
double SAME_CONTACT_DIST = 0.005;
239 if(supportDist > SAME_CONTACT_DIST && targetDist > SAME_CONTACT_DIST)
241 polygons.push_back(footStepPolygon(contact));
248 LineConfig leftPolygonConf;
249 leftPolygonConf.color = Color::Blue;
250 leftPolygonConf.width = 0.01;
251 leftPolygonConf.style = LineStyle::Dotted;
252 LineConfig rightPolygonConf = leftPolygonConf;
253 rightPolygonConf.color = Color::Red;
254 LineConfig targetContactPolygonConf = leftPolygonConf;
255 targetContactPolygonConf.color = Color::Green;
256 targetContactPolygonConf.width = 0.01;
257 targetContactPolygonConf.style = LineStyle::Solid;
259 gui.addElement({
"Markers",
"Footsteps",
"Plan"}, mc_rtc::gui::Button(
"Print Plan (YAML)",
262 mc_rtc::Configuration conf;
264 mc_rtc::log::info(
"Plan:\n{}",
265 conf.dump(
true,
true));
268 gui.addElement({
"Markers",
"Footsteps",
"Plan"},
269 Polygon(
"TargetContact", targetContactPolygonConf,
270 [
this, footStepPolygon]() {
return footStepPolygon(
targetContact()); }),
271 Polygon(
"FootstepPlan Left", leftPolygonConf,
272 [contactsPolygons]() {
return contactsPolygons(
"LeftFootCenter"); }),
273 Polygon(
"FootstepPlan Right", rightPolygonConf,
274 [contactsPolygons]() {
return contactsPolygons(
"RightFootCenter"); }));
279 gui.removeElement({
"Walking"},
"Torso Pitch [deg]");
280 gui.removeElement({
"Walking"},
"Print Plan");
281 gui.removeCategory({
"Markers",
"Footsteps",
"Plan"});