Quickstart Guide

Getting set up

To install NamedTrajectories simply enter the package manager in the Julia REPL with ] and run

pkg> add NamedTrajectories

Then just use the package as usual with

using NamedTrajectories

For the following examples let's work with a simple trajectory

\[\qty{z_t = \mqty(x_t \\ u_t)}_{t=1:T}\]

where $x_t$ is the state and $u_t$ is the control at a time indexed by $t$. Together $z_t$ is referred to as a knot point and a NamedTrajectory essentially just stores a collection of knot points and makes it easy to access the state and control variables.

Creating a variable-timestep NamedTrajectory

Here we will create a NamedTrajectory with a variable timestep.

# define the number of timesteps
T = 10
Δt = 0.1

# define the knot point data as a NamedTuple of matrices
data = (
    x = rand(3, T),
    u = rand(2, T),
    Δt = fill(Δt, T),
)

# we must specify a timestep and control variable for the NamedTrajectory.
timestep = :Δt
control = :u

# we can now create a `NamedTrajectory` object
traj = NamedTrajectory(data; timestep=timestep, controls=control)

# we can return the names of the stored variables
traj.names
(:x, :u, :Δt)

Adding more problem data

In many settings we will want to specify the problem data of our NamedTrajectory – e.g. bounds, initial values, final values, and goal values.

# define the number of timesteps
T = 10

# define the knot point data as a NamedTuple of matrices
data = (
    x = rand(3, T),
    u = rand(2, T),
    Δt = rand(T),
)

# define initial values
initial = (
    x = [1.0, 0.0, 0.0],
    u = [0.0, 0.0],
)

# define final value, here just on the control
final = (
    u = [0.0, 0.0],
)

# define bounds
bounds = (
    x = 1.0,
    u = 1.0
)

# set a goal for the state
goal = (
    x = [0.0, 0.0, 1.0],
)

# we must specify a timestep and control variable for the NamedTrajectory
timestep = :Δt
control = :u

# we can now create a `NamedTrajectory` object
traj = NamedTrajectory(
    data;
    timestep=timestep,
    controls=control,
    initial=initial,
    final=final,
    bounds=bounds,
    goal=goal
)

# we can then show the bounds
traj.bounds
(x = ([-1.0, -1.0, -1.0], [1.0, 1.0, 1.0]), u = ([-1.0, -1.0], [1.0, 1.0]))

Retrieving data

There are a number of ways to access data, for example

traj.x
3×10 view(reshape(view(::Vector{Float64}, :), 6, 10), 1:3, :) with eltype Float64:
 0.233995  0.353604  0.58482   0.794777  …  0.13376   0.399041   0.677832
 0.919576  0.875515  0.620421  0.713392     0.799584  0.0292449  0.299246
 0.318337  0.63502   0.664411  0.112234     0.530962  0.835313   0.881934

returns the data matrix associated with the state variable x.

traj.data
6×10 reshape(view(::Vector{Float64}, :), 6, 10) with eltype Float64:
 0.233995  0.353604  0.58482   0.794777  …  0.13376   0.399041   0.677832
 0.919576  0.875515  0.620421  0.713392     0.799584  0.0292449  0.299246
 0.318337  0.63502   0.664411  0.112234     0.530962  0.835313   0.881934
 0.72015   0.880766  0.663848  0.962174     0.217087  0.656634   0.653942
 0.958976  0.343139  0.583161  0.480217     0.489653  0.295889   0.592795
 0.55252   0.8299    0.59284   0.630414  …  0.208036  0.665518   0.37482

returns the all of the data as a matrix where each column is a knot point.

traj.datavec
60-element Vector{Float64}:
 0.23399520676324137
 0.9195760045236989
 0.3183373247794967
 0.7201499486906784
 0.9589764090593217
 0.5525199988469646
 0.35360361637355475
 0.8755146982760033
 0.6350200632243167
 0.8807658063267413
 ⋮
 0.6566342807397133
 0.2958891755570029
 0.665517669393035
 0.6778317554312273
 0.2992457012208958
 0.8819339107642207
 0.6539417897060322
 0.5927952189531
 0.37481950109136175

returns the all of the data as a view of the data matrix as a vector – useful for passing data to solvers.

traj[1]
KnotPoint{Float64, (:x, :u, :Δt), Tuple{UnitRange{Int64}, UnitRange{Int64}, UnitRange{Int64}}, Tuple{Symbol, Symbol, Symbol}, Tuple{Symbol, Symbol}}(1, [0.23399520676324137, 0.9195760045236989, 0.3183373247794967, 0.7201499486906784, 0.9589764090593217, 0.5525199988469646], 0.5525199988469646, (x = 1:3, u = 4:5, Δt = 6:6), (:x, :u, :Δt), (:u, :Δt))

returns a KnotPoint.

traj[1].x
3-element view(reshape(view(::Vector{Float64}, :), 6, 10), 1:3, 1) with eltype Float64:
 0.23399520676324137
 0.9195760045236989
 0.3183373247794967

returns the state at the first knot point.

get_times(traj)
10-element Vector{Float64}:
 0.0
 0.5525199988469646
 1.3824197245565397
 1.975259764704353
 2.60567384159694
 2.8440967792278338
 3.664057641190708
 3.9550296954480615
 4.163065354150041
 4.828583023543076

returns the times of the knot points.

get_timesteps(traj)
10-element reshape(view(reshape(view(::Vector{Float64}, :), 6, 10), 6:6, :), 10) with eltype Float64:
 0.5525199988469646
 0.829899725709575
 0.5928400401478133
 0.6304140768925868
 0.23842293763089362
 0.8199608619628742
 0.2909720542573532
 0.20803565870197993
 0.665517669393035
 0.37481950109136175

returns the timesteps of the knot points, as vector.

Retrieving metadata

We can also retrieve metadata about the trajectory, for example

traj.names
(:x, :u, :Δt)

returns the names of the variables stored in the trajectory.

traj.dims
(x = 3, u = 2, Δt = 1)

returns the dimensions of the variables stored in the trajectory.

traj.T
10

returns the number of knot points in the trajectory.

traj.components
(x = 1:3, u = 4:5, Δt = 6:6)

returns the components of the trajectory.

Updating problem data

The NamedTrajectory can be updated by accessing fields and replacing the data.

We also have update! to update trajectory components, and update_bound!, which allows you to pass in the same kinds of bounds available at construction (e.g., an Int or Tuple). The bound will get shaped to match the trajectory component dimensions just like at construction. These methods cannot be used to update non-existent bounds or components.

For efficiency, a trajectory cannot add new data after it is constructed. However, we have convenience methods like add_component that build a new trajectory with added data.

update_bound!(traj, :x, 2.) # TODO: consider fleshing out this section with more examples of updating trajectory components, knot points, globals, bounds, etc.

This page was generated using Literate.jl.