28template <
typename F,
typename State,
typename Input,
typename Time>
29State
RK4(F&& f, State x, Input u, Time t0, Time dt) {
30 auto halfdt = dt * 0.5;
31 State k1 = f(t0, x, u, dt);
32 State k2 = f(t0 + halfdt, x + k1 * halfdt, u, dt);
33 State k3 = f(t0 + halfdt, x + k2 * halfdt, u, dt);
34 State k4 = f(t0 + dt, x + k3 * dt, u, dt);
36 return x + (k1 + k2 * 2.0 + k3 * 2.0 + k4) * (dt / 6.0);
123 int numStates,
int numInputs, std::chrono::duration<double> dt,
139 return dynamics(x, u);
163 int numStates,
int numInputs, std::chrono::duration<double> dt,
171 : m_numStates{numStates},
172 m_numInputs{numInputs},
174 m_numSteps{numSteps},
175 m_transcriptionMethod{method},
176 m_dynamicsType{dynamicsType},
177 m_dynamicsFunction{
std::move(dynamics)},
178 m_timestepMethod{timestepMethod} {
180 m_U = DecisionVariable(m_numInputs, m_numSteps + 1);
182 if (m_timestepMethod == TimestepMethod::kFixed) {
184 for (
int i = 0; i < numSteps + 1; ++i) {
185 m_DT(0, i) = m_dt.count();
187 }
else if (m_timestepMethod == TimestepMethod::kVariableSingle) {
193 for (
int i = 0; i < numSteps + 1; ++i) {
196 }
else if (m_timestepMethod == TimestepMethod::kVariable) {
197 m_DT = DecisionVariable(1, m_numSteps + 1);
198 for (
int i = 0; i < numSteps + 1; ++i) {
199 m_DT(0, i).SetValue(m_dt.count());
203 if (m_transcriptionMethod == TranscriptionMethod::kDirectTranscription) {
204 m_X = DecisionVariable(m_numStates, m_numSteps + 1);
205 ConstrainDirectTranscription();
206 }
else if (m_transcriptionMethod ==
207 TranscriptionMethod::kDirectCollocation) {
208 m_X = DecisionVariable(m_numStates, m_numSteps + 1);
209 ConstrainDirectCollocation();
210 }
else if (m_transcriptionMethod == TranscriptionMethod::kSingleShooting) {
214 ConstrainSingleShooting();
223 template <
typename T>
226 SubjectTo(InitialState() == initialState);
234 template <
typename T>
237 SubjectTo(FinalState() == finalState);
251 for (
int i = 0; i < m_numSteps + 1; ++i) {
272 for (
int i = 0; i < m_numSteps + 1; ++i) {
275 auto dt = DT()(0, i);
276 callback(time, x, u, dt);
288 template <
typename T>
291 for (
int i = 0; i < m_numSteps + 1; ++i) {
292 SubjectTo(U().Col(i) >= lowerBound);
302 template <
typename T>
305 for (
int i = 0; i < m_numSteps + 1; ++i) {
306 SubjectTo(U().Col(i) <= upperBound);
316 SubjectTo(DT() >= minTimestep.count());
325 SubjectTo(DT() <= maxTimestep.count());
375 void ConstrainDirectCollocation() {
376 Assert(m_dynamicsType == DynamicsType::kExplicitODE);
381 for (
int i = 0; i < m_numSteps; ++i) {
384 auto& f = m_dynamicsFunction;
387 auto t_end = t_begin + h;
389 auto x_begin = X().Col(i);
390 auto x_end = X().Col(i + 1);
392 auto u_begin = U().Col(i);
393 auto u_end = U().Col(i + 1);
395 auto xdot_begin = f(t_begin, x_begin, u_begin, h);
396 auto xdot_end = f(t_end, x_end, u_end, h);
398 -3 / (2 * h) * (x_begin - x_end) - 0.25 * (xdot_begin + xdot_end);
400 auto t_c = t_begin + 0.5 * h;
401 auto x_c = 0.5 * (x_begin + x_end) + h / 8 * (xdot_begin - xdot_end);
402 auto u_c = 0.5 * (u_begin + u_end);
404 SubjectTo(xdot_c == f(t_c, x_c, u_c, h));
410 void ConstrainDirectTranscription() {
413 for (
int i = 0; i < m_numSteps; ++i) {
414 auto x_begin = X().Col(i);
415 auto x_end = X().Col(i + 1);
417 Variable dt = DT()(0, i);
419 if (m_dynamicsType == DynamicsType::kExplicitODE) {
420 SubjectTo(x_end == RK4<
const decltype(m_dynamicsFunction)&,
421 VariableMatrix, VariableMatrix, Variable>(
422 m_dynamicsFunction, x_begin, u, time, dt));
423 }
else if (m_dynamicsType == DynamicsType::kDiscrete) {
424 SubjectTo(x_end == m_dynamicsFunction(time, x_begin, u, dt));
431 void ConstrainSingleShooting() {
434 for (
int i = 0; i < m_numSteps; ++i) {
435 auto x_begin = X().Col(i);
436 auto x_end = X().Col(i + 1);
438 Variable dt = DT()(0, i);
440 if (m_dynamicsType == DynamicsType::kExplicitODE) {
441 x_end =
RK4<
const decltype(m_dynamicsFunction)&, VariableMatrix,
442 VariableMatrix, Variable>(m_dynamicsFunction, x_begin, u,
444 }
else if (m_dynamicsType == DynamicsType::kDiscrete) {
445 x_end = m_dynamicsFunction(time, x_begin, u, dt);
454 std::chrono::duration<double> m_dt;
460 function_ref<VariableMatrix(
const Variable& t,
const VariableMatrix& x,
461 const VariableMatrix& u,
const Variable& dt)>
#define SLEIPNIR_DLLEXPORT
Definition SymbolExports.hpp:34
This class allows the user to pose and solve a constrained optimal control problem (OCP) in a variety...
Definition OCPSolver.hpp:103
void ConstrainInitialState(const T &initialState)
Utility function to constrain the initial state.
Definition OCPSolver.hpp:225
void SetMinTimestep(std::chrono::duration< double > minTimestep)
Convenience function to set a lower bound on the timestep.
Definition OCPSolver.hpp:315
VariableMatrix InitialState()
Convenience function to get the initial state in the trajectory.
Definition OCPSolver.hpp:365
VariableMatrix & U()
Get the input variables.
Definition OCPSolver.hpp:347
void SetMaxTimestep(std::chrono::duration< double > maxTimestep)
Convenience function to set an upper bound on the timestep.
Definition OCPSolver.hpp:324
void ForEachStep(const function_ref< void(const VariableMatrix &x, const VariableMatrix &u)> callback)
Set the constraint evaluation function.
Definition OCPSolver.hpp:248
VariableMatrix & DT()
Get the timestep variables.
Definition OCPSolver.hpp:358
void ConstrainFinalState(const T &finalState)
Utility function to constrain the final state.
Definition OCPSolver.hpp:236
void SetUpperInputBound(const T &upperBound)
Convenience function to set an upper bound on the input.
Definition OCPSolver.hpp:304
VariableMatrix FinalState()
Convenience function to get the final state in the trajectory.
Definition OCPSolver.hpp:372
void ForEachStep(const function_ref< void(const Variable &t, const VariableMatrix &x, const VariableMatrix &u, const Variable &dt)> callback)
Set the constraint evaluation function.
Definition OCPSolver.hpp:266
void SetLowerInputBound(const T &lowerBound)
Convenience function to set a lower bound on the input.
Definition OCPSolver.hpp:290
OCPSolver(int numStates, int numInputs, std::chrono::duration< double > dt, int numSteps, function_ref< VariableMatrix(const VariableMatrix &x, const VariableMatrix &u)> dynamics, DynamicsType dynamicsType=DynamicsType::kExplicitODE, TimestepMethod timestepMethod=TimestepMethod::kFixed, TranscriptionMethod method=TranscriptionMethod::kDirectTranscription)
Build an optimization problem using a system evolution function (explicit ODE or discrete state trans...
Definition OCPSolver.hpp:122
VariableMatrix & X()
Get the state variables.
Definition OCPSolver.hpp:336
OCPSolver(int numStates, int numInputs, std::chrono::duration< double > dt, int numSteps, function_ref< VariableMatrix(const Variable &t, const VariableMatrix &x, const VariableMatrix &u, const Variable &dt)> dynamics, DynamicsType dynamicsType=DynamicsType::kExplicitODE, TimestepMethod timestepMethod=TimestepMethod::kFixed, TranscriptionMethod method=TranscriptionMethod::kDirectTranscription)
Build an optimization problem using a system evolution function (explicit ODE or discrete state trans...
Definition OCPSolver.hpp:162
This class allows the user to pose a constrained nonlinear optimization problem in natural mathematic...
Definition OptimizationProblem.hpp:50
An autodiff variable pointing to an expression node.
Definition Variable.hpp:31
void SetValue(double value)
Sets Variable's internal value.
Definition Variable.hpp:75
A matrix of autodiff variables.
Definition VariableMatrix.hpp:28
VariableBlock< VariableMatrix > Col(int col)
Returns a column slice of the variable matrix.
Definition VariableMatrix.hpp:485
An implementation of std::function_ref, a lightweight non-owning reference to a callable.
Definition FunctionRef.hpp:17
Definition Concepts.hpp:28
Definition Concepts.hpp:12
Definition Hessian.hpp:18
DynamicsType
Enum describing a type of system dynamics constraints.
Definition OCPSolver.hpp:57
@ kExplicitODE
The dynamics are a function in the form dx/dt = f(t, x, u).
@ kDiscrete
The dynamics are a function in the form xₖ₊₁ = f(t, xₖ, uₖ).
TranscriptionMethod
Enum describing an OCP transcription method.
Definition OCPSolver.hpp:42
@ kSingleShooting
States depend explicitly as a function of all previous states and all previous inputs.
@ kDirectTranscription
Each state is a decision variable constrained to the integrated dynamics of the previous state.
@ kDirectCollocation
The trajectory is modeled as a series of cubic polynomials where the centerpoint slope is constrained...
TimestepMethod
Enum describing the type of system timestep.
Definition OCPSolver.hpp:67
@ kVariableSingle
The timesteps are equal length but allowed to vary as a single decision variable.
@ kFixed
The timestep is a fixed constant.
@ kVariable
The timesteps are allowed to vary as independent decision variables.
State RK4(F &&f, State x, Input u, Time t0, Time dt)
Performs 4th order Runge-Kutta integration of dx/dt = f(t, x, u) for dt.
Definition OCPSolver.hpp:29
function_ref(R(*)(Args...)) -> function_ref< R(Args...)>
Implement std::hash so that hash_code can be used in STL containers.
Definition PointerIntPair.h:280
#define Assert(condition)
Abort in C++.
Definition Assert.hpp:24