Get Started

Formulate your problem in ICLOCS2

Formulating an optimal control problem in ICLOCS2 is straight-forward, and this guide will assist you in setting up the problem correctly and efficiently.

A general purpose optimal control problem can be formulated in the following Bolza form

and can be directly implement in ICLOCS2 through the following procedures.

Time Variables

First we define the time variables with


for the initial time and


for the final time. If the upper bound and the lower bounds are the same, then the final time can be fixed. Otherwise it is a variable terminal time problem.

State Variables

For state variables, we need to provide the initial conditions

problem.states.x0=[x1(t0) ... xn(t0)];

and bounds on intial conditions

problem.states.x0l=[x1(t0)_lowerbound ... xn(t0)_lowerbound]; 
problem.states.x0u=[x1(t0)_upperbound ... xn(t0)_upperbound];  

Again, the initial states can be fixed by setting upper and lower bounds the same.

Furthermore, we can to specify the bounds on the state variables

problem.states.xl=[x1_lowerbound ... xn_lowerbound];
problem.states.xu=[x1_upperbound ... xn_upperbound]; 

as well as bounds on the rate of change of state variables (optional)

problem.states.xrl=[x1dot_lowerbound ... xndot_lowerbound]; 
problem.states.xru=[x1dot_upperbound ... xndot_upperbound];  

For unbounded variables, -inf and inf may be used accordingly.

In ICLOCS2, we allow the user to specify the level of accuracy required for each variable. Here the bounds on the absolute local (discretization) error of state variables can be specified

pproblem.states.xErrorTol=[eps_x1 ... eps_xn];  

together with the tolerances for state and state rate variable box constraint violations

problem.states.xConstraintTol=[eps_x1_bounds ... eps_xn_bounds];
problem.states.xrConstraintTol=[eps_x1dot_bounds ... eps_xndot_bounds];

Next is to define the terminal state bounds

problem.states.xfl=[x1(tf)_lowerbound ... xn(tf)_lowerbound]; 
problem.states.xfu=[x1(tf)_upperbound ... xn(tf)_upperbound]; 

It is also recommend to give an initial guess of the state values at various times along the trajectory in the following form

guess.time=[t0 ... tf];
guess.states(:,1)=[x1(t0) ... x1(tf)];
% ...
guess.states(:,n)=[xn(t0) ... xn(tf)]; 

Input/control Variables

Firstly, it is possible to define the number of control actions. By default, the number of control actions is in correspondence with the number of integration intervals, with


Then smilarly, we need to define simple bounds. for input variables

problem.inputs.ul=[u1_lowerbound ... um_lowerbound];
problem.inputs.uu=[u1_upperbound ... um_upperbound];

bounds on the first control action.

problem.inputs.u0l=[u1_lowerbound(t0) ... um_lowerbound(t0)];
problem.inputs.u0u=[u1_upperbound(t0) ... um_upperbound(t0)]; 

and bounds on the rate of change. for control variables (optional)

problem.inputs.url=[u1dot_lowerbound ... umdot_lowerbound]; 
problem.inputs.uru=[u1dot_upperbound ... umdot_upperbound];  

Furthermore, we need tolerance for control variable and input rate box constraint violation

problem.inputs.uConstraintTol=[eps_u1_bounds ... eps_um_bounds];
problem.inputs.urConstraintTol=[eps_u1dot_bounds ... eps_umdot_bounds]; 

as well as an initial guess of the input trajectory (optional but recommended)

guess.inputs(:,1)=[u1(t0) ... u1(tf)]];
guess.inputs(:,m)=[um(t0) ... um(tf)]];

Path constraint

We need to specify the bounds for the path constraint function[g1_lowerbound g2_lowerbound ...];[g1_upperbound g2_upperbound ...];

and path constraint violation tolerances


Additional boundary constraint

For additional boundary constraints (in addition to simple bounds on variables), we will define the bounds of the boundary constraint function here.[b1_lowerbound b2_lowerbound ...];
problem.constraints.bu=[b1_upperbound b2_upperbound ...];

We may store the necessary problem parameters used in the functions in the following form;

and give reference to the plant model if Adigator is used to supply the derivative information = '...';

Now we can start to define the sub-functions.

Cost Functions

First, the Lagrange (stage) cost can be defined in L_unscaled(x,u,p,t,data) as

%Define states and setpoints
x1 = x(:,1); 

%Define inputs
u1 = u(:,1);
% ...
um = u(:,m);

stageCost = ...;

and the Mayer (boundary) cost in sub-function E_unscaled(x0,xf,u0,uf,p,t0,tf,data) as


System Dynamics

We then can specify the system dynamics in sub-function f_unscaled(x,u,p,t,data) with

%Stored data
auxdata = data.auxdata;

%Define states
x1 = x(:,1);

%Define inputs
u1 = u(:,1);
% ...
um = u(:,m);

%Define ODE right-hand side

dx(:,1) = f1(x1,..xn,u1,,p,t);
dx(:,n) = fn(x1,..xn,u1,,p,t);

Path Constraints

Any path constraints need to be specified in sub-function g_unscaled(x,u,p,t,data) with

%Define states
x1 = x(:,1);

%Define inputs
u1 = u(:,1);
% ...
um = u(:,m);


Additional Boundary Constraints

Any boundary constraints that are not formulated as variable simple bounds need to be specified in sub-function b_unscaled(x0,xf,u0,uf,p,t0,tf,vdat,varargin) . The user should only modify the follwing sections of codes

%------------- BEGIN CODE --------------
%------------- END OF CODE --------------

This conclude the process of formulating an optimal control problem in ICLOCS2.