ethz-adrl / towr

A light-weight, Eigen-based C++ library for trajectory optimization for legged robots.
http://wiki.ros.org/towr
BSD 3-Clause "New" or "Revised" License
908 stars 227 forks source link

Advice on how to decrease unrealistic contact forces between spline nodes #77

Closed ferrolho closed 4 years ago

ferrolho commented 4 years ago

Hi, @awinkler! I am trying to compute a 2-seconds-long jump for a quadruped, but unfortunately the solver converges to a solution with unrealistic contact forces. Please see the animation below.

animation

I am aware that this is because the formulation only ensures unilaterality and forces within the friction cones at the nodes of the polynomials but not in between. You do mention this in the towr::ForceConstraint documentation:

Attention: Constraint is enforced only at the spline nodes. In between violations of this constraint can occur.

However, I am wondering if you have any tips on how to formulate the problem in a way that avoids these unrealistic forces.

For the sake of completion, I will detail the changes I made to the current version of the codebase. I added a new gait for the jump:

case C5: SetGaits({Stand, Hop2, Stand}); break;  // jump

The Stand phase duration is still set to 0.3 (no changes to this line), but I changed the times of the Hop2 (GetStridePronk() method defined here) to:

QuadrupedGaitGenerator::GetStridePronk () const
{
  double push   = 0.5;
  double flight = 0.4;
  double land   = 0.5;
(...)

Therefore, for the new gait C5, the default timings are 0.3 + 0.5 + 0.4 + 0.5 + 0.3 = 2.0. The settings in the interface are:

Screenshot from 2020-08-01 20-36-49

I have also tried to add more and shorter Stand phases before and after the Hop2, e.g., Stand, Stand, Stand, Hop2, Stand, Stand, Stand and changing the Stand time to 0.1, but I had no luck. I was hoping that having more phases would allow to have more nodes in the same time interval as before, therefore leading to a formulation with more constraints enforcing the unilaterality more often.

I also tried increasing duration_base_polynomial_ slightly, or to decrease force_polynomials_per_stance_phase_ from 3 to 2, as you mention here. I am trying to avoid adding a cost because that slows down convergence, but maybe that is the way to solve this?

Thank you in advance! :slightly_smiling_face:

awinkler commented 4 years ago

hmmm, adding multiple Stand phases behind each other will still only be parameterized as one long stand phase if i'm not mistaken. And if that stand phase gets longer, while still being parameterized by the same number of polynomials, the less "freedom per time" that polynomial has. I could imagine in this scenario the solver needs a very abrupte change in the force profile to cause that long of a flight-phase. To give it that freedom, you could try to reduce the stand time before and after, so that the force polynomials don't have to simultaneously model standing in the place and also then changing abruptly. Their expressiveness is sort of concentrated on a shorter time interval.

But as you rightfully investigated, this is not so easy to do, and you already turned on some of the knobs i would have tried as well.

ferrolho commented 4 years ago

adding multiple Stand phases behind each other will still only be parameterized as one long stand phase if i'm not mistaken.

I was not aware of this. I stacked multiple Stand phases similarly to how you stack other types of phases: https://github.com/ethz-adrl/towr/blob/a211e01a25b8950ec6eded9d828edaaa5e055f90/towr/src/quadruped_gait_generator.cc#L80-L84 The goal was to prolong the "standing" time before the jump, similarly to how the lines above prolong locomotion trajectories.

Indeed, if the formulation of multiple Stand phases stacked to each other results in only one very long phase, then it is true that the polynomial will have less "freedom per time" to model the forces required for the jump. But my initial idea for having multiple Stand phases was precisely to allow the solver to have a long polynomial modelling the initial standing time, and then another polynomial to model the abrupt changes in force required for the jump take-off.

I think we should make a conclusion note here for future readers: while it is true that the unilaterality and forces within the friction cones are only enforced at the spline nodes and not in between, that does not seem to be the "crux" for modelling this jumping task; rather, the crux seems to be related to the limited expressiveness of each phase's polynomial.

I will have a look at the codebase myself now, but do you know if it would be easy to change the code to not reduce stacks of Stand phases to only one long Stand phase? I believe that may be the right way to achieve this, rather than trying to turn more knobs. :stuck_out_tongue:

ferrolho commented 4 years ago

adding multiple Stand phases behind each other will still only be parameterized as one long stand phase if i'm not mistaken.

I can confirm you were not mistaken. The lines below are responsible for merging phases from the pre-specified gait if they do not involve a change in contact state for any of the feet: https://github.com/ethz-adrl/towr/blob/7193d66af21df61d1811f495a216c33bf22e700c/towr/src/gait_generator.cc#L90-L95

I tried my luck by forcing the body of the if statement to always run:

// bool contacts_will_change = curr.at(ee) != next.at(ee);
bool contacts_will_change = true;

which did stop the merging of the Stand phases.

I verified this by checking the size of params.ee_phase_durations_ for the first foot with

std::cout << "[DEBUG] params.ee_phase_durations_[0]: " << params.ee_phase_durations_[0].size() << std::endl;

just after the for loop https://github.com/ethz-adrl/towr/blob/d30c4a06a86e8378ce5dea813071d0ef6d04070b/towr_ros/src/towr_ros_app.cc#L73-L76

For the gait sequence Stand, Stand, Hop2, Stand, Stand, the output is

[DEBUG] params.ee_phase_durations_[0]: 7

which is correct because Stand has only one BB_ phase, and Hop2 has three phases: BB_, II_, BB_.

Unfortunately, this still did not produce the trajectory I was hoping for, and there seem to be some extra flight phases that are not specified in the gait sequence. Please see the animation below: animation

awinkler commented 4 years ago

Well, I don’t think treating multiple stand phases as separate makes sense. This way of specifying the gait was really just a helper class. I think if we want to give more freedom to the polynomials representing the stand phases, we should use more force polynomials per stand phase (as you already correctly tried). The position polynomial for the stance phase is fixed anyway, so there is no need to use multiple of those.

So this really just brings us back to your initial comment comment; don’t see a robust/deterministic fix for that...

ferrolho commented 4 years ago

I agree with your remarks, @awinkler. I will now close this issue. Thank you for your help and feedback.

Final note for future readers: I don't want to leave prospect users of TOWR with a bad impression. Let me emphasise that the issue discussed above is really only a setback if the duration of the trajectory is longer than the expressiveness of the polynomials available. For shorter trajectories, TOWR works really well! See the 1-second-long jump below, with well-behaved forces, and for which the solver converges in ~10 iterations. :slightly_smiling_face: animation