72 OCP(
int num_states,
int num_inputs, std::chrono::duration<Scalar>
dt,
77 DynamicsType dynamics_type = DynamicsType::EXPLICIT_ODE,
78 TimestepMethod timestep_method = TimestepMethod::FIXED,
79 TranscriptionMethod transcription_method =
80 TranscriptionMethod::DIRECT_TRANSCRIPTION)
92 transcription_method} {}
111 OCP(
int num_states,
int num_inputs, std::chrono::duration<Scalar> dt,
117 DynamicsType dynamics_type = DynamicsType::EXPLICIT_ODE,
118 TimestepMethod timestep_method = TimestepMethod::FIXED,
119 TranscriptionMethod transcription_method =
120 TranscriptionMethod::DIRECT_TRANSCRIPTION)
121 : m_num_steps{num_steps},
122 m_dynamics{std::move(dynamics)},
123 m_dynamics_type{dynamics_type},
124 m_transcription_method{transcription_method} {
126 m_U = this->decision_variable(num_inputs, m_num_steps + 1);
128 if (timestep_method == TimestepMethod::FIXED) {
130 for (
int i = 0; i < num_steps + 1; ++i) {
131 m_DT[0, i] = dt.count();
133 }
else if (timestep_method == TimestepMethod::VARIABLE_SINGLE) {
134 Variable single_dt = this->decision_variable();
139 for (
int i = 0; i < num_steps + 1; ++i) {
140 m_DT[0, i] = single_dt;
142 }
else if (timestep_method == TimestepMethod::VARIABLE) {
143 m_DT = this->decision_variable(1, m_num_steps + 1);
144 for (
int i = 0; i < num_steps + 1; ++i) {
145 m_DT[0, i].set_value(dt.count());
149 if (transcription_method == TranscriptionMethod::DIRECT_TRANSCRIPTION) {
150 m_X = this->decision_variable(num_states, m_num_steps + 1);
151 constrain_direct_transcription();
152 }
else if (transcription_method ==
153 TranscriptionMethod::DIRECT_COLLOCATION) {
154 m_X = this->decision_variable(num_states, m_num_steps + 1);
155 constrain_direct_collocation();
156 }
else if (transcription_method == TranscriptionMethod::SINGLE_SHOOTING) {
160 constrain_single_shooting();
167 template <
typename T>
170 auto x_0 = this->initial_state();
176 for (
auto& elem : x_0_value) {
177 elem = initial_state;
185 if (m_transcription_method == TranscriptionMethod::SINGLE_SHOOTING &&
186 std::ranges::all_of(x_0_value, [](
const auto& elem) {
187 return elem.type() == ExpressionType::CONSTANT;
191 this->subject_to(x_0 == x_0_value);
198 template <
typename T>
201 this->subject_to(this->final_state() == final_state);
213 for (
int i = 0; i < m_num_steps + 1; ++i) {
233 for (
int i = 0; i < m_num_steps + 1; ++i) {
236 auto dt = this->dt()[0, i];
237 callback(time, x, u, dt);
247 template <
typename T>
250 for (
int i = 0; i < m_num_steps + 1; ++i) {
251 this->subject_to(U().col(i) >= lower_bound);
259 template <
typename T>
262 for (
int i = 0; i < m_num_steps + 1; ++i) {
263 this->subject_to(U().col(i) <= upper_bound);
271 this->subject_to(dt() >= min_timestep.count());
278 this->subject_to(dt() <= max_timestep.count());
324 DynamicsType m_dynamics_type;
325 TranscriptionMethod m_transcription_method;
338 template <
typename F,
typename State,
typename Input,
typename Time>
339 State rk4(F&& f, State x, Input u, Time t0, Time dt) {
340 auto halfdt = dt * Scalar(0.5);
341 State k1 = f(t0, x, u, dt);
342 State k2 = f(t0 + halfdt, x + k1 * halfdt, u, dt);
343 State k3 = f(t0 + halfdt, x + k2 * halfdt, u, dt);
344 State k4 = f(t0 + dt, x + k3 * dt, u, dt);
346 return x + (k1 + k2 * Scalar(2) + k3 * Scalar(2) + k4) * (dt / Scalar(6));
350 void constrain_direct_collocation() {
351 slp_assert(m_dynamics_type == DynamicsType::EXPLICIT_ODE);
353 Variable<Scalar> time{0};
356 for (
int i = 0; i < m_num_steps; ++i) {
357 Variable h = dt()[0, i];
359 auto& f = m_dynamics;
362 auto t_end = t_begin + h;
364 auto x_begin = X().col(i);
365 auto x_end = X().col(i + 1);
367 auto u_begin = U().col(i);
368 auto u_end = U().col(i + 1);
370 auto xdot_begin = f(t_begin, x_begin, u_begin, h);
371 auto xdot_end = f(t_end, x_end, u_end, h);
372 auto xdot_c = Scalar(-3) / (Scalar(2) * h) * (x_begin - x_end) -
373 Scalar(0.25) * (xdot_begin + xdot_end);
375 auto t_c = t_begin + Scalar(0.5) * h;
376 auto x_c = Scalar(0.5) * (x_begin + x_end) +
377 h / Scalar(8) * (xdot_begin - xdot_end);
378 auto u_c = Scalar(0.5) * (u_begin + u_end);
380 this->subject_to(xdot_c == f(t_c, x_c, u_c, h));
387 void constrain_direct_transcription() {
388 Variable<Scalar> time{0};
390 for (
int i = 0; i < m_num_steps; ++i) {
391 auto x_begin = X().col(i);
392 auto x_end = X().col(i + 1);
394 Variable dt = this->dt()[0, i];
396 if (m_dynamics_type == DynamicsType::EXPLICIT_ODE) {
398 x_end == rk4<
const decltype(m_dynamics)&, VariableMatrix<Scalar>,
399 VariableMatrix<Scalar>, Variable<Scalar>>(
400 m_dynamics, x_begin, u, time, dt));
401 }
else if (m_dynamics_type == DynamicsType::DISCRETE) {
402 this->subject_to(x_end == m_dynamics(time, x_begin, u, dt));
410 void constrain_single_shooting() {
411 Variable<Scalar> time{0};
413 for (
int i = 0; i < m_num_steps; ++i) {
414 auto x_begin = X().col(i);
415 auto x_end = X().col(i + 1);
417 Variable dt = this->dt()[0, i];
419 if (m_dynamics_type == DynamicsType::EXPLICIT_ODE) {
420 x_end = rk4<
const decltype(m_dynamics)&, VariableMatrix<Scalar>,
421 VariableMatrix<Scalar>, Variable<Scalar>>(
422 m_dynamics, x_begin, u, time, dt);
423 }
else if (m_dynamics_type == DynamicsType::DISCRETE) {
424 x_end = m_dynamics(time, x_begin, u, dt);
OCP(int num_states, int num_inputs, std::chrono::duration< Scalar > dt, int num_steps, function_ref< VariableMatrix< Scalar >(const Variable< Scalar > &t, const VariableMatrix< Scalar > &x, const VariableMatrix< Scalar > &u, const Variable< Scalar > &dt)> dynamics, DynamicsType dynamics_type=DynamicsType::EXPLICIT_ODE, TimestepMethod timestep_method=TimestepMethod::FIXED, TranscriptionMethod transcription_method=TranscriptionMethod::DIRECT_TRANSCRIPTION)
Definition ocp.hpp:111
OCP(int num_states, int num_inputs, std::chrono::duration< Scalar > dt, int num_steps, function_ref< VariableMatrix< Scalar >(const VariableMatrix< Scalar > &x, const VariableMatrix< Scalar > &u)> dynamics, DynamicsType dynamics_type=DynamicsType::EXPLICIT_ODE, TimestepMethod timestep_method=TimestepMethod::FIXED, TranscriptionMethod transcription_method=TranscriptionMethod::DIRECT_TRANSCRIPTION)
Definition ocp.hpp:72