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 
31 
32 namespace lipm_walking
33 {
34 
35 namespace
36 {
37 
43 sva::PTransformd makeHorizontal(sva::PTransformd pose)
44 {
45  const Eigen::Matrix3d R = pose.rotation();
46  const Eigen::Vector3d p = pose.translation();
47  Eigen::Vector3d rpy = mc_rbdyn::rpyFromMat(R);
48  return {mc_rbdyn::rpyToMat(0., 0., rpy(2)), {p.x(), p.y(), 0.}};
49 }
50 
51 } // namespace
52 
53 void FootstepPlan::load(const mc_rtc::Configuration & config)
54 {
55  config("com_height", comHeight_);
56  config("contacts", contacts_);
57  config("double_support_duration", doubleSupportDuration_);
58  config("final_dsp_duration", finalDSPDuration_);
59  config("init_dsp_duration", initDSPDuration_);
60  config("landing_duration", landingDuration_);
61  config("landing_pitch", landingPitch_);
62  config("single_support_duration", singleSupportDuration_);
63  config("swing_height", swingHeight_);
64  config("takeoff_duration", takeoffDuration_);
65  config("takeoff_pitch", takeoffPitch_);
66  config("torso_pitch", torsoPitch_);
67  if(config.has("mpc"))
68  {
69  mpcConfig = config("mpc");
70  }
71 }
72 
73 void FootstepPlan::save(mc_rtc::Configuration & config) const
74 {
75  config.add("com_height", comHeight_);
76  config.add("contacts", contacts_);
77  config.add("double_support_duration", doubleSupportDuration_);
78  config.add("final_dsp_duration", finalDSPDuration_);
79  config.add("init_dsp_duration", initDSPDuration_);
80  config.add("landing_duration", landingDuration_);
81  config.add("landing_pitch", landingPitch_);
82  config.add("single_support_duration", singleSupportDuration_);
83  config.add("swing_height", swingHeight_);
84  config.add("takeoff_duration", takeoffDuration_);
85  config.add("takeoff_pitch", takeoffPitch_);
86  if(hasTorsoPitch())
87  {
88  config.add("torso_pitch", torsoPitch_);
89  }
90  if(!mpcConfig.empty())
91  {
92  config("mpc") = mpcConfig;
93  }
94 }
95 
96 void FootstepPlan::complete(const Sole & sole)
97 {
98  for(unsigned i = 0; i < contacts_.size(); i++)
99  {
100  auto & contact = contacts_[i];
101  contact.id = i;
102  if(contact.halfLength < 1e-4)
103  {
104  contact.halfLength = sole.halfLength;
105  }
106  if(contact.halfWidth < 1e-4)
107  {
108  contact.halfWidth = sole.halfWidth;
109  }
110  if(contact.surfaceName.length() < 1)
111  {
112  LOG_ERROR("Footstep plan has no surface name for contact " << i);
113  }
114  }
115 }
116 
117 void FootstepPlan::reset(unsigned startIndex)
118 {
119  nextFootstep_ = startIndex + 1;
120  supportContact_ = contacts_[startIndex > 0 ? startIndex - 1 : 0];
121  targetContact_ = contacts_[startIndex];
123 }
124 
126 {
127  prevContact_ = supportContact_;
128  supportContact_ = targetContact_;
129  unsigned targetFootstep = nextFootstep_++;
130  targetContact_ = (targetFootstep < contacts_.size()) ? contacts_[targetFootstep] : prevContact_;
131  nextContact_ = (nextFootstep_ < contacts_.size()) ? contacts_[nextFootstep_] : supportContact_;
132 }
133 
134 void FootstepPlan::goToNextFootstep(const sva::PTransformd & actualTargetPose)
135 {
136  assert(nextFootstep_ >= 1);
137  sva::PTransformd poseDrift = actualTargetPose * targetContact_.pose.inv();
138  const Eigen::Vector3d & posDrift = poseDrift.translation();
139  sva::PTransformd xyDrift = Eigen::Vector3d{posDrift.x(), posDrift.y(), 0.};
140  for(unsigned i = nextFootstep_ - 1; i < contacts_.size(); i++)
141  {
142  contacts_[i] = xyDrift * contacts_[i];
143  }
144  targetContact_.pose = xyDrift * targetContact_.pose;
146 }
147 
149 {
150  nextContact_ = targetContact_;
151  targetContact_ = supportContact_;
152  supportContact_ = prevContact_;
153  nextFootstep_--;
154  if(nextFootstep_ >= contacts_.size())
155  {
156  // at goToNextFootstep(), targetContact_ will copy prevContact_
157  prevContact_ = nextContact_;
158  }
159 }
160 
161 sva::PTransformd FootstepPlan::computeInitialTransform(const mc_rbdyn::Robot & robot) const
162 {
163  sva::PTransformd X_0_c = contacts_[0].pose;
164  const std::string & surfaceName = contacts_[0].surfaceName;
165  const sva::PTransformd & X_0_fb = robot.posW();
166  sva::PTransformd X_s_0 = robot.surfacePose(surfaceName).inv();
167  sva::PTransformd X_s_fb = X_0_fb * X_s_0;
168  return X_s_fb * X_0_c;
169 }
170 
171 void FootstepPlan::updateInitialTransform(const sva::PTransformd & X_0_lf,
172  const sva::PTransformd & X_0_rf,
173  double initHeight)
174 {
175  sva::PTransformd X_0_mid = sva::interpolate(X_0_lf, X_0_rf, 0.5);
176  sva::PTransformd X_0_old = sva::interpolate(contacts_[0].pose, contacts_[1].pose, 0.5);
177  sva::PTransformd X_delta = makeHorizontal(X_0_old.inv() * X_0_mid);
178  for(unsigned i = 2; i < contacts_.size(); i++)
179  {
180  // X_0_nc = X_old_c X_0_new = X_0_c X_old_0 X_0_new
181  const sva::PTransformd & X_0_c = contacts_[i].pose;
182  contacts_[i].pose = X_0_c * X_delta;
183  }
184  if(contacts_[0].surfaceName == "LeftFootCenter" && contacts_[1].surfaceName == "RightFootCenter")
185  {
186  contacts_[0].pose = makeHorizontal(X_0_lf);
187  contacts_[1].pose = makeHorizontal(X_0_rf);
188  }
189  else if(contacts_[0].surfaceName == "RightFootCenter" && contacts_[1].surfaceName == "LeftFootCenter")
190  {
191  contacts_[0].pose = makeHorizontal(X_0_rf);
192  contacts_[1].pose = makeHorizontal(X_0_lf);
193  }
194  else
195  {
196  LOG_ERROR("Invalid footstep plan: initial surfaces are \"" << contacts_[0].surfaceName << "\" and \""
197  << contacts_[1].surfaceName << "\"");
198  }
199  sva::PTransformd X_0_rise = Eigen::Vector3d{0., 0., initHeight};
200  for(unsigned i = 0; i < contacts_.size(); i++)
201  {
202  contacts_[i].pose = contacts_[i].pose * X_0_rise;
203  }
204  X_0_init_ = X_delta * X_0_rise;
205 }
206 
207 } // namespace lipm_walking
void load(const mc_rtc::Configuration &config)
Load plan from configuration dictionary.
double halfLength
Half-length of the sole in [m].
Definition: Sole.h:45
void goToNextFootstep()
Advance to next footstep in plan.
void updateInitialTransform(const sva::PTransformd &X_0_lf, const sva::PTransformd &X_0_rf, double initHeight)
Update plan coordinates from robot foot transforms.
double halfWidth
Half-width of the sole in [m].
Definition: Sole.h:46
sva::PTransformd computeInitialTransform(const mc_rbdyn::Robot &robot) const
Compute initial floating-base transform over first contact.
mc_rtc::Configuration mpcConfig
Definition: FootstepPlan.h:426
void restorePreviousFootstep()
Rewind one footstep back in plan.
Main controller namespace.
Definition: build.dox:1
void reset(unsigned startIndex)
Rewind plan to a given contact.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW void complete(const Sole &sole)
Complete contacts from sole parameters.
bool hasTorsoPitch() const
Does the plan provide a reference torso pitch?
Definition: FootstepPlan.h:172
Foot sole properties.
Definition: Sole.h:38
void save(mc_rtc::Configuration &config) const
Save plan to configuration dictionary.
sva::PTransformd pose
Plücker transform of the contact in the inertial frame.
Definition: Contact.h:321