Affine Body Revolute Joint External Force
#668 AffineBodyRevoluteJointExternalForce
The Affine Body Revolute Joint External Force applies a scalar external torque around the axis of a Revolute Joint. The torque drives rotational motion between the two connected affine bodies about the shared joint axis.
Torque Application
Given a scalar torque \(\tau\) and the joint axis direction \(\hat{\mathbf{e}}\), the external torque is converted into a translational force at each body's center of mass. The torque produces equal-and-opposite tangential forces on the two bodies:
where:
- \(\tau\) is the scalar torque magnitude (per edge)
- \(\hat{\mathbf{e}}_k\) is the normalized joint axis direction in body \(k\)'s current frame
- \(\mathbf{r}_k\) is the lever arm vector from the joint axis to body \(k\)'s center of mass, perpendicular to the axis
- \(\mathbf{0}_9\) denotes the nine-dimensional zero vector (no affine force component)
Axis Direction
The joint axis is defined by two points \(\mathbf{x}^0\) and \(\mathbf{x}^1\) on each body, following the Revolute Joint convention. The axis direction in world space is:
where \(\mathring{\mathbf{J}}^{\hat{e}}_k\) maps the rest-space axis direction through the current affine transform.
Lever Arm
The lever arm \(\mathbf{r}_k\) is the perpendicular distance from the joint axis to the center of mass of body \(k\):
where \(\mathbf{d}_k\) is the vector from the axis point to the center of mass in world space.
When \(\|\mathbf{r}_k\|^2 < \epsilon\) (the center of mass lies on the axis), the force contribution for that body is zero.
Sign Convention
A positive \(\tau\) applies torque to body \(j\) in the \(+\hat{\mathbf{e}}\) direction (counterclockwise when viewed along \(+\hat{\mathbf{e}}\), right-hand rule) and an equal-and-opposite reaction torque to body \(i\).
Energy Integration
The external forces are incorporated into each affine body's kinetic energy term through the predicted position \(\tilde{\mathbf{q}}\), following the same mechanism as AffineBodyExternalForce:
where \(\tilde{\mathbf{q}}\) is updated each time step to include the acceleration from the external force:
State Update
At the end of each time step, the time integrator computes the current joint angle:
where \(\theta(\mathbf{q})\) is the revolute angle extracted from the current affine body states, and \(\theta_{\text{init}}\) is the initial angle offset captured at the start of the simulation. The angle is mapped to the range \((-\pi, \pi]\). This value is written back to the angle attribute for user inspection via the Animator.
Runtime Control
The torque can be updated at each frame through the Animator system:
- Set
external_torque/is_constrainedto1to enable the torque, or0to disable it. - Modify the
external_torqueattribute to change the torque magnitude.
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:
external_torque: \(\tau\) in the formulae above, scalar torque around the joint axis (one per edge)external_torque/is_constrained: enables (1) or disables (0) the external torqueangle: \(\theta_{\text{current}}\), the current joint angle in radians (updated by the backend each time step)