Model¶
A Model (ssqpy.model.Model in Python, ssqp::model::Model in C++) is a prerequisite for solving an OCP with
SSQP. It bundles, over an optimization horizon \(H\):
-
a cost function for each stage, \(\ell_k(\boldsymbol{x}, \boldsymbol{u})\),
-
dynamics functions for each stage, \(\boldsymbol{f}_k(\boldsymbol{x}, \boldsymbol{u})\), and
-
constraint functions for each stage, \(\boldsymbol{c}_k(\boldsymbol{x}, \boldsymbol{u})\) (optional; a stage may have none).
All stage cost and dynamics functions must be defined; constraints may be left empty.
Horizon, states and controls¶
A model optimizes over \(H\) steps while treating the initial state \(\boldsymbol{x}_0\) as fixed (only the initial controls can be altered). This means there are \(H\) total controls (\(\boldsymbol{u}_0\) to \(\boldsymbol{u}_{H-1}\)) and \(H + 1\) total states (\(\boldsymbol{x}_0\) to \(\boldsymbol{x}_H\)). At the terminal stage \(H\) there are no controls, so stagewise functions must be written to ignore \(\boldsymbol{u}\) at that stage. Predefined functions already account for this.
\(\boldsymbol{x}\) need not be a Euclidean vector: SSQP also supports states that include manifold-valued components, such as a floating-base orientation. See Manifold-valued states in Costs, Constraints & Dynamics.
Defining a model¶
A model can be defined in two ways, which can also be mixed:
- Custom function objects: subclass
StageCost,StageDynamicsand (optionally)StageConstraintsand pass instances tomodel.finalize(...), as in the Quickstart. This is required for systems that are not described by a robot XML file (e.g. simplified/reduced models). - XML description files: pass
urdf_pathormjcf_pathto the constructor to load a robot description via Pinocchio. This gives access to robot algorithms (forward/inverse dynamics, kinematics, Jacobians) that the predefined costs and constraints use internally, and lets you useModel.addContactConstraintfor contact-implicit stages.
When a model is constructed from an XML file, it is not immediately usable for optimization: call finalize() to
assign costs/dynamics/constraints (explicitly, or letting the model build its own robot dynamics) before solving.
model.finalized reports whether this has happened.
Built-in presets¶
A handful of common robots are baked into the ssqp binary as URDF presets, so they can be used without pointing
urdf_path at a file on disk. Pass from_preset instead:
Available presets: Go2, A1, Panda, G1, Talos, DoublePendulum (ssqpy.model.Preset.NONE is the default,
meaning no preset). Each preset fixes its own urdf_path and free_flyer, so from_preset is mutually exclusive
with urdf_path, mjcf_path and free_flyer; passing both raises an error.
Constructor arguments¶
| Keyword argument | Description |
|---|---|
urdf_path / mjcf_path |
Path to a URDF or MJCF file describing the robot |
free_flyer |
Whether the model has a floating base (only relevant when loaded from XML) |
from_preset |
A built-in URDF preset to build the model from, instead of urdf_path |
solver_mode |
The SolverMode formulation to optimize in |
integration |
The Integration scheme used to propagate state |
ignore_innate_constraints |
Whether to ignore joint/velocity/torque limits declared in the XML |
actuated_joints |
Restrict actuation to a subset of joint indices |
finalize arguments¶
model.finalize(**kwargs) accepts, among others: costs / stage_cost / terminal_cost, dynamics,
constraints, custom_lower_position_bounds / custom_upper_position_bounds / custom_velocity_bounds /
custom_torque_bounds (override XML-derived innate constraint bounds), and init_states / init_controls (initial
guesses). See the API reference for the complete, up-to-date
list.
Solver mode¶
SolverMode selects the NLP formulation used for the dynamics equality constraint:
-
Kinematics: no system dynamics; controls are velocities and the state is the system configuration. -
ForwardDynamics: the state is configuration + velocity; controls are torques applied via forward dynamics. -
InverseDynamics: the state is configuration + velocity; controls are accelerations, with torques (needed to produce them) constrained to stay within effort limits. This simplifies the LQR formulation and can be more robust thanForwardDynamics. -
ReducedInverseDynamics: likeInverseDynamics, but an unactuated floating base and/or joint subset is enforced implicitly through state propagation rather than via equality constraints.
Integration scheme¶
Integration selects how velocity and configuration are propagated between stages:
-
ExplicitEuler: \(\boldsymbol{x}_{n+1} = \boldsymbol{x}_n + \boldsymbol{v}_n dt\), \(\boldsymbol{v}_{n+1} = \boldsymbol{v}_n + \boldsymbol{a}_n dt\) -
SemiImplicitEuler(default): \(\boldsymbol{x}_{n+1} = \boldsymbol{x}_n + \boldsymbol{v}_{n+1} dt\), \(\boldsymbol{v}_{n+1} = \boldsymbol{v}_n + \boldsymbol{a}_n dt\)
Contacts and forces¶
For XML-based models, Model.addForce(k, frame) declares an external force at a frame for a stage, and
Model.addContactConstraint(k, frame, mu=0.6, max_normal_force=inf, eq_tol=0.0, no_slip=True) is a convenience
that both adds a contact constraint (friction cone, non-penetration and, unless no_slip=False, a zero linear
velocity bound on the frame) and the associated force in one call; this is the mechanism
used by legged-robot examples (e.g. Go2, G1) to model foot contacts against the terrain.
See the Python API reference for the full Model method list.