FootstepPlan.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2019, CNRS-UM LIRMM
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <mc_rbdyn/rpy_utils.h>
29 #include <mc_rtc/gui.h>
30 
32 
33 namespace lipm_walking
34 {
35 
36 namespace
37 {
38 
44 sva::PTransformd makeHorizontal(sva::PTransformd pose)
45 {
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.}};
50 }
51 
52 } // namespace
53 
54 void FootstepPlan::load(const mc_rtc::Configuration & config)
55 {
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_);
68  if(config.has("mpc"))
69  {
70  mpcConfig = config("mpc");
71  }
72 }
73 
74 void FootstepPlan::save(mc_rtc::Configuration & config) const
75 {
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_);
87  if(hasTorsoPitch())
88  {
89  config.add("torso_pitch", torsoPitch_);
90  }
91  if(!mpcConfig.empty())
92  {
93  config.add("mpc") = mpcConfig;
94  }
95 }
96 
97 void FootstepPlan::complete(const Sole & sole)
98 {
99  for(unsigned i = 0; i < contacts_.size(); i++)
100  {
101  auto & contact = contacts_[i];
102  contact.id = i;
103  if(contact.halfLength < 1e-4)
104  {
105  contact.halfLength = sole.halfLength;
106  }
107  if(contact.halfWidth < 1e-4)
108  {
109  contact.halfWidth = sole.halfWidth;
110  }
111  if(contact.surfaceName.length() < 1)
112  {
113  mc_rtc::log::error("Footstep plan has no surface name for contact {}", i);
114  }
115  }
116 }
117 
118 void FootstepPlan::reset(unsigned startIndex)
119 {
120  nextFootstep_ = startIndex + 1;
121  supportContact_ = contacts_[startIndex > 0 ? startIndex - 1 : 0];
122  targetContact_ = contacts_[startIndex];
124 }
125 
127 {
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_;
133 }
134 
135 void FootstepPlan::goToNextFootstep(const sva::PTransformd & actualTargetPose)
136 {
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++)
142  {
143  contacts_[i] = xyDrift * contacts_[i];
144  }
145  targetContact_.pose = xyDrift * targetContact_.pose;
147 }
148 
150 {
151  nextContact_ = targetContact_;
152  targetContact_ = supportContact_;
153  supportContact_ = prevContact_;
154  nextFootstep_--;
155  if(nextFootstep_ >= contacts_.size())
156  {
157  // at goToNextFootstep(), targetContact_ will copy prevContact_
158  prevContact_ = nextContact_;
159  }
160 }
161 
162 sva::PTransformd FootstepPlan::computeInitialTransform(const mc_rbdyn::Robot & robot) const
163 {
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;
170 }
171 
172 void FootstepPlan::updateInitialTransform(const sva::PTransformd & X_0_lf,
173  const sva::PTransformd & X_0_rf,
174  double initHeight)
175 {
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++)
180  {
181  // X_0_nc = X_old_c X_0_new = X_0_c X_old_0 X_0_new
182  const sva::PTransformd & X_0_c = contacts_[i].pose;
183  contacts_[i].pose = X_0_c * X_delta;
184  }
185  if(contacts_[0].surfaceName == "LeftFootCenter" && contacts_[1].surfaceName == "RightFootCenter")
186  {
187  contacts_[0].pose = makeHorizontal(X_0_lf);
188  contacts_[1].pose = makeHorizontal(X_0_rf);
189  }
190  else if(contacts_[0].surfaceName == "RightFootCenter" && contacts_[1].surfaceName == "LeftFootCenter")
191  {
192  contacts_[0].pose = makeHorizontal(X_0_rf);
193  contacts_[1].pose = makeHorizontal(X_0_lf);
194  }
195  else
196  {
197  mc_rtc::log::error("Invalid footstep plan: initial surfaces are \"{}\" and \"{}\"", contacts_[0].surfaceName,
198  contacts_[1].surfaceName);
199  }
200  sva::PTransformd X_0_rise = Eigen::Vector3d{0., 0., initHeight};
201  for(unsigned i = 0; i < contacts_.size(); i++)
202  {
203  contacts_[i].pose = contacts_[i].pose * X_0_rise;
204  }
205  X_0_init_ = X_delta * X_0_rise;
206 }
207 
208 void FootstepPlan::addGUIElements(mc_rtc::gui::StateBuilder & gui)
209 {
210  using namespace mc_rtc::gui;
211 
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)); }));
215 
216  auto footStepPolygon = [](const Contact & contact)
217  {
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());
223  return polygon;
224  };
225 
226  auto contactsPolygons = [this, footStepPolygon](const std::string & surfaceName)
227  {
228  std::vector<std::vector<Eigen::Vector3d>> polygons;
229  const auto & contacts = contacts_;
230  for(unsigned i = 0; i < contacts.size(); i++)
231  {
232  auto & contact = contacts[i];
233  if(contact.surfaceName == surfaceName)
234  {
235  double supportDist = (contact.p() - supportContact().p()).norm();
236  double targetDist = (contact.p() - targetContact().p()).norm();
237  constexpr double SAME_CONTACT_DIST = 0.005;
238  // only display contact if it is not the support or target contact
239  if(supportDist > SAME_CONTACT_DIST && targetDist > SAME_CONTACT_DIST)
240  {
241  polygons.push_back(footStepPolygon(contact));
242  }
243  }
244  }
245  return polygons;
246  };
247 
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;
258 
259  gui.addElement({"Markers", "Footsteps", "Plan"}, mc_rtc::gui::Button("Print Plan (YAML)",
260  [this]
261  {
262  mc_rtc::Configuration conf;
263  this->save(conf);
264  mc_rtc::log::info("Plan:\n{}",
265  conf.dump(true, true));
266  }));
267 
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"); }));
275 }
276 
277 void FootstepPlan::removeGUIElements(mc_rtc::gui::StateBuilder & gui)
278 {
279  gui.removeElement({"Walking"}, "Torso Pitch [deg]");
280  gui.removeElement({"Walking"}, "Print Plan");
281  gui.removeCategory({"Markers", "Footsteps", "Plan"});
282 }
283 
284 } // namespace lipm_walking
sva::PTransformd pose
Definition: Contact.h:314
const Eigen::Vector3d & p() const
Definition: Contact.h:104
mc_rtc::Configuration mpcConfig
Definition: FootstepPlan.h:452
void reset(unsigned startIndex)
void addGUIElements(mc_rtc::gui::StateBuilder &gui)
Display the footstep plan in the GUI.
void updateInitialTransform(const sva::PTransformd &X_0_lf, const sva::PTransformd &X_0_rf, double initHeight)
EIGEN_MAKE_ALIGNED_OPERATOR_NEW void complete(const Sole &sole)
void load(const mc_rtc::Configuration &config)
const Contact & targetContact() const
Definition: FootstepPlan.h:412
const std::vector< Contact > & contacts() const
Definition: FootstepPlan.h:146
void save(mc_rtc::Configuration &config) const
sva::PTransformd computeInitialTransform(const mc_rbdyn::Robot &robot) const
const Contact & supportContact() const
Definition: FootstepPlan.h:310
void removeGUIElements(mc_rtc::gui::StateBuilder &gui)
Remove the footstep plan from the GUI.
double halfLength
Definition: Sole.h:45
double halfWidth
Definition: Sole.h:46