DoubleSupport.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 "DoubleSupport.h"
29 
30 namespace lipm_walking
31 {
32 
34 
36 {
37  const auto & ctl = controller();
38  auto Fzs = ctl.robot().frame(ctl.prevContact().surfaceName).wrench().force().z();
39  auto Fzt = ctl.robot().frame(ctl.nextContact().surfaceName).wrench().force().z();
40  return Fzs >= minSupportForce_ && Fzt >= minSupportForce_ && goodInitialSupport_;
41 }
42 
44 {
45  auto & ctl = controller();
46 
47  if(ctl.externalFootstepPlanner.hasPlan(ExternalPlanner::DoubleSupport))
48  {
49  ctl.plan.resetContacts(ctl.externalFootstepPlanner.plan());
50  ctl.updatePlan("external");
51  }
52  else if(ctl.externalFootstepPlanner.planRequested(ExternalPlanner::DoubleSupport))
53  {
54  mc_rtc::log::warning("[{}] An external plan was requested for this DSP but is not available, pause walking",
55  name());
56  ctl.externalFootstepPlanner.cancelRequest();
57  stopDuringThisDSP_ = true;
58  ctl.pauseWalking = true;
59  }
60 }
61 
63 {
64  auto & ctl = controller();
65  ctl.walkingState = WalkingState::DoubleSupport;
66 
67  double phaseDuration = ctl.doubleSupportDuration(); // careful! side effect here
68 
69  duration_ = phaseDuration;
70  initLeftFootRatio_ = ctl.leftFootRatio();
71  if(phaseDuration <= ctl.timeStep)
72  {
73  mc_rtc::log::error_and_throw<std::invalid_argument>("[{}] The double support phase duration cannot be "
74  "less than the controller's timestep (requested {} <= {})",
75  name(), duration_, ctl.timeStep);
76  }
77  remTime_ = duration_;
78  stateTime_ = 0.;
79  stopDuringThisDSP_ = ctl.pauseWalking;
80  if(phaseDuration > ctl.timeStep)
81  {
82  timeSinceLastPreviewUpdate_ = 2 * PREVIEW_UPDATE_PERIOD; // update at transition...
83  }
84  else // ... unless DSP duration is zero
85  {
86  timeSinceLastPreviewUpdate_ = 0.;
87  }
88 
89  if(ctl.plan.name == "external")
90  {
91  handleExternalPlan();
92  }
93 
94  const std::string & targetSurfaceName = ctl.targetContact().surfaceName;
95  auto actualTargetPose = ctl.controlRobot().surfacePose(targetSurfaceName);
96  ctl.plan.goToNextFootstep(actualTargetPose);
97 
98  if(ctl.isLastDSP()) // called after goToNextFootstep
99  {
100  stopDuringThisDSP_ = true;
101  }
102 
103  if(ctl.prevContact().surfaceName == "LeftFootCenter")
104  {
105  ctl.setContacts({{ContactState::Left, ctl.prevContact().pose}, {ContactState::Right, ctl.supportContact().pose}});
106  targetLeftFootRatio_ = 0.;
107  }
108  else // (ctl.prevContact().surfaceName == "RightFootCenter")
109  {
110  ctl.setContacts({{ContactState::Left, ctl.supportContact().pose}, {ContactState::Right, ctl.prevContact().pose}});
111  targetLeftFootRatio_ = 1.;
112  }
113 
114  if(!ctl.isInOpenLoopTicker() && stateTime_ <= maxAbortPercent_ * duration_ && !checkInitialSupport())
115  {
116  mc_rtc::log::warning("[DoubleSupport] Stepping aborted at t = {}, poor contact detected!", stateTime_);
117  mc_rtc::log::info("[DoubleSupport] Stopping during this DSP, remaining time: {}", remTime_);
118  stopDuringThisDSP_ = true;
119  }
120 
121  if(stopDuringThisDSP_)
122  {
123  targetLeftFootRatio_ = 0.5;
124  }
125 
126  logger().addLogEntry("rem_phase_time", [this]() { return remTime_; });
127  logger().addLogEntry("walking_phase", []() { return 2.; });
128 
129  runState(); // don't wait till next cycle to update reference and tasks
130 }
131 
133 {
134  logger().removeLogEntry("rem_phase_time");
135  logger().removeLogEntry("walking_phase");
136 }
137 
139 {
140  auto & ctl = controller();
141  double dt = ctl.timeStep;
142 
143  if(remTime_ > 0 && timeSinceLastPreviewUpdate_ > PREVIEW_UPDATE_PERIOD
144  && !(stopDuringThisDSP_ && remTime_ < PREVIEW_UPDATE_PERIOD))
145  {
146  updatePreview();
147  }
148 
149  double x = clamp(remTime_ / duration_, 0., 1.);
150  ctl.leftFootRatio(x * initLeftFootRatio_ + (1. - x) * targetLeftFootRatio_);
151 
152  ctl.preview->integrate(pendulum(), dt);
153  pendulum().completeIPM(ctl.prevContact().p(), ctl.prevContact().normal());
154  pendulum().resetCoMHeight(ctl.plan.comHeight(), ctl.prevContact().p(), ctl.prevContact().normal());
155  controller().stabilizer()->target(pendulum().com(), pendulum().comd(), pendulum().comdd(), pendulum().zmp());
156 
157  remTime_ -= dt;
158  stateTime_ += dt;
159  timeSinceLastPreviewUpdate_ += dt;
160 }
161 
163 {
164  auto & ctl = controller();
165 
166  if(!stopDuringThisDSP_ && remTime_ < 0.)
167  {
168  output("SingleSupport");
169  return true;
170  }
171  if(stopDuringThisDSP_ && remTime_ < -0.5)
172  {
173  if(!ctl.isLastDSP())
174  {
175  ctl.plan.restorePreviousFootstep(); // current one is for next SSP
176  }
177  output("Standing");
178  return true;
179  }
180  return false;
181 }
182 
184 {
185  auto & ctl = controller();
186  ctl.mpc().contacts(ctl.prevContact(), ctl.supportContact(), ctl.targetContact());
187  if(stopDuringThisDSP_)
188  {
189  ctl.mpc().phaseDurations(0., remTime_, 0.);
190  }
191  else
192  {
193  ctl.mpc().phaseDurations(0., remTime_, ctl.singleSupportDuration());
194  }
195  if(ctl.updatePreview())
196  {
197  timeSinceLastPreviewUpdate_ = 0.;
198  }
199  else
200  {
201  mc_rtc::log::warning("No capture trajectory, resuming walking");
202  stopDuringThisDSP_ = false;
203  }
204 }
205 
206 } // namespace lipm_walking
207 
208 EXPORT_SINGLE_STATE("LIPMWalking::DoubleSupport", lipm_walking::states::DoubleSupport)
mc_tasks::lipm_stabilizer::ContactState ContactState
Definition: Contact.h:46
constexpr double PREVIEW_UPDATE_PERIOD
Definition: Controller.h:55
double clamp(double v, double vMin, double vMax)
Definition: clamp.h:47
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Controller & controller()
Definition: State.h:47