pub struct Model {
pub bodies: Vec<Body>,
pub joints: Vec<Joint>,
pub gravity: Vec3<f64>,
pub dt: f64,
pub nq: usize,
pub nv: usize,
pub q_offsets: Vec<usize>,
pub v_offsets: Vec<usize>,
pub actuators: Vec<Actuator>,
pub contact_exclude: Vec<(usize, usize)>,
}Expand description
Static model describing the topology and parameters of a physical system.
Fields§
§bodies: Vec<Body>Bodies in the kinematic tree (index 0 = first body, no world body).
joints: Vec<Joint>Joints connecting bodies.
gravity: Vec3<f64>Gravity vector in world frame.
dt: f64Integration timestep.
nq: usizeTotal number of position DOFs.
nv: usizeTotal number of velocity DOFs.
q_offsets: Vec<usize>Position DOF offset for each joint.
v_offsets: Vec<usize>Velocity DOF offset for each joint.
actuators: Vec<Actuator>Actuators (motors) acting on joints.
contact_exclude: Vec<(usize, usize)>Body pairs that must never produce a contact, beyond the structural
exclusions Model::may_collide applies on its own.
The escape hatch for authored geometry that overlaps across a moving joint — common in URDFs, where a shoulder capsule is drawn long enough to intersect the trunk box at some arm angles. Such a pair is a modelling artifact, not an event, but no rule derivable from the tree can tell it apart from a genuine self-touch, so it is data.
Order within a pair does not matter.
Implementations§
Source§impl Model
impl Model
Sourcepub fn default_state(&self) -> State
pub fn default_state(&self) -> State
Create a default empty state for this model.
Sourcepub fn actuator_forces(&self, ctrl: &DVec<f64>) -> DVec<f64>
pub fn actuator_forces(&self, ctrl: &DVec<f64>) -> DVec<f64>
Map actuator-space controls to generalized forces of dimension nv.
Each actuator’s control is clamped to its ctrl_range, scaled by gear,
and added to the first velocity DOF of the joint it drives.
When the model has no actuators, ctrl is interpreted as a raw per-DOF
generalized force and passed through unchanged — this keeps hand-built
models (which set state.ctrl per DOF) working.
Sourcepub fn actuator_forces_at(
&self,
ctrl: &DVec<f64>,
q: &DVec<f64>,
v: &DVec<f64>,
) -> DVec<f64>
pub fn actuator_forces_at( &self, ctrl: &DVec<f64>, q: &DVec<f64>, v: &DVec<f64>, ) -> DVec<f64>
Map actuator-space controls to generalized forces, evaluating the full affine actuator law against the joint’s current state.
Identical to Self::actuator_forces for plain motors. Position and
velocity servos need q and v, so this is the variant the dynamics
call; the state-free one remains for callers that only have controls.
Sourcepub fn contact_materials(&self, scene: &ContactMaterial) -> Vec<ContactMaterial>
pub fn contact_materials(&self, scene: &ContactMaterial) -> Vec<ContactMaterial>
One crate::ContactMaterial per body: each body’s own material where
it has one, and scene everywhere else.
This is what phyz_contact::assemble wants for its materials
argument. Callers used to write vec![material.clone(); n_bodies]
because there was no other way to fill the slice; that expression is
exactly model.contact_materials(&material) on a model whose bodies
all carry None, so switching to this call changes nothing until a
body is actually given a material.
The result is always at least one element long, since assemble treats
an empty slice as “defaults everywhere”.
Which body carries the material matters. Friction combines by
max — see ContactMaterial::combine — so a grippy body grips
everything it touches, including surfaces you wanted it to slide on.
Sourcepub fn set_body_material(
&mut self,
name: &str,
material: ContactMaterial,
) -> bool
pub fn set_body_material( &mut self, name: &str, material: ContactMaterial, ) -> bool
Attach material to the body named name, returning whether it
existed. The ergonomic form of model.bodies[i].material = Some(..)
when you have a name rather than an index — which is the usual case
after importing a URDF or MJCF.
Sourcepub fn body_index(&self, name: &str) -> Option<usize>
pub fn body_index(&self, name: &str) -> Option<usize>
Look up a body index by name.
Sourcepub fn joint_index(&self, name: &str) -> Option<usize>
pub fn joint_index(&self, name: &str) -> Option<usize>
Look up a joint index by name.
Sourcepub fn weld_groups(&self) -> Vec<usize>
pub fn weld_groups(&self) -> Vec<usize>
Weld-group id per body: bodies joined only by JointType::Fixed
joints share an id, because no configuration can ever move them
relative to one another.
Used by contact filtering — see Model::may_collide. A welded pair
overlaps by construction (that is what a fixed joint usually
expresses: one physical part split across two links), and the
overlap is constant, so a contact between them is a permanent
unresolvable penetration rather than an event.
Transitive, so a chain A —fixed— B —fixed— C puts all three in one
group even though A and C are not parent and child.
Sourcepub fn may_collide(&self, i: usize, j: usize, welds: &[usize]) -> bool
pub fn may_collide(&self, i: usize, j: usize, welds: &[usize]) -> bool
May bodies i and j produce a contact with each other?
welds is Model::weld_groups, passed in so a detection loop
computes it once rather than per pair.
Three structural exclusions, none of them tunable, because each one describes a pair that is in contact in every configuration and so carries no information:
- A body with itself. Two shapes on one link cannot move relative to each other.
- Parent and child. The two links a joint connects overlap at the joint by construction — that is what a joint is. A humanoid has one such pair per joint, and left unfiltered they are the only contacts the narrow phase ever reports.
- Welded bodies. As (2), for links a fixed joint chain has made rigid with respect to each other.
Anything else — a hand reaching its own thigh, an arm crossing the
trunk — is a real event and is allowed through. Models needing a
further exclusion (geometry that overlaps across a moving joint, a
common URDF authoring artifact) list it in Model::contact_exclude.
Source§impl Model
impl Model
Sourcepub fn validate(&self) -> Vec<Issue>
pub fn validate(&self) -> Vec<Issue>
Check the model for authoring mistakes.
Returns every issue found, most serious first. An empty result means the model is self-consistent as far as these checks can tell — not that it is physically sensible.
Sourcepub fn fatal_issues(&self) -> Vec<Issue>
pub fn fatal_issues(&self) -> Vec<Issue>
Issues that make the model unusable.