Kamino#
SolverKamino simulates constrained rigid multi-body
systems in maximal coordinates. It is designed for mechanical assemblies with
kinematic loops, under- or overactuation, joint limits, hard frictional
contacts, and restitutive impacts.
Unlike the other maximal-coordinate solvers, Kamino focuses on constrained rigid mechanical assemblies rather than particle or deformable simulation. Kamino is currently in BETA 1, and Newton users are discouraged from depending on it. Evaluate it only when kinematic loops and hard contact constraints are primary requirements and an experimental solver is acceptable.
Experimental
SolverKamino is experimental. Its public API,
behavior, feature support, performance, and implementation may change
without prior notice.
See the SolverKamino API reference for construction
and configuration details. Runnable workflows are available in the
Kamino examples.
Body acceleration#
Kamino populates body_qdd when the extended state
attribute is requested. Values are center-of-mass spatial accelerations in the
world frame, with linear acceleration followed by angular acceleration. For a
step of duration dt, Kamino reports the discrete step average
(body_qd_out - body_qd_in) / dt. Consequently, a contact impact reports its
velocity impulse divided by dt rather than a continuous midpoint
acceleration. Resetting a state clears the requested acceleration in each reset
world.
Choosing a dynamics solver#
Kamino provides three forward-dynamics backends:
"padmm"(default): proximal ADMM, dense Jacobians/dynamics, and the Euler integrator. It is the slower, more robust option because it solves equality and inequality constraints together."dvi"(opt-in): projected dual iterations, sparse Jacobians, dense dynamics with the RCM-reordered blocked LLT solver, and the Euler integrator. It is generally faster, but approximates the coupled problem by alternating between a direct solve for equality constraints and projected iterations for inequality constraints. As a rule of thumb, DVI solves inequality constraints less accurately than PADMM, particularly as the number of active inequalities grows. Dual preconditioning is not supported."lox"(opt-in, experimental): a primal splitting method. Like DVI, it alternates between solving for equality constraints (and smooth dynamics in general) and solving for inequality constraints; however, in LOX the split is performed at the velocity level, and ADMM is used to reach a consensus.
Select the backend when constructing the configuration so dependent defaults initialize consistently:
config = newton.solvers.SolverKamino.Config(dynamics_solver="dvi")
solver = newton.solvers.SolverKamino(model, config=config)
DVI is best suited to performance-sensitive rigid mechanisms with relatively
few active contacts; PADMM remains the safer and more broadly validated choice.
Set sparse_jacobian=False for fully dense DVI, or set
sparse_dynamics=True to use sparse dynamics with the Conjugate Residual
solver.
For large bilateral systems, opt into RCM-reordered factorization explicitly:
config.dvi.bilateral_solver_type = "LLTBRCM"
config.dvi.bilateral_solver_kwargs = {
"block_size": 32,
"reuse_permutation": True,
"parallel_factorization": True,
}
The cached permutation remains mathematically valid when matrix values or
sparsity change and is recomputed automatically if the active dimension
changes. Keep the default "LLTB" solver for small systems.
DVI unilateral subsolvers#
DVI offers two subsolvers for bounded joint rows, limits, and contacts:
PGS (default) uses projected Gauss-Seidel updates with less work per iteration, making it a simple choice for modest contact problems.
APGD offers a faster convergence rate for each frozen-correction quadratic problem, at the cost of objective-gradient evaluations and an inner backtracking loop. CUDA execution requires conditional-graph support.
Both support dense and sparse operators and bilateral Schur elimination.
See the SolverKamino configuration reference for
subsolver selection and iteration controls.
Constraint recovery and material compliance#
PADMM and DVI share the constraint settings in config.constraints. Each
constraint group has a global recovery time and speed cap. Bilateral joints
remain rigid; contacts and joint limits can opt into an implicit spring-damper
law using model stiffness and damping.
config = newton.solvers.SolverKamino.Config(dynamics_solver="dvi")
config.constraints.joint_recovery_time = 0.01
config.constraints.joint_recovery_speed = 0.05
config.constraints.contact_compliance = True
config.constraints.contact_recovery_time = None # Derive c / k per contact.
config.constraints.contact_recovery_speed = 0.5
config.constraints.limit_compliance = True
config.constraints.limit_recovery_time = None # Derive c / k per joint DoF.
config.constraints.limit_recovery_speed = 0.5
solver = newton.solvers.SolverKamino(model, config=config)
Recovery times are in seconds. joint_recovery_speed supplies one numerical
cap for all bilateral rows; limit_recovery_speed does the same for all
limit rows. Each cap is in m/s for linear rows and rad/s for angular rows.
The contact cap is in m/s. Caps apply independently to each constraint row. Their default is
infinity (unlimited); zero disables positional recovery while retaining the
velocity constraint and any physical compliance. They do not cap restitution,
motor targets, or body velocities. These settings are configured before solver
construction.
For step size \(h\), positive stiffness \(k\), damping \(c\), and signed constraint violation \(\phi\), backward Euler gives
With integrator="moreau", constraints are evaluated at the midpoint and the
remaining pose update spans \(h/2\). For compliant rows the coefficients are
The impulse still spans the full timestep \(h\). These coefficients enforce
the spring-damper law at the end of the step using the linearized constraint
position. Moreau requires use_collision_detector=True so contacts are
evaluated at the midpoint. The existing fallback to Euler for external contacts
also uses Euler compliance coefficients. Hard-row recovery retains its existing
full-step coefficients under either integrator.
The solver adds \(E\) to the physical constraint operator and adds the
capped bias \(b\) to the constraint velocity. A global
contact_recovery_time or limit_recovery_time overrides \(\tau\)
and therefore sets the effective damping to \(k\tau\) in both terms.
With no override, the solver uses the model damping. Once the recovery cap is
active, the law differs from the uncapped linear spring-damper. Numerical
regularization and ADMM proximal penalties remain separate from \(E\).
Contact stiffness/damping come from positive
rigid_contact_stiffness and the corresponding
rigid_contact_damping when supplied. Otherwise, they
are the arithmetic means of shape_material_ke and
shape_material_kd of the two shapes. This fallback also
works with Kamino’s internal collision pipeline. Only the contact normal
receives compliance; tangential rows retain the Coulomb friction law.
The normal spring impulse contributes fully to the friction load, including in
DVI’s PGS solver. Its hard-contact stabilization exclusion does not apply to
physical spring forces.
Compliant contacts obtain bounce from their spring-damper and ignore the
material restitution coefficient.
Limits use joint_limit_ke and
joint_limit_kd of their joint DoF. Limit detection is
unchanged. Non-positive or infinite stiffness retains the hard law for either family;
this interface does not represent a pure damper with zero stiffness. The
per-DOF drive gains and passive damping are independent of structural joint
recovery and are not reused for it.
The speed cap and recovery time apply to penetration or violated limits. Speculative contacts retain the positive-gap closing allowance \(\max(\phi,0)/h\); the cap does not slow approach before contact. Contact dead zones and the existing hard-contact restitution rules remain in effect.
Compatibility#
By default, compliance is disabled, recovery times are None, and caps are
unlimited. Existing configurations retain their dimensionless alpha
(joints), beta (limits), and gamma (contacts) recovery fractions. Hard
rows without a recovery-time override continue to use \(s\phi/h\) for
their corresponding legacy fraction \(s\). An explicit recovery time
takes precedence. At a given timestep, the equivalent time is
\(\tau=h(1/s-1)\) for \(s>0\); this conversion changes with timestep.
For example, a fraction of 0.01 at 240 Hz corresponds to 0.4125 s.
For a zero fraction, set the corresponding recovery time and recovery-speed
cap to zero.
This conversion preserves rigid-row recovery. Enabling finite stiffness can
introduce elastic deflection or bounce, so material gains must suit the intended
motion rather than reproduce rigid-contact trajectories exactly.
The new settings are configured through Python. USD schema and importer extensions for these settings are deferred to a separate change.
The shared recovery/compliance settings currently support PADMM and DVI.
LOX rejects non-default values for these new settings and retains its existing
config.lox.contact_compliance option and recovery controls.
LOX’s option uses only positive per-contact stiffness; it does not fall back to
shape materials, and its internal-pipeline contacts remain hard. PADMM and DVI
reject config.lox.contact_compliance=True with guidance to use the shared
option. Switching between these options can therefore change which contacts
are compliant even when the model materials are unchanged.
LOX unilateral projection#
LOX projects contacts, joint limits, and joint friction with mass-split
sweeps. config.lox.gauss_seidel_max_colors selects the sweep: one gives a
fully parallel Jacobi sweep, and larger values process up to that many
approximate constraint colors sequentially. config.lox.projection_acceleration
optionally accelerates the resulting map:
"none"(default) runs plain sweeps."apgd"applies restarted Nesterov extrapolation and requiresgauss_seidel_max_colors=1."anderson"applies one safeguarded Anderson direction after every sweep, for either the Jacobi or the colored map. Setprojection_anderson_recycle=Falseto discard the direction between splitting iterations.
LOX contact extensions#
Enable these features through config.lox after selecting
dynamics_solver="lox". They are disabled by default.
contact_compliance=Trueturns contacts with a positive per-contact stiffnessk[N/m] (newton.Contacts.rigid_contact_stiffness) into implicit spring-dampers, with the dampingd[N s/m] ofnewton.Contacts.rigid_contact_damping. They add1 / (dt (k dt + d))to the normal contact operator and recover the fractionk dt / (k dt + d)of existing penetration per step. Their bounce comes from the spring-damper, so they ignore restitution. Contacts without a positive stiffness, and contacts detected by Kamino’s own collision pipelines, remain hard.newton.CollisionPipelineprovides per-contact stiffness only for hydroelastic contacts.contact_implicit_restitution=Truedecides the restitution of speculative impacts inside each local contact update, from its current reaction-free normal velocity, which better preserves energy in speculative impacts. Restitution applies either way: by default, the bounce target is fixed at the beginning of the step.contact_spatial_friction=Trueaccounts for the shapemu_torsionalandmu_rollingcoefficients, both in metres. Sliding, torsion, and rolling share one elliptic friction budget. Contacts with zero angular coefficients retain the classical 3D contact solve. Kamino’s primitive collision pipeline provides no angular coefficients.
Inspecting terminal status#
After each step, status provides one
device-resident terminal status record per world. PADMM and DVI both provide
converged, iterations, r_p, r_d, and r_c fields. Their
residual definitions are backend-specific:
PADMM: Let
xandybe the current preconditioned impulse iterates,x_prevandy_prevtheir previous values,Pthe diagonal dual preconditioner, andetaandrhothe proximal and penalty parameters.r_p = ||P (x - y)||_infis the primal consensus residual [N·s or N·m·s].r_d = ||P^-1 (eta (x - x_prev) + rho (y - y_prev))||_infis the ADMM dual residual [m/s or rad/s].r_cis the maximum absolute impulse-velocity inner product over inequality blocks [J]. ThePfactors convert the first two residuals from solver scaling to physical constraint units.DVI: With physical impulse
lambdaand augmented constraint velocityv,r_pis the maximum infinity-norm projection distance of unilateral impulses from the nonnegative limit cone or Coulomb contact cone [N·s or N·m·s].r_dis the maximum of the corresponding velocity distance from the dual cone and the bilateral velocity violation [m/s or rad/s].r_c = max |lambda_k dot v_k|is the maximum inequality complementarity violation [J].LOX:
convergedanditerationsreport LOX’s native splitting termination state. With body twistsvof the smooth solve andpof the unilateral projection, and the splitting body weightW,r_p = ||W (v - p)||_infis the consensus residual [N·s or N·m·s] andr_d = ||v - v_prev||_infis the last change of the smooth solution [m/s or rad/s].r_cis the squared maximum Delassus-scaled natural-map residual of the joint-friction, limit, and contact rows under their contact law [J], which measures feasibility and complementarity together. These residuals do not require solution metrics; they are NaN before a solve and for failed worlds. LOX additionally reportsfailed; a world that is neither converged nor failed reached the iteration limit and uses its last projected iterate. A failed world stays failed until it is reset, for example withsolver.reset(..., world_mask=...). Until then, LOX skips its solve, and its bodies keep their input velocity, without gravity, joint or contact forces, so checkfailedto detect and reset these worlds.
These are absolute maxima: no backend divides them by a reference norm, constraint count, or tolerance. Additional fields are not portable between backends.
status = solver.status
assert status.device == model.device
assert status.shape == (model.world_count,)
# Host inspection is explicit and synchronizes the device-to-host copy.
status_host = status.numpy()
unconverged_worlds = (~status_host["converged"].astype(bool)).nonzero()[0]
Terminal status is always maintained. collect_solver_info=True enables
additional solver diagnostics and adds runtime and memory overhead; it is not
required to access status.
Actuation and forward kinematics#
Kamino dynamics routes actuation independently for each joint DoF. A DoF can use explicit effort, unbounded implicit PD, or effort-limited implicit PD; passive armature, damping, and Coulomb friction are likewise configured per DoF. Implicit-PD target modes require a non-zero applicable gain: velocity mode requires derivative gain, while position-based modes require proportional or derivative gain. Coulomb friction supports all non-free joint types, while joint dynamics and implicit PD currently support revolute, prismatic, and gimbal joint types only.
The forward-kinematics solver still partitions each joint as entirely passive
or entirely actuated. Different non-passive target modes are allowed within a
joint, but mixing passive and actuated DoFs within one joint is not yet
supported. The fk_actuation_flag model attribute provides an explicit
joint-level override for this FK partition.