Affine Body Driving Revolute Joint
References:
A unified newton barrier method for multibody dynamics
#19 AffineBodyDrivingRevoluteJoint
The Affine Body Driving Revolute Joint is a constraint constitution that drives a Revolute Joint (UID=18) to a target angle. It must be applied to a geometry that already has an AffineBodyRevoluteJoint constitution.
The driving joint supports two operating modes:
- Active mode (
is_passive = 0): the joint drives toward a user-specifiedaim_angle. - Passive mode (
is_passive = 1): the joint resists external forces by treating the current angle as the target, effectively locking the joint in place.
The constraint can also be toggled on and off at runtime via the is_constrained flag.
Energy
We assume 2 affine body indices \(i\) and \(j\), each with their own state vector \(\mathbf{q}_i\) and \(\mathbf{q}_j\) as defined in the Affine Body constitution.
The current relative rotation angle \(\theta\) between the two bodies about the joint axis is extracted from the affine body states using the joint axis and normal rest frames, as defined in the Revolute Joint:
where \(\hat{\mathbf{n}}\) and \(\hat{\mathbf{b}}\) are the normal and binormal directions in each body's frame.
The target angle \(\tilde\theta\) is determined by:
where \(\theta_{\text{init}}\) is the initial angle offset captured at the start of the simulation.
The energy function is:
where \(K = \gamma (m_i + m_j)\), \(\gamma\) is the user defined strength_ratio parameter, and \(m_i\), \(m_j\) are the masses of the two affine bodies.
When is_constrained = 0, the energy is zero and the driving effect is disabled.
State Update
At the end of each time step, the time integrator updates the angle attribute to reflect the current joint angle:
where \(\text{map}_{[-\pi,\pi]}\) maps the angle into \((-\pi, \pi]\).
Requirement
This constitution must be applied to a geometry that already has an AffineBodyRevoluteJoint (UID=18) constitution.
Attributes
On the joint geometry (1D simplicial complex), on edges:
driving/strength_ratio: \(\gamma\) in \(K = \gamma(m_i + m_j)\) aboveis_constrained: enables (1) or disables (0) the driving effectis_passive: passive mode (1) locks at the current angle; active mode (0) drives toaim_angleaim_angle: \(\theta_{\text{aim}}\), the target angle in active modeangle: \(\theta_{\text{current}}\), the current relative angle (updated by the backend each time step)init_angle: \(\theta_{\text{init}}\), the initial angle offset