DDP reformulation question

Hi :wave:

i’m trying to use the new DDP solver inside acados. I have added to my code the following lines:

ocp.solver_options.nlp_solver_type = ‘DDP’
ocp.solver_options.globalization = ‘MERIT_BACKTRACKING’
ocp.solver_options.with_adaptive_levenberg_marquardt = True
ocp.translate_to_feasibility_problem()

Now, in my problem, I have con_h_expr constraints (20) and linear cost.
When I call ocp.translate_to_feasibility_problem() I obtain the following error:

Exception: (‘inconsistent dimension: regarding W, yref.\nGot W[(20, 20)], yref[(74,)],’, ‘cost_y_expr[20]\n’)

during the check cost.yref.shape[0] != ny in here acados/interfaces/acados_template/acados_template/acados_ocp.py at 733bba361cdd8e777cead4a3c726036aab410e46 · acados/acados · GitHub

Now, yref is 54 (my states+inputs) + 20 the constraints, but ny is only 20. But before calling ocp.translate_to_feasibility_problem(), ny was 54.

As far as I understood, ocp.translate_to_feasibility_problem() removes all the previous cost term. Is there a way to define them again, or what should i do to preserve the old cost and add only the constraint as an additional one?

Thank you,
Giulio

Hi Giulio,

happy to hear that you are already trying out the new acados DDP solver!

I made a fix, resetting yref in translate_to_feasibility_problem.
Also, I added the option keep_cost to translate_to_feasibility_problem.

It would make sense to add options to the function to specify weights for all the constraints.
Would you be interested in contributing in this direction?

Best,
Jonathan

2 Likes

Thanks for the fast reply! I just tried your code, now I have the following:

AcadosOcpSolver.set(): mismatching dimension for field "yref" with dimension 30 (you have 54).

Without calling ocp.translate_to_feasibility_problem and DDP, normally I have 54 elements (30 states + 24 inputs).
What I’m doing is just the following

ocp.solver_options.nlp_solver_type = 'DDP'
ocp.solver_options.globalization = 'MERIT_BACKTRACKING'
ocp.solver_options.with_adaptive_levenberg_marquardt = True

ocp.cost.cost_type = 'NONLINEAR_LS'
ocp.cost.cost_type_e = 'NONLINEAR_LS'
ocp.model.cost_y_expr = cs.vertcat(ocp.model.x, ocp.model.u)
ocp.model.cost_y_expr_e = ocp.model.x
ocp.translate_to_feasibility_problem(keep_x0=False, keep_cost=True)

and at each control loop setting
self.acados_ocp_solver.set(j, "yref", yref)

(the error come from here).

Plus, I cannot really set the initial constraints _0 (basically I have some constraints for the input in the form of casadi func). Normally, this is handled well by the other solvers.

ocp.model.con_h_expr = expr_h_friction
ocp.constraints.uh = self.constr_uh_friction
ocp.constraints.lh = self.constr_lh_friction
ocp.model.con_h_expr_0 = expr_h_friction
ocp.constraints.uh_0 = self.constr_uh_friction
ocp.constraints.lh_0 = self.constr_lh_friction

Regarding the contribution, I’m tempted, the only constraint is time here :face_with_head_bandage:! But I would like to have a look!

Hi,

I think the translate_to_feasibility_problem function is not too hard to understand.
Since you have a nonlinear least squares cost formulation, and all constraints are formulated as penalties, basically a y entry is added for each constraint with reference value 0.0.
If you only want to set the yref values for your original cost, just set the yref values for the y entries added by the translation function to zero to leave them unchanged.
You can print the expression ocp.model.cost_y_expr after the translation to get a better understanding of this.

Cheers,
Jonathan

i noticed that in translate_to_feasibility_problem,

the following lines (1322-1323-1324) should be commented

otherwise the first step in acados_ocp_solver.set(0, “yref”, yref) contains only the constraints, and not anymore old_cost+constraints. (like for the other .set along the horizon).

Furthermore, I needed to put ocp.model.con_h_expr_0 = None, after calling the function translate_to_feasibility_problem, to avoid a size mismatch problem in the make_consistent() function.

If interested, the code about my specific problem is here:

Still, I notice strange behavior using DDP. When I leave keep_x0=True, I have a timing in some closed loop iter. of 0.001ms, and sometimes spikes to 0.008ms (even in this case, the robot does not walk as nicely as with sqp. But I feel something is missing). This strong variability in timing does not seem to happen with the variable keep_x0=False. (time is more or less consistent during the different calls, but the robot falls. This is for the case x0 is a variable itself, like in robust MPC I guess.)

Hi Giulio,

I addressed both things that you pointed out in the last comment in the pull request.

How do you use the DDP solver in closed loop?
I think that actually, we did not really test it yet.
If you formulate your problem with translate_to_feasibility_problem(keep_x0=False), it is not possible right now to update the initial state. Or how did you do that?
Thus, you basically always solve the same problem over and over, if you keep_x0=False, which should then give you a very consistent timing.
On the other hand, your initial state update probably is correct when you set keep_x0=True and the differences in runtime correspond to the solver requiring a varying number of iterations. I suggest printing the solver statistics to evaluate this.

I think, we should set up a minimal example with closed loop DDP in acados for reference!

Indeed, keep_x0=False had no sense in my case!
Anyway, thanks for the fix, I have just tried them. I found why I had the high randomicity in the timing:
disabling ocp.solver_options.globalization = ‘MERIT_BACKTRACKING’ made it much more consistent (from 1 to 2 ms). It even walks as good as with sqp now!