## 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

`problem.time.t0=0;`

for the initial time and

```
problem.time.tf_min=final_time_min;
problem.time.tf_max=final_time_max;
guess.tf=final_time_guess;
```

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

`problem.inputs.N=0;`

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

```
problem.constraints.gl=[g1_lowerbound g2_lowerbound ...];
problem.constraints.gu=[g1_upperbound g2_upperbound ...];
```

and path constraint violation tolerances

`problem.constraints.gTol=[0.1];`

#### 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.

```
problem.constraints.bl=[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

`problem.data.auxdata=auxdata;`

and give reference to the plant model if Adigator is used to supply the derivative information

`problem.data.plantmodel = '...';`

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);
%...
xn=x(:,n);
%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

`boundaryCost=...;`

#### 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);
%...
xn=x(:,n),
%Define inputs
u1 = u(:,1);
% ...
um = u(:,m);
%Define ODE right-hand side
dx(:,1) = f1(x1,..xn,u1,..um,p,t);
%...
dx(:,n) = fn(x1,..xn,u1,..um,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);
%...
xn=x(:,n),
%Define inputs
u1 = u(:,1);
% ...
um = u(:,m);
c(:,1)=g1(x1,...,u1,...p,t);
c(:,2)=g2(x1,...,u1,...p,t);
```

#### 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 --------------
bc(1,:)=b1(x0,xf,u0,uf,p,tf);
bc(2,:)=b2(x0,xf,u0,uf,p,tf);
%------------- END OF CODE --------------
```

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