Input parameters to acados simulation

Hello,
I have been writing a code to simulate a model with input parameters. My approach worked with solving the problem as an OCP problem but not when using integrators to simulate.

Here is the code:

clear all

model_path=fullfile(pwd,'..','myCartPoleRefGenModelALL')

addpath(model_path)

check_acados_requirements()

T=1;

N=50;

Ts=T/N;

x0=[0;pi;0;0];%Initial state is that pendulum is stationary and in equilibrium position

model=myCartPoleRefGenModelALL;

nx=model.nx;

nu=model.nu;

sim_model = acados_sim_model();

sim_model.set('name', 'plantClosedLoop');

sim_model.set('T', Ts); %h is sampling time of closed loop system made equivalent to simulation time step (T/N) could be different though

sim_model.set('sym_x', model.sym_x);

sim_model.set('sym_u', model.sym_u);

sim_model.set('sym_p',model.sym_p);

sim_model.set('sym_xdot', model.sym_xdot);

sim_model.set('dyn_type', 'explicit');%

sim_model.set('dyn_expr_f', model.stateExpression);%

sim_opts = acados_sim_opts();

sim_opts.set('method', 'erk');%

sim = acados_sim(sim_model, sim_opts);

Nsim=150; %how sampling times simulate MPC (closed loop system); timeMPCsim=Nsim*Ts

x_sim=zeros(nx,Nsim+1); %x0,...,xN ; matrix to hold closed loop state response

u_sim=zeros(nu,Nsim);%u1,...,uN; matrix to hold control inputs

x_sim(:,1)=x0;%initial state starting from index 1 thats why Nsim+1 in x_sims

for ii=1:Nsim

% set initial state

sim.set('x', x_sim(:,ii));

sim.set('u', u_sim(:,1));

sim.set('p',reshape([1 1 1 1 1],5,1));

% solve

sim.solve();

% get simulated state

x_sim(:,ii+1) = sim.get('xn');

end

figure;

plot(1:Nsim+1, x_sim);

legend('p', 'theta', 'v', 'omega');

The error I get is:

Error using sim_set
sim_set: error setting p, wrong dimension, got 1, need 3

Error in acados_sim/set (line 121)
            sim_set(obj.model_struct, obj.opts_struct, obj.C_sim, obj.C_sim_ext_fun, field, value);

Error in myCartPoleSimParam (line 39)
    sim.set('p',1);

Hello Mohammed, :wave:
welcome to the acados forum!

As indicated by the error message, you are providing numerical values of the wrong dimension. The function sim.set('p', p_value) expects a value p_value with the same dimensions as model.sym_p.

Hello Kaethe,
Model.sym_p is a 1x1 vector and that is what I am inputting. I also tried inputting 3 values but then another error is raised where it says it expects 5 values which is why I am confused.

mhm that sounds weird indeed. Could you provide the code for your controller as well? How do you set the parameter there?

Hello Kaethe,
This is the OCP code which worked for me in terms of assigning the values of the parameters.

clear all

model_path=fullfile(pwd,'..','test_model_with_param')

addpath(model_path)

check_acados_requirements()

% OCP parameters and designated solvers

%Note: OCP is an open-loop control method

%Note: Repeat OCP at each time instant = MPC (closed-loop control)

N=100; %%%%%%%%%%%%%%%5

T=2; %%%%%%%%%%%%%

Ts=T/N; %every time period a control signal is outputed for OCP and currently for MPC too (uniform time grid)

%We will consider currently that MPC outputs control input at this rate too

x0=[0;pi;0;0];%Initial state is that pendulum is stationary and in equilibrium position

nlp_solver='sqp';

qp_solver='partial_condensing_hpipm';

qp_solver_cond_N = 5; % for partial condensing

sim_method = 'erk'; % integrator is explicit runge kutta for OCP

%model

model=test_model_with_param;

nx=model.nx;

nu=model.nu;

ny = size(model.cost_expr_y, 1); % used in simulink example

ny_e = size(model.cost_expr_y_e, 1);

%Create new acados solver for cart-pole model

ocp_model=acados_ocp_model();

%Set characteristics of ocp (problem formulation)

ocp_model.set('name','test_model_with_param');

ocp_model.set('T',T); %Refers to how much time simulate open-loop system

ocp_model.set('sym_x',model.sym_x);

ocp_model.set('sym_u', model.sym_u);

ocp_model.set('sym_xdot', model.sym_xdot);

ocp_model.set('sym_p',model.sym_p);

ocp_model.set('cost_type', 'nonlinear_ls');

ocp_model.set('cost_type_e', 'nonlinear_ls');

ocp_model.set('cost_expr_y', model.cost_expr_y);

%Below is the mayer term or terminal cost

ocp_model.set('cost_expr_y_e', model.cost_expr_y_e);

ocp_model.set('cost_W', model.W); %weighting matrices for lagrange term (in difference between reference and actual states)

ocp_model.set('cost_W_e', model.W_e); %weighting matrices for mayer term (in difference between reference and actual states)

%using explicit RK method

ocp_model.set('dyn_type', 'explicit');

ocp_model.set('dyn_expr_f', model.stateExpression);

%state and input constraints

ocp_model.set('constr_x0', x0);%initial state must be prescribed initial state

ocp_model.set('constr_Jbu',model.constr_Jbu); %next 3 lines describe constraints on control inputs

ocp_model.set('constr_lbu',model.constr_lbu);

ocp_model.set('constr_ubu',model.constr_ubu);

%Set characteristics of ocp operations

ocp_opts = acados_ocp_opts();

ocp_opts.set('param_scheme_N', N); %prediction horizon in context of MPC

ocp_opts.set('nlp_solver', nlp_solver);

ocp_opts.set('sim_method', sim_method);

ocp_opts.set('qp_solver', qp_solver);

ocp_opts.set('qp_solver_cond_N', qp_solver_cond_N);

ocp_opts.set('ext_fun_compile_flags', ''); % '-O2'

%Create OCP SOLVER (open-loop solver)

ocp = acados_ocp(ocp_model, ocp_opts);

x_traj_init = zeros(nx, N+1);

u_traj_init = zeros(nu, N);%as last state due to (N-1)th control input

%initialize reference trajectory

yref=zeros(5,1);

yref_e=zeros(4,1);

%%%%Note: with OCP you are giving reference trajectory across the full prediction horizon

%%%%Note: in MPC only the current reference as determined by tau is given.

plotYRef=zeros(1,N+1);

%Setting reference trajectory for the OCP problem

ocp.set('p',1);

for j=0:N-1

ocp.set('cost_y_ref',yref,j);%set reference trajectory across horizon (have reference for x and u)

end

ocp.set('cost_y_ref_e',yref_e,N);%set terminal state reference

%Solve and get results

ocp.solve();

utraj = ocp.get('u');

xtraj = ocp.get('x');

status = ocp.get('status'); % 0 - success

ocp.print('stat')

%%%%Plots

ts = linspace(0, T, N+1);

figure; hold on;

States = {'p', 'theta', 'v', 'dtheta'};

for i=1:length(States)

subplot(length(States), 1, i);

plot(ts, xtraj(i,:)); grid on; hold on;

plot(ts,plotYRef);

ylabel(States{i});

xlabel('t [s]')

end

%Plot control input trajectory

figure

stairs(ts, [utraj'; utraj(end)])

ylabel('F [N]')

xlabel('t [s]')

grid on

%%output position reference trajectory

referenceVariables=xtraj;%get position trajectory

tOCP=T;

time_Vect=linspace(0,tOCP,length(referenceVariables(1,:))); %must both OCP and MPC have same T and N such consistent timing


AND This is the model which both the OCP and integrator are based on.

function model= test_model_with_param()

%Import CasADi for non-linear modelling and algorithms differentiation

import casadi.*

%define number of states and number of controls

nx=4;

nu=1;

%Define Model parameters

M=SX.sym('M');

m=0.1;

l=0.8;

g=9.81;

%%%%%OCP model without tau as will not have reference control signal + just want to get reference trajectory

%Name states using scalar valued expression type in CasADi

%All units are in SI units

p=SX.sym('p'); %horizontal displacement of the cart

theta=SX.sym('theta');%angle between upwards vertical and rod (0 means upright)

v=SX.sym('v');%horizontal velocity of cart

dtheta=SX.sym('dtheta');%angular velocity of rod

F=SX.sym('F');%control input (force)

%State Vector and its derivative

sym_x=vertcat(p,theta,v,dtheta);%vertically concatenate state variables

sym_xdot=SX.sym('xdot',nx,1);%Create derivative of state vector

sym_u=F; %define control input as force

sym_p=M;

%describing dynamics of system

denom= M+m-m*cos(theta).^2;

stateExpression=vertcat(v, ...

dtheta, ...

(-m*l*sin(theta)*dtheta.^2+m*g*cos(theta)*sin(theta)+F)/denom, ...

(-m*l*cos(theta)*sin(theta)*dtheta.^2+F*cos(theta)+(M+m)*g*sin(theta))/l*denom ...

);

implicitStateExpression=stateExpression-sym_xdot;

%constraints

constr_Jbu=[1];

Umax=80;

constr_lbu=-Umax;

constr_ubu=Umax;%no slack variables in input constraint (hard constraint)

%Note: usually Zl should be larger

%cost function

W_x=diag([1e2 1e2 1e-3 1e-3]);%weight of each state in cost function

W_u=1e-1;

%cost function for reference tracking

cost_expr_y = vertcat(sym_x,sym_u); %%currently only position is a reference

W = blkdiag(W_x,W_u);

cost_expr_y_e=sym_x;

W_e=W_x; %why because to maintain periodicity of the generated path

%Defining model struct parameters

model.nx=nx; %%%

model.nu=nu; %%%

model.sym_x=sym_x; %%%

model.sym_xdot=sym_xdot; %%%

model.sym_u=sym_u; %%%

model.stateExpression=stateExpression; %%%

model.implicitStateExpression=implicitStateExpression; %%%

model.W_x=W_x; %weighting matrix of states in cost function (not used currently but actually equal to W)

model.W_e=W_e; %weighting matrix of terminal states in cost function

model.W=W;

model.cost_expr_y=cost_expr_y;

model.cost_expr_y_e=cost_expr_y_e;

model.constr_Jbu=constr_Jbu;

model.constr_lbu=constr_lbu;

model.constr_ubu=constr_ubu;

model.sym_p=sym_p;

end

Hi Mohammed,

we updated the minimal closed loop example to use parameters.

Maybe that helps to understand and clarify how it can be done.

If you have some unexpected behavior, please provide a complete minimal example to reproduce the issue.

Best,
Jonathan