28 #include <mc_rbdyn/rpy_utils.h>
29 #include <mc_rtc/constants.h>
41 const mc_rtc::Configuration & config,
42 mc_control::ControllerParameters params)
43 :
mc_control::fsm::
Controller(robotModule, dt, config, params), planInterpolator(gui()), externalFootstepPlanner(*this),
44 halfSitPose(controlRobot().mbc().q)
46 auto robotConfig = config(
"robot_models")(
controlRobot().name());
47 auto planConfig = config(
"plans")(
controlRobot().name());
48 if(planConfig.has(
"external"))
53 mc_rtc::log::info(
"Loading default stabilizer configuration");
54 defaultStabilizerConfig_ = robot().module().defaultLIPMStabilizerConfiguration();
55 if(robotConfig.has(
"stabilizer"))
57 mc_rtc::log::info(
"Loading additional stabilizer configuration");
58 defaultStabilizerConfig_.load(robotConfig(
"stabilizer"));
63 std::vector<std::string> plans = planConfig.keys();
64 double comHeight = defaultStabilizerConfig_.comHeight;
65 for(
const auto & p : plans)
67 auto plan = planConfig(p);
68 if(!
plan.has(
"com_height"))
70 plan.add(
"com_height", comHeight);
74 double postureStiffness = config(
"tasks")(
"posture")(
"stiffness");
75 double postureWeight = config(
"tasks")(
"posture")(
"weight");
76 postureTask = getPostureTask(robot().name());
77 postureTask->stiffness(postureStiffness);
78 postureTask->weight(postureWeight);
81 const auto & halfSit = robotModule->stance();
82 const auto & refJointOrder = robot().refJointOrder();
83 for(
unsigned i = 0; i < refJointOrder.size(); ++i)
85 if(robot().hasJoint(refJointOrder[i]))
87 halfSitPose[robot().jointIndexByName(refJointOrder[i])] = halfSit.at(refJointOrder[i]);
92 sva::PTransformd X_0_lfc =
controlRobot().surfacePose(
"LeftFootCenter");
93 sva::PTransformd X_0_rfc =
controlRobot().surfacePose(
"RightFootCenter");
94 sva::PTransformd X_0_lf =
controlRobot().surfacePose(
"LeftFoot");
95 sva::PTransformd X_lfc_lf = X_0_lf * X_0_lfc.inv();
96 sva::PTransformd X_rfc_lfc = X_0_lfc * X_0_rfc.inv();
97 double stepWidth = X_rfc_lfc.translation().y();
98 sole_ = robotConfig(
"sole");
101 if(robotConfig(
"sole").has(
"leftAnkleOffset"))
111 mpcConfig_ = config(
"mpc");
121 new mc_tasks::lipm_stabilizer::StabilizerTask(
123 solver().realRobots(),
124 robot().robotIndex(),
125 defaultStabilizerConfig_.leftFootSurface,
126 defaultStabilizerConfig_.rightFootSurface,
127 defaultStabilizerConfig_.torsoBodyName,
130 stabilizer_->configure(defaultStabilizerConfig_);
136 config(
"initial_plan", initialPlan);
142 double swingWeight = 1000;
143 double swingStiffness = 500;
144 if(robotConfig.has(
"swingfoot"))
146 robotConfig(
"swingfoot")(
"weight", swingWeight);
147 robotConfig(
"swingfoot")(
"stiffness", swingStiffness);
149 swingFootTaskRight_.reset(
new mc_tasks::SurfaceTransformTask(
"RightFootCenter", robots(), robots().robotIndex(),
150 swingWeight, swingStiffness));
151 swingFootTaskLeft_.reset(
new mc_tasks::SurfaceTransformTask(
"LeftFootCenter", robots(), robots().robotIndex(),
152 swingWeight, swingStiffness));
164 datastore().make_call(
"KinematicAnchorFrame::" + robot().name(),
165 [
this](
const mc_rbdyn::Robot & robot)
167 return sva::interpolate(robot.surfacePose(
"RightFootCenter"),
168 robot.surfacePose(
"LeftFootCenter"), leftFootRatio_);
171 mc_rtc::log::success(
"LIPMWalking controller init done.");
176 logger.addLogEntry(
"controlRobot_LeftFoot", [
this]() {
return controlRobot().surfacePose(
"LeftFoot"); });
177 logger.addLogEntry(
"controlRobot_LeftFootCenter", [
this]() {
return controlRobot().surfacePose(
"LeftFootCenter"); });
178 logger.addLogEntry(
"controlRobot_RightFoot", [
this]() {
return controlRobot().surfacePose(
"RightFoot"); });
179 logger.addLogEntry(
"controlRobot_RightFootCenter",
180 [
this]() {
return controlRobot().surfacePose(
"RightFootCenter"); });
181 logger.addLogEntry(
"mpc_failures", [
this]() {
return nbMPCFailures_; });
182 logger.addLogEntry(
"left_foot_ratio", [
this]() {
return leftFootRatio_; });
184 logger.addLogEntry(
"plan_com_height", [
this]() {
return plan.
comHeight(); });
189 logger.addLogEntry(
"plan_landing_pitch", [
this]() {
return plan.
landingPitch(); });
192 logger.addLogEntry(
"plan_swing_height", [
this]() {
return plan.
swingHeight(); });
194 logger.addLogEntry(
"plan_takeoff_offset", [
this]() {
return plan.
takeoffOffset(); });
195 logger.addLogEntry(
"plan_takeoff_pitch", [
this]() {
return plan.
takeoffPitch(); });
196 logger.addLogEntry(
"realRobot_LeftFoot", [
this]() {
return realRobot().surfacePose(
"LeftFoot"); });
197 logger.addLogEntry(
"realRobot_LeftFootCenter", [
this]() {
return realRobot().surfacePose(
"LeftFootCenter"); });
198 logger.addLogEntry(
"realRobot_RightFoot", [
this]() {
return realRobot().surfacePose(
"RightFoot"); });
199 logger.addLogEntry(
"realRobot_RightFootCenter", [
this]() {
return realRobot().surfacePose(
"RightFootCenter"); });
200 logger.addLogEntry(
"realRobot_posW", [
this]() {
return realRobot().posW(); });
209 mc_rtc::gui::Point3D(
"Target Ankle Pos", [
this]() {
return this->
targetContact().
anklePos(sole_); }),
212 gui->addElement({
"Walking",
"Main"},
213 Button(
"# EMERGENCY STOP",
216 mc_rtc::log::error(
"EMERGENCY STOP!");
223 mc_rtc::log::warning(
"Reset to Initial state");
224 this->resume(
"Initial");
227 gui->addElement({
"Walking",
"CoM"}, Label(
"Plan name", [
this]() {
return plan.
name; }));
229 gui->addElement({
"Walking",
"Swing"}, Label(
"Plan name", [
this]() {
return plan.
name; }),
246 gui->addElement({
"Walking",
"Timings"}, Label(
"Plan name", [
this]() {
return plan.
name; }),
252 [
this](
double duration)
255 duration = std::round(duration / T) * T;
260 [
this](
double duration)
263 duration = std::round(duration / T) * T;
271 mc_rtc::gui::Label(
"Ankle offset",
275 "position of ankle w.r.t to left foot center. The corresponding offset for the right "
276 "foot is computed assuming that the feet are symetrical in the lateral direction"};
278 mc_rtc::gui::ArrayInput(
279 "Left Ankle Offset", [
this]() ->
const Eigen::Vector2d & {
return sole_.leftAnkleOffset; },
280 [
this](
const Eigen::Vector2d & offset)
282 sole_.leftAnkleOffset = offset;
285 mc_rtc::gui::ArrayLabel(
"Right Ankle Offset",
286 [
this]() -> Eigen::Vector2d {
287 return {sole_.leftAnkleOffset.x(), -sole_.leftAnkleOffset.y()};
289 mc_rtc::gui::ArrayLabel(
"Sole half width/length",
291 return Eigen::Vector2d{sole_.halfWidth, sole_.halfLength};
299 config()(
"observerPipelineName", observerPipelineName_);
300 if(!hasObserverPipeline(observerPipelineName_))
302 mc_rtc::log::error_and_throw<std::runtime_error>(
"LIPMWalking requires an observer pipeline named \"{}\"",
303 observerPipelineName_);
306 mc_control::fsm::Controller::reset(data);
308 stabilizer_->reset();
313 gui_->removeCategory({
"Contacts"});
318 const std::vector<std::pair<mc_tasks::lipm_stabilizer::ContactState, sva::PTransformd>> & contacts,
322 auto rName = robot().name();
323 auto gName =
"ground";
324 auto gSurface =
"AllGround";
325 auto friction =
stabilizer()->config().friction;
326 removeContact({rName, gName,
stabilizer()->footSurface(mc_tasks::lipm_stabilizer::ContactState::Left), gSurface});
327 removeContact({rName, gName,
stabilizer()->footSurface(mc_tasks::lipm_stabilizer::ContactState::Right), gSurface});
328 for(
const auto & contact : contacts)
330 const auto & rSurface =
stabilizer()->footSurface(contact.first);
331 Eigen::Vector6d dof = Eigen::Vector6d::Ones();
338 addContact({rName, gName, rSurface, gSurface, friction, dof});
345 if(std::abs(ratio - leftFootRatio_) > maxRatioVar)
347 mc_rtc::log::warning(
"Left foot ratio jumped from {} to {}", leftFootRatio_, ratio);
349 leftFootRatio_ =
clamp(ratio, 0., 1.,
"leftFootRatio");
354 const auto & observerp = observerPipeline(observerPipelineName_);
355 if(!observerp.success())
357 mc_rtc::log::error(
"Required pipeline \"{}\" for real robot observation failed to run!", observerPipelineName_);
358 for(
const auto & observer : observerp.observers())
360 if(!observer.success())
362 mc_rtc::log::error(
"Observer \"{}\" failed with error \"{}\"", observer.observer().name(),
363 observer.observer().error());
376 if(!mc_control::fsm::Controller::running())
378 return mc_control::fsm::Controller::run();
381 ctlTime_ += timeStep;
385 bool ret = mc_control::fsm::Controller::run();
395 constexpr
double MAX_HEIGHT_DIFF = 0.02;
398 mc_rtc::log::warning(
"Already pausing, how did you get there?");
405 mc_rtc::log::warning(
"Cannot pause on uneven ground, will pause later");
407 gui()->removeElement({
"Walking",
"Main"},
"Pause walking");
412 mc_rtc::log::warning(
"Pausing now that contacts are at same level");
418 gui()->removeElement({
"Walking",
"Main"},
"Pause walking");
425 static bool isInTheAir =
false;
426 constexpr
double CONTACT_THRESHOLD = 30.;
427 double leftFootForce = realRobot().forceSensor(
"LeftFootForceSensor").force().z();
428 double rightFootForce = realRobot().forceSensor(
"RightFootForceSensor").force().z();
429 if(leftFootForce < CONTACT_THRESHOLD && rightFootForce < CONTACT_THRESHOLD)
433 mc_rtc::log::warning(
"Robot is in the air");
441 mc_rtc::log::info(
"Robot is on the ground again");
449 bool loadingNewPlan = (
plan.
name != name);
468 const sva::PTransformd & X_0_lf =
controlRobot().surfacePose(
"LeftFootCenter");
469 const sva::PTransformd & X_0_rf =
controlRobot().surfacePose(
"RightFootCenter");
476 stabilizer_->torsoPitch(torsoPitch);
481 mc_rtc::log::info(
"Loaded footstep plan \"{}\"", name);
487 if(name ==
"external")
500 if(name.find(
"custom") != std::string::npos)
503 if(name.find(
"backward") != std::string::npos)
507 else if(name.find(
"forward") != std::string::npos)
511 else if(name.find(
"lateral") != std::string::npos)
525 if(segmentName_.length() > 0)
529 segmentName_ =
"t_" + std::to_string(++nbLogSegments_).erase(0, 1) +
"_" + label;
530 logger().addLogEntry(segmentName_, [
this]() {
return ctlTime_; });
535 logger().removeLogEntry(segmentName_);
557 return gui()->hasElement({
"Ticker"},
"Stop") && !datastore().has(
"Log::Replay");
double clamp(double v, double vMin, double vMax)
mc_rbdyn::Robot & controlRobot()
bool pauseWalkingRequested
double measuredLeftFootRatio()
const Contact & targetContact()
virtual bool run() override
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Controller(mc_rbdyn::RobotModulePtr robot, double dt, const mc_rtc::Configuration &config, mc_control::ControllerParameters params={})
std::shared_ptr< mc_tasks::lipm_stabilizer::StabilizerTask > stabilizer()
void updatePlan(const std::string &name)
const Contact & supportContact()
std::vector< std::vector< double > > halfSitPose
void loadFootstepPlan(std::string name)
void addGUIElements(std::shared_ptr< mc_rtc::gui::StateBuilder > gui)
bool isInOpenLoopTicker() const
void warnIfRobotIsInTheAir()
std::shared_ptr< mc_tasks::SurfaceTransformTask > swingFootTaskLeft_
std::shared_ptr< Preview > preview
void pauseWalkingCallback(bool verbose=false)
void setContacts(const std::vector< std::pair< mc_tasks::lipm_stabilizer::ContactState, sva::PTransformd >> &contacts, bool fullDoF=false)
void addLogEntries(mc_rtc::Logger &logger)
mc_planning::Pendulum & pendulum()
void startLogSegment(const std::string &label)
void reset(const mc_control::ControllerResetData &data) override
PlanInterpolator planInterpolator
std::shared_ptr< mc_tasks::SurfaceTransformTask > swingFootTaskRight_
ExternalPlanner externalFootstepPlanner
Handle requesting/receiving plans from an external planner.
void configure(const mc_rtc::Configuration &config)
External planning configuration.
void addLogEntries(mc_rtc::Logger &logger)
void addGUIElements(std::shared_ptr< mc_rtc::gui::StateBuilder > gui)
const std::shared_ptr< Preview > solution() const
void initState(const mc_planning::Pendulum &pendulum)
static constexpr EIGEN_MAKE_ALIGNED_OPERATOR_NEW double SAMPLING_PERIOD
void comHeight(double height)
void configure(const mc_rtc::Configuration &)
void sole(const Sole &sole)
void configure(const mc_rtc::Configuration &config)
void restoreLateralTarget()
const sva::PTransformd & worldReference() const
void restoreForwardTarget()
void restoreBackwardTarget()
FootstepPlan getPlan(std::string name)
std::vector< std::string > availablePlans() const
void updateSupportPath(const sva::PTransformd &X_0_lf, const sva::PTransformd &X_0_rf)
const std::string & customPlanName() const
EIGEN_MAKE_ALIGNED_OPERATOR_NEW Eigen::Vector2d leftAnkleOffset