28 #include <mc_rtc/gui.h>
37 inline double floorn(
double x,
int n)
39 return floor(pow(10, n) * x) / pow(10, n);
47 {
"Markers",
"Footsteps",
"PlanInterpolator"},
48 Trajectory(
"Support_Path", [
this]() ->
const std::vector<Eigen::Vector3d> & {
return supportPathDisplay_; }),
50 "World target [m, rad]",
51 [
this]() -> Eigen::VectorXd
53 Eigen::Vector3d targetLocal;
54 targetLocal << targetPose_.pos(), 0.;
55 Eigen::Matrix3d rotLocal = mc_rbdyn::rpyToMat({0., 0., targetPose_.theta});
56 sva::PTransformd targetWorld = sva::PTransformd(rotLocal, targetLocal) * worldReference_;
57 double thetaWorld = mc_rbdyn::rpyFromMat(targetWorld.rotation()).z();
58 Eigen::VectorXd vec(4);
59 vec <<
floorn(targetWorld.translation().x(), 4),
floorn(targetWorld.translation().y(), 4),
60 floorn(thetaWorld, 4), worldReference_.translation().z();
66 {
"Walking",
"Footsteps",
"PlanInterpolator"},
68 "Gait", {
"Walk",
"Shuffle",
"Turn"}, [
this]() {
return gait(); },
69 [
this](
const std::string & dir) {
gait(dir); }),
71 "Lead foot", {
"Left",
"Right"},
72 [
this]() -> std::string {
return (startWithRightFootstep_) ?
"Right" :
"Left"; },
73 [
this](
const std::string & footName)
75 startWithRightFootstep_ = (footName ==
"Right");
79 "Desired step angle [deg]", [
this]() {
return desiredStepAngle_ * 180. / M_PI; },
80 [
this](
double angleDeg)
86 "Desired step length [m]", [
this]() {
return desiredStepLength_; },
89 bool isLateral = (customPlan_.name ==
"custom_lateral");
95 "Extra step width [m]", [
this]() {
return extraStepWidth_; },
102 "Initial tangent [deg]", [
this]() {
return -initPose_.theta * 180. / M_PI; },
105 initPose_.theta =
clamp(-angle * M_PI / 180., -2 * M_PI, 2 * M_PI);
109 "Scale initial tangent", [
this]() {
return supportPath_.extraInitVelScaling(); },
112 supportPath_.extraInitVelScaling(s);
116 "Scale target tangent", [
this]() {
return supportPath_.extraTargetVelScaling(); },
119 supportPath_.extraTargetVelScaling(s);
123 "Walk target from current", {
"x [m]",
"y [m]",
"theta [deg]"},
124 [
this]() {
return targetPose_.vectorDegrees(); },
125 [
this](
const Eigen::Vector3d & desired)
130 Label(
"Number of steps", [
this]() {
return nbFootsteps_; }),
131 Label(
"Step angle [deg]", [
this]() {
return std::round(stepAngle_ * 180. / M_PI * 10.) / 10.; }),
132 Label(
"Step length [m]", [
this]() {
return std::round(stepLength_ * 1000.) / 1000.; }),
133 Label(
"Total length [m]", [
this]() {
return std::round(supportPath_.arcLength(0., 1.) * 1000.) / 1000.; }));
138 gui_->removeCategory({
"Walking",
"Footsteps",
"PlanInterpolator"});
139 gui_->removeCategory({
"Markers",
"Footsteps",
"PlanInterpolator"});
140 gui_->removeCategory({
"Walking",
"Footsteps",
"PlanInterpolator",
"Online"});
145 Eigen::Vector3d posWorld;
146 posWorld << desired(0), desired(1), worldReference_.translation().z();
147 Eigen::Matrix3d rotWorld = mc_rbdyn::rpyToMat({0., 0., desired(2)});
148 sva::PTransformd X_desired(rotWorld, posWorld);
150 sva::PTransformd targetLocal = X_desired * worldReference_.inv();
151 double thetaLocal = mc_rbdyn::rpyFromMat(targetLocal.rotation()).z();
152 const Eigen::Vector3d & posLocal = targetLocal.translation();
167 double absX = std::abs(targetPose_.
x);
168 double absY = std::abs(targetPose_.
y);
182 for(
auto name : {
"custom_backward",
"custom_forward",
"custom_lateral",
"external"})
184 if(!plans_.has(name))
186 mc_rtc::log::error(
"[PlanInterpolator] Configuration lacks \"{}\" plan, skipping...", name);
189 customPlan_ = plans_(name);
194 mc_rtc::log::error(
"Wrong initial foothold order in \"{}\" plan", name);
196 sva::PTransformd X_0_mid = sva::interpolate(leftFoot.
pose, rightFoot.
pose, 0.5);
197 if(!X_0_mid.rotation().isIdentity() || X_0_mid.translation().norm() > 1e-4)
199 mc_rtc::log::error(
"Invalid X_0_mid(\"{}\") = {}", name, X_0_mid);
204 desiredStepLength_ = plans_(
"custom_forward")(
"step_length");
205 customPlan_ = plans_(
"custom_forward");
206 customPlan_.
name =
"custom_forward";
212 if(targetPose_.
pos().norm() < 2e-3)
227 double dx = targetPose_.
x;
228 if(dx < 0. && customPlan_.
name !=
"custom_backward")
230 desiredStepLength_ = plans_(
"custom_backward")(
"step_length");
233 else if(dx >= 0. && customPlan_.
name !=
"custom_forward")
235 desiredStepLength_ = plans_(
"custom_forward")(
"step_length");
242 if(customPlan_.
name !=
"custom_lateral")
244 desiredStepLength_ = plans_(
"custom_lateral")(
"step_length");
251 if(customPlan_.
name !=
"custom_lateral")
253 desiredStepLength_ = plans_(
"custom_lateral")(
"step_length");
261 void PlanInterpolator::runWalking_()
263 bool goingBackward = (targetPose_.
pos().x() < 0.);
266 customPlan_ = plans_(
"custom_backward");
267 customPlan_.
name =
"custom_backward";
268 supportPath_.
reset(initPose_.
pos(), -initPose_.
ori(), targetPose_.
pos(), -targetPose_.
ori());
269 lastBackwardTarget_ = targetPose_;
273 customPlan_ = plans_(
"custom_forward");
274 customPlan_.
name =
"custom_forward";
275 supportPath_.
reset(initPose_.
pos(), initPose_.
ori(), targetPose_.
pos(), targetPose_.
ori());
276 lastForwardTarget_ = targetPose_;
278 if(!startWithRightFootstep_)
284 double totalLength = supportPath_.
arcLength(0., 1.);
285 unsigned nbInnerSteps =
static_cast<unsigned>(std::max(0., std::round(totalLength / desiredStepLength_) - 1));
286 double maxStepLength = 1.1 * desiredStepLength_;
287 if(totalLength / (nbInnerSteps + 1) > maxStepLength)
291 double innerStepLength = totalLength / (nbInnerSteps + 1);
292 double innerVel = (goingBackward ? -1. : +1.) * innerStepLength / T;
293 double outerStepLength;
297 outerStepLength = 0.5 * innerStepLength;
298 outerVel = 0.5 * innerVel;
300 stepLength_ = innerStepLength;
304 outerStepLength = totalLength;
307 stepLength_ = totalLength;
311 bool isRightFootstep = startWithRightFootstep_;
312 unsigned nbFinalSteps = 0;
313 double freeLength = outerStepLength;
314 double curVel = outerVel;
315 while(nbFinalSteps < 2)
317 double length = freeLength;
318 double curStepWidth = stepWidth_ + extraStepWidth_;
319 if(length > totalLength - outerStepLength - 1e-3)
323 if(length >= totalLength - 1e-3)
325 curStepWidth = stepWidth_;
327 length = totalLength;
332 Eigen::Vector2d supportPoint = supportPath_.
pos(t);
333 Eigen::Vector2d supportTangent = supportPath_.
tangent(t);
336 supportTangent *= -1.;
338 Eigen::Vector2d supportNormal = {-supportTangent.y(), supportTangent.x()};
339 double sign = (isRightFootstep) ? -1. : +1.;
340 double dy = 0.5 * sign * curStepWidth;
341 double theta = atan2(supportTangent.y(), supportTangent.x());
342 Eigen::Vector2d p = supportPoint + dy * supportNormal;
343 SE2d stepPose = {p.
x(), p.y(), theta};
346 contact.pose = stepPose.asPTransform();
347 contact.refVel = curVel * Eigen::Vector3d{supportTangent.x(), supportTangent.y(), 0.};
348 contact.surfaceName = (isRightFootstep) ?
"RightFootCenter" :
"LeftFootCenter";
350 isRightFootstep = !isRightFootstep;
352 freeLength += innerStepLength;
358 if(nbFootsteps_ - 3 != nbInnerSteps)
360 mc_rtc::log::error(
"[PlanInterpolator] Footstep count check failed");
362 if(std::abs(2 * outerStepLength + nbInnerSteps * innerStepLength - totalLength) > 1e-4)
364 mc_rtc::log::error(
"[PlanInterpolator] Total length check failed");
369 if(nbFootsteps_ != 2)
371 mc_rtc::log::error(
"[PlanInterpolator] Footstep count check failed");
373 if(std::abs(outerStepLength - totalLength) > 1e-4)
375 mc_rtc::log::error(
"[PlanInterpolator] Total length check failed");
380 void PlanInterpolator::runShuffling_()
382 customPlan_ = plans_(
"custom_lateral");
383 customPlan_.
name =
"custom_lateral";
384 lastLateralTarget_ = targetPose_;
385 supportPath_.
reset(initPose_.
pos(), initPose_.
ori(), targetPose_.
pos(), targetPose_.
ori());
387 std::string leadFootSurfaceName, followFootSurfaceName;
388 bool goingToTheRight = (targetPose_.
pos().y() < 0.);
391 leadFootSurfaceName =
"RightFootCenter";
392 followFootSurfaceName =
"LeftFootCenter";
393 startWithRightFootstep_ =
true;
397 leadFootSurfaceName =
"LeftFootCenter";
398 followFootSurfaceName =
"RightFootCenter";
400 startWithRightFootstep_ =
false;
403 double totalLength = supportPath_.
arcLength(0., 1.);
404 double nbSteps = std::max(1., std::round(totalLength / desiredStepLength_));
405 double maxStepLength = 1.1 * desiredStepLength_;
406 if(totalLength / nbSteps > maxStepLength)
410 double stepLength = totalLength / nbSteps;
413 for(
unsigned i = 1; i <= nbSteps; i++)
415 double curStepWidth = stepWidth_;
418 curStepWidth += extraStepWidth_;
421 Eigen::Vector2d supportPoint = supportPath_.
pos(t);
422 double theta = t * targetPose_.
theta;
423 Eigen::Vector2d lateralVec = {-std::sin(theta), std::cos(theta)};
424 lateralVec *= (goingToTheRight ? -1. : +1.) * 0.5 * curStepWidth;
425 Eigen::Vector2d leadPos = supportPoint + lateralVec;
426 Eigen::Vector2d followPos = supportPoint - lateralVec;
427 SE2d leadStepPose = {leadPos.
x(), leadPos.y(), theta};
428 SE2d followStepPose = {followPos.
x(), followPos.y(), theta};
430 Contact followStep, leadStep;
431 followStep.pose = followStepPose.asPTransform();
432 followStep.surfaceName = followFootSurfaceName;
433 leadStep.pose = leadStepPose.asPTransform();
434 leadStep.surfaceName = leadFootSurfaceName;
441 stepLength_ = stepLength;
444 void PlanInterpolator::runTurning_()
446 lastLateralTarget_ = targetPose_;
447 customPlan_ = plans_(
"custom_lateral");
448 customPlan_.
name =
"custom_lateral";
449 supportPath_.
reset(initPose_.
pos(), initPose_.
ori(), targetPose_.
pos(), targetPose_.
ori());
451 std::string leadFootSurfaceName, followFootSurfaceName;
452 bool goingToTheRight = (targetPose_.
theta < 0.);
455 leadFootSurfaceName =
"RightFootCenter";
456 followFootSurfaceName =
"LeftFootCenter";
457 startWithRightFootstep_ =
true;
461 leadFootSurfaceName =
"LeftFootCenter";
462 followFootSurfaceName =
"RightFootCenter";
464 startWithRightFootstep_ =
false;
467 double totalAngle = std::abs(targetPose_.
theta);
468 double nbSteps = std::max(1., std::round(totalAngle / desiredStepAngle_));
469 double maxStepAngle = 1.0 * desiredStepAngle_;
470 if(totalAngle / nbSteps > maxStepAngle)
474 double stepAngle = totalAngle / nbSteps;
477 for(
unsigned i = 1; i <= nbSteps; i++)
479 double curStepWidth = stepWidth_;
482 curStepWidth += extraStepWidth_;
484 double theta = (goingToTheRight ? -1. : +1.) * i * stepAngle;
485 Eigen::Vector2d supportPoint = targetPose_.
pos();
486 Eigen::Vector2d lateralVec = {-std::sin(theta), std::cos(theta)};
487 lateralVec *= (goingToTheRight ? -1. : +1.) * 0.5 * curStepWidth;
488 Eigen::Vector2d leadPos = supportPoint + lateralVec;
489 Eigen::Vector2d followPos = supportPoint - lateralVec;
490 SE2d leadStepPose = {leadPos.
x(), leadPos.y(), theta};
491 SE2d followStepPose = {followPos.
x(), followPos.y(), theta};
493 Contact followStep, leadStep;
494 followStep.pose = followStepPose.asPTransform();
495 followStep.surfaceName = followFootSurfaceName;
496 leadStep.pose = leadStepPose.asPTransform();
497 leadStep.surfaceName = leadFootSurfaceName;
503 stepAngle_ = stepAngle;
509 constexpr
double PATH_STEP = 0.05;
510 sva::PTransformd X_0_mid = sva::interpolate(X_0_lf, X_0_rf, 0.5);
511 supportPathDisplay_.clear();
512 for(
double s = 0.; s <= 1.; s += PATH_STEP)
514 Eigen::Vector2d p = supportPath_.
pos(s);
515 SE2d pose = {p.
x(), p.y(), 0.};
516 sva::PTransformd X_0_p = pose * X_0_mid;
517 supportPathDisplay_.push_back(X_0_p.translation());
521 void PlanInterpolator::restoreDefaults()
524 initPose_.
theta = 0.;
525 startWithRightFootstep_ =
true;
double floorn(double x, int n)
double clamp(double v, double vMin, double vMax)
void configure(const mc_rtc::Configuration &config)
static constexpr double DEFAULT_EXTRA_STEP_WIDTH
void updateLocalTarget_(const SE2d &target)
static constexpr double IN_PLACE_MAX_STEP_ANGLE
static constexpr double MIN_STEP_LENGTH
std::string gait() const noexcept
static constexpr double MAX_SAGITTAL_STEP_LENGTH
static constexpr double MAX_LATERAL_STEP_LENGTH
static constexpr double MAX_EXTRA_STEP_WIDTH
static constexpr double IN_PLACE_EXTRA_STEP_WIDTH
void updateSupportPath(const sva::PTransformd &X_0_lf, const sva::PTransformd &X_0_rf)
void updateWorldTarget_(const Eigen::Vector3d &desired)
lipm_walking::utils::SE2d SE2d
Eigen::Vector2d ori() const
Eigen::Vector2d pos() const
double extraInitVelScaling()
double extraTargetVelScaling()
T tangent(double t) const
double arcLengthInverse(double t_start, double length, double t_guess=-1.) const
double arcLength(double t_start, double t_end) const