SingleSupport.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 "SingleSupport.h"
29 
30 namespace lipm_walking
31 {
32 
34 {
35  using Foot = mc_plugin::ExternalFootstepPlanner::Foot;
36  auto & ctl = controller();
37 
38  double allowedTime = ctl.externalFootstepPlanner.allowedTimeSingleSupport();
39  if(allowedTime >= duration_)
40  {
41  mc_rtc::log::error_and_throw<std::runtime_error>("[{}] Maximum allowed time ({:.3f}) for the external planner "
42  "cannot be greater than the single support duration ({:.3f})",
43  name(), allowedTime, duration_);
44  }
45 
46  if(ctl.externalFootstepPlanner.planningRequested())
47  {
48  if(remTime_ > allowedTime)
49  { // If we have enough time left to compute a plan,
50  // then we request a plan to be used during the next DoubleSupport phase
51  if(ctl.supportContact().surfaceName == "LeftFootCenter")
52  {
53  const auto lf_start = utils::SE2d{ctl.supportContact().pose};
54  const auto rf_start = utils::SE2d{ctl.targetContact().pose};
55  Foot supportFoot = Foot::Right;
56  ctl.externalFootstepPlanner.requestPlan(ExternalPlanner::DoubleSupport, supportFoot, lf_start, rf_start,
57  allowedTime);
58  }
59  else
60  {
61  const auto rf_start = utils::SE2d{ctl.supportContact().pose};
62  const auto lf_start = utils::SE2d{ctl.targetContact().pose};
63  Foot supportFoot = Foot::Left;
64  ctl.externalFootstepPlanner.requestPlan(ExternalPlanner::DoubleSupport, supportFoot, lf_start, rf_start,
65  allowedTime);
66  }
67  }
68  }
69 }
70 
72 {
73  auto & ctl = controller();
74  ctl.walkingState = WalkingState::SingleSupport;
75  auto & supportContact = ctl.supportContact();
76  auto & targetContact = ctl.targetContact();
77 
78  duration_ = ctl.singleSupportDuration();
79  hasUpdatedMPCOnce_ = false;
80  remTime_ = ctl.singleSupportDuration();
81  stateTime_ = 0.;
82  timeSinceLastPreviewUpdate_ = 0.; // don't update at transition
83 
84  if(supportContact.surfaceName == "LeftFootCenter")
85  {
86  ctl.leftFootRatio(1.);
87  ctl.setContacts({{ContactState::Left, supportContact.pose}});
88  swingFootTask = ctl.swingFootTaskRight_;
89  }
90  else
91  {
92  ctl.leftFootRatio(0.);
93  ctl.setContacts({{ContactState::Right, supportContact.pose}});
94  swingFootTask = ctl.swingFootTaskLeft_;
95  }
96  swingFootTask->reset();
97  ctl.solver().addTask(swingFootTask);
98 
99  swingFoot_.landingDuration(ctl.plan.landingDuration());
100  swingFoot_.landingPitch(ctl.plan.landingPitch());
101  swingFoot_.takeoffDuration(ctl.plan.takeoffDuration());
102  swingFoot_.takeoffOffset(ctl.plan.takeoffOffset());
103  swingFoot_.takeoffPitch(ctl.plan.takeoffPitch());
104  swingFoot_.reset(swingFootTask->surfacePose(), targetContact.pose, duration_, ctl.plan.swingHeight());
105 
106  logger().addLogEntry("rem_phase_time", [this]() { return remTime_; });
107  logger().addLogEntry("walking_phase", []() { return 1.; });
108  swingFoot_.addLogEntries(logger());
109 
110  runState(); // don't wait till next cycle to update reference and tasks
111 }
112 
114 {
115  controller().solver().removeTask(swingFootTask);
116 
117  logger().removeLogEntry("contact_impulse");
118  logger().removeLogEntry("rem_phase_time");
119  logger().removeLogEntry("walking_phase");
120  swingFoot_.removeLogEntries(logger());
121 }
122 
124 {
125  if(remTime_ < 0.)
126  {
127  output("DoubleSupport");
128  return true;
129  }
130  return false;
131 }
132 
134 {
135  auto & ctl = controller();
136  double dt = ctl.timeStep;
137 
138  if(ctl.plan.name == "external")
139  {
140  handleExternalPlan();
141  }
142 
143  updateSwingFoot();
144  if(timeSinceLastPreviewUpdate_ > PREVIEW_UPDATE_PERIOD)
145  {
146  updatePreview();
147  }
148 
149  ctl.preview->integrate(pendulum(), dt);
150  if(hasUpdatedMPCOnce_)
151  {
152  pendulum().resetCoMHeight(ctl.plan.comHeight(), ctl.supportContact().p(), ctl.supportContact().normal());
153  pendulum().completeIPM(ctl.supportContact().p(), ctl.supportContact().normal());
154  }
155  else // still in DSP of preview
156  {
157  pendulum().completeIPM(ctl.prevContact().p(), ctl.prevContact().normal());
158  }
159 
160  stabilizer()->target(pendulum().com(), pendulum().comd(), pendulum().comdd(), pendulum().zmp());
161 
162  remTime_ -= dt;
163  stateTime_ += dt;
164  timeSinceLastPreviewUpdate_ += dt;
165 }
166 
168 {
169  auto & ctl = controller();
170  auto & targetContact = ctl.targetContact();
171  auto & supportContact = ctl.supportContact();
172  double dt = ctl.timeStep;
173 
174  if(!stabilizer()->inDoubleSupport())
175  {
176  bool liftPhase = (remTime_ > duration_ / 3.);
177  bool touchdownDetected = detectTouchdown(swingFootTask, targetContact.pose);
178  if(liftPhase || !touchdownDetected)
179  {
180  swingFoot_.integrate(dt);
181  swingFootTask->target(swingFoot_.pose());
182  // T_0_s transforms a MotionVecd variable from world to surface frame
183  sva::PTransformd T_0_s(swingFootTask->surfacePose().rotation());
184  swingFootTask->refVelB(T_0_s * swingFoot_.vel());
185  swingFootTask->refAccel(T_0_s * swingFoot_.accel());
186  }
187  else
188  {
189  if(supportContact.surfaceName == "LeftFootCenter")
190  {
191  stabilizer()->setContacts(
192  {{ContactState::Left, supportContact.pose}, {ContactState::Right, targetContact.pose}});
193  }
194  else
195  {
196  stabilizer()->setContacts(
197  {{ContactState::Left, targetContact.pose}, {ContactState::Right, supportContact.pose}});
198  }
199  }
200  }
201 }
202 
203 bool states::SingleSupport::detectTouchdown(const std::shared_ptr<mc_tasks::SurfaceTransformTask> footTask,
204  const sva::PTransformd & contactPose)
205 {
206  const sva::PTransformd X_0_s = footTask->surfacePose();
207  const sva::PTransformd & X_0_c = contactPose;
208  sva::PTransformd X_c_s = X_0_s * X_0_c.inv();
209  double xDist = std::abs(X_c_s.translation().x());
210  double yDist = std::abs(X_c_s.translation().y());
211  double zDist = std::abs(X_c_s.translation().z());
212  double Fz = controller().robot().surfaceWrench(footTask->surface()).force().z();
213  return (xDist < 0.01 && yDist < 0.01 && zDist < 0.01 && Fz > 50.);
214 }
215 
217 {
218  auto & ctl = controller();
219  ctl.mpc().contacts(ctl.supportContact(), ctl.targetContact(), ctl.nextContact());
220  if(ctl.isLastSSP() || ctl.pauseWalking)
221  {
222  ctl.nextDoubleSupportDuration(ctl.plan.finalDSPDuration());
223  ctl.mpc().phaseDurations(remTime_, ctl.plan.finalDSPDuration(), 0.);
224  }
225  else
226  {
227  ctl.mpc().phaseDurations(remTime_, ctl.doubleSupportDuration(), ctl.singleSupportDuration());
228  }
229  if(ctl.updatePreview())
230  {
231  timeSinceLastPreviewUpdate_ = 0.;
232  hasUpdatedMPCOnce_ = true;
233  }
234 }
235 
236 } // namespace lipm_walking
237 
238 EXPORT_SINGLE_STATE("LIPMWalking::SingleSupport", lipm_walking::states::SingleSupport)
constexpr double PREVIEW_UPDATE_PERIOD
Definition: Controller.h:55
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Controller & controller()
Definition: State.h:47
bool detectTouchdown(const std::shared_ptr< mc_tasks::SurfaceTransformTask > footTask, const sva::PTransformd &contactPose)