Skip to content

Commit

Permalink
removed obsolete code, adapt some wordings
Browse files Browse the repository at this point in the history
  • Loading branch information
Vrixyz committed Feb 19, 2025
1 parent 904ce87 commit 29afe9c
Showing 1 changed file with 6 additions and 227 deletions.
233 changes: 6 additions & 227 deletions docs/user_guides/templates/joint_constraints.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ mathematical constraints to be generated. The clear advantage is that there is n
any motion other than that single rotation to this body, meaning there is no way the body shifts to a position that is
not realistic, even if the dynamics solver does not converge completely.

Rapier implements this approach through `MultiBodyJointSet`,
Rapier implements this approach through `MultibodyJointSet`,
where each joint is attached to its relevant rigid-bodies identified by their handle.

## Constraints-based approach
Expand Down Expand Up @@ -85,233 +85,16 @@ the Multibody joints example from the [demo](/demos3d). The constraints-based ap
[joint constraints](./advanced_collision_detection.mdx#joint-constraints) section and demonstrated by the [Joint constraints](/all_examples3/?constraints) demo.

## Multibodies

Multibodies implement the reduced-coordinates approach. A multibody is a set of **multibody links** attached together by
a **multibody joint**.


### Creating a multibody
Creating a multibody is done link-by-link using the `MultibodyDesc` structure based on the builder pattern. Each link
of a multibody is described by a single `MultibodyDesc` to which children links can be added by calling the `.add_child`
method. This method will itself return a new `MultibodyDesc` that can be used to initialize the child, create even
more nested children, etc.


<ul class="nav nav-tabs">
<li class="active"><a id="tab_nav_link" data-toggle="tab" href="#multibody_desc_2D">2D example</a></li>
<li><a id="tab_nav_link" data-toggle="tab" href="#multibody_desc_3D">3D example</a></li>
</ul>

<div class="tab-content" markdown="1">
<div id="multibody_desc_2D" class="tab-pane in active">
```rust
use na::{Vector2, Point2, Isometry2, Matrix2};
use nphysics2d::object::MultibodyDesc;
use nphysics2d::joint::{RevoluteJoint, PrismaticJoint};
use nphysics2d::math::{Velocity, Inertia};

let joint = RevoluteJoint::new(-0.1);
let mut multibody_desc = MultibodyDesc::new(joint)
// The velocity of this body.
// Default: zero velocity.
.velocity(Velocity::linear(1.0, 2.0))
// The angular inertia tensor of this rigid body, expressed on its local-space.
// Default: the zero matrix.
.angular_inertia(3.0)
// The rigid body mass.
// Default: 0.0
.mass(1.2)
// The mass and angular inertia of this rigid body expressed in
// its local-space. Default: zero.
// Will override `.mass(...)` and `.angular_inertia(...)`.
.local_inertia(Inertia::new(1.0, 3.0))
// The center of mass of this rigid body expressed in its local-space.
// Default: the origin.
.local_center_of_mass(Point2::new(1.0, 2.0))
/// The position of the joint wrt. `parent`, expressed in the local
/// frame of `parent`.
/// Default: Vector2::zeros()
.parent_shift(Vector2::new(1.0, 2.0))
/// The position of the newly created multibody link wrt. the joint,
/// expressed in the local frame of the joint.
/// Default: Vector2::zeros()
.body_shift(Vector2::new(1.0, 2.0));

/// Add a children link to the multibody link represented by `multibody_desc`.
let child_joint = PrismaticJoint::new(Vector2::y_axis(), 0.0);
multibody_desc.add_child(child_joint)
// The `add_child` method returns another `MultibodDesc` used to
// set the properties of the child. It is also possible to call
// `.add_child` on this child.
.body_shift(Vector2::x() * 2.0);


/// We can add a second child to our multibody by re-using the initial `multibody_desc`:
let second_child_joint = RevoluteJoint::new(2.3);
multibody_desc.add_child(second_child_joint);

/// Actually build the multibody.
let multibody = multibody_desc.build();
// Finally, wa may add this multibody to a body set.
let multibody_handle = body_set.insert(multibody);

```
</div>
<div id="multibody_desc_3D" class="tab-pane">
```rust
use na::{Vector3, Point3, Isometry3, Matrix3};
use nphysics3d::object::MultibodyDesc;
use nphysics3d::joint::{RevoluteJoint, PrismaticJoint, HelicalJoint};
use nphysics3d::math::{Velocity, Inertia};

let joint = RevoluteJoint::new(-0.1);
let mut multibody_desc = MultibodyDesc::new(joint)
// The name of this multibody link.
// Default: ""
.name("my multibody link".to_owned())
// The velocity of this body.
// Default: zero velocity.
.velocity(Velocity::linear(1.0, 2.0, 3.0))
// The angular inertia tensor of this rigid body, expressed on its local-space.
// Default: the zero matrix.
.angular_inertia(Matrix3::from_diagonal_element(3.0))
// The rigid body mass.
// Default: 0.0
.mass(1.2)
// The mass and angular inertia of this rigid body expressed in
// its local-space. Default: zero.
// Will override `.mass(...)` and `.angular_inertia(...)`.
.local_inertia(Inertia::new(1.0, Matrix3::from_diagonal_element(3.0)))
// The center of mass of this rigid body expressed in its local-space.
// Default: the origin.
.local_center_of_mass(Point3::new(1.0, 2.0, 3.0))
/// The position of the joint wrt. `parent`, expressed in the local
/// frame of `parent`.
/// Default: Vector3::zeros()
.parent_shift(Vector3::new(1.0, 2.0, 3.0))
/// The position of the newly created multibody link wrt. the joint,
/// expressed in the local frame of the joint.
/// Default: Vector3::zeros()
.body_shift(Vector3::new(1.0, 2.0, 3.0));

/// Add a children link to the multibody link represented by `multibody_desc`.
let child_joint = PrismaticJoint::new(Vector2::y_axis(), 0.0);
multibody_desc.add_child(child_joint)
// The `add_child` method returns another `MultibodDesc` used to
// set the properties of the child. It is also possible to call
// `.add_child` on this child.
.body_shift(Vector3::x() * 2.0);


/// We can add a second child to our multibody by re-using the initial `multibody_desc`:
let second_child_joint = HelicalJoint::new(Vector3::y_axis(), 1.0, 0.0);
multibody_desc.add_child(second_child_joint);

/// Actually build the multibody.
let multibody = multibody_desc.build();
// Finally, wa may add this multibody to a body set.
let multibody_handle = body_set.insert(multibody);
```
</div>
</div>

:::note
The first multibody link of a multibody is necessarily attached to an implicit fixed ground. Note however that
"attached" is a bit misleading here. Indeed if `joint` is set to an instance of `FreeJoint`, then this first
multibody link will have all the possible degrees of freedom, making it completely free to perform any movement.
:::

:::warning
The `FreeJoint` can be used only by the first link of the multibody, otherwise, the creation of the
multibody will panic.
:::

While it is not possible to remove a link from an existing multibody, it is possible to add new links:

```rust
// This will create the multibody links identified by `multibody_desc`
// and all its children. The multibody link identified by `multibody_desc`
// is then attached as a child of the pre-existing multibody link identified
// by `parent_handle`.
multibody_desc.build_with_parent(multibody, link_id);
```

:::note "Multibody link part handles"
The `BodyPartHandle` identifying a specific link of a multibody can be constructed with `BodyPartHandle(handle, i)`
where `handle` is the multibody handle, and `i` designates the `i`-th link of the multibody. Multibody links
are indexed in their creation order.
:::
The API to create a Multibody joint is similar to creating an Impulse Joint, refer to [Joints](./joints.mdx),
but insert those into a `MultibodyJointSet`.

Alternatively, you may retrieve a reference to a multibody link and its index using its name set during its construction:

```rust
for link in multibody.links_with_name("my multibody link name") {
/// ...
}
```

You may refer to the [code](https://github.com/rustsim/nphysics/blob/master/examples3d/multibody3.rs) of
[that demo](/all_examples3/?multibody) for concrete examples of multibody creation.

### Removing a multibody
The removal of a multibody from the body set uses the same method as the removal of a rigid-body: `body_set.remove(handle)`.
It is not possible to remove a single link of a multibody without removing the whole multibody altogether.

<hidden>

<technote>This part should belong in a GenericJoint section within joints.mdx.</technote>


### Multibody joint limits and motors
It is often desirable to limit the amplitude of movement a multibody link can have with regard to its parent. For
example we might want to limit the minimum and maximum value for the DOF of a prismatic joint in order to simulate a
piston with finite stroke. Or we might want to limit the maximum angle a revolute joint can make with regard to its
parent. Those are modeled by **joint limits**. Joint limits are currently only implemented for multibody joints with
DOF that are independent from each other. Therefore, it is not implemented for the `FreeJoint`, `BallJoint`, and
`CartesianJoint`. All other joints have methods similar to the following:

| Method | Description |
|-- | -- |
| `.enable_min_angle(limit)` | Sets the minimum angle (in radians) the joint angular DOF can take. |
| `.enable_max_angle(limit)` | Sets the maximum angle (in radians) the joint angular DOF can take. |
| `.disable_min_angle()` | Disable the lower angle limit. |
| `.disable_max_angle()` | Disable the upper angle limit. |
| `.enable_min_offset(limit)` | Sets the minimum offset the joint linear DOF can take. |
| `.enable_max_offset(limit)` | Sets the maximum offset the joint linear DOF can take. |
| `.disable_min_offset()` | Disable the lower offset limit. |
| `.disable_max_offset()` | Disable the upper offset limit. |

:::note
Joints with no angular DOF will not have the methods related to the angular limits. Similarly, joints with no linear DOF will not have the methods related to the linear limits. Joints with several angular or linear DOF will have those methods with an index appended to their name, e.g., the `.enable_min_angle_1(limit)` method of an universal joint will enable a lower limit for its first angular DOF.
:::

---------------

It is also often desirable to motorize a joint to impose a movement. For example simulating a motorized car wheel can be achieved by enabling a motor on a revolute joint linking the wheel with the car frame. A motor is specified by a target velocity and a maximum force. **nphysics** will apply forces at the motorized joint so that the joint reaches the target velocity, but will never apply a force that is stronger than some maximum user-defined value. Setting a small maximum force can be useful for having the joint accelerate progressively. In any case, setting a maximum motor force is **highly recommended**.

:::warning
Not setting any maximum force implies that **nphysics** is allowed to generate any force as large as necessary to reach the target velocity in one timestep. This is strongly discouraged because that can lead to odd behaviors. For example if a motorized pendulum with no maximum force hits a wall, the non-penetration constraint due to the contact will have to generate a force that counteracts the effect of the motor force. However this will not be possible given the motor is free to apply any, potentially infinite, force. This can result in the pendulum traversing the wall.
:::

For the moment, joint motors are only implemented for multibody joints with DOF that are independent from each other. Therefore, it is not implemented for `FreeJoint`, `BallJoints`, and `CartesianJoints`. All other joints have methods similar to the following:

| Method | Description |
|-- | -- |
| `.enable_angular_motor()` | Activate the angular motor. |
| `.disable_angular_motor()` | Disable the angular motor. |
| `.set_desired_angular_motor_velocity(vel)` | Set the angular velocity the motor must achieve. Setting this to `0.0` is possible and will simulate joint friction. |
| `.set_max_angular_motor_torque(max)` | Sets the maximum torque the motor can deliver to reach the desired velocity. |
| `.enable_linear_motor()` | Activate the linear motor. |
| `.disable_linear_motor()` | Disable the linear motor. |
| `.set_desired_linear_motor_velocity(vel)` | Set the velocity the motor must achieve. Setting this to `0.0` is possible and will simulate joint friction. |
| `.set_max_linear_motor_force(max)` | Sets the maximum linear force the motor can deliver to reach the desired velocity. |

:::note
Joints with no angular DOF will not have the methods related to the angular motors. Similarly, joints with no linear DOF will not have the methods related to the linear motors. Joints with several angular or linear DOF will have those methods with an index appended to their name, e.g., the `.enable_angular_motor_1()` method of an universal joint will enable a motor for its first angular DOF.
:::

</hidden>

## Combining joint constraints
## Combining both

A joint constraint geometry is completely configured at its creation, and added to the joint set by the
`joint_set.insert(&mut bodies, body1, body2, joint, true)` method by specifying the handles of the bodies the joint is
Expand All @@ -327,8 +110,4 @@ The 5th joint that closes the loop must be modeled as a joint constraint, here a

<center>
![Loop-closing constraint](/img/loop_closing_joint.svg)
</center>

:::note
Note that using the world to create multibody links removes any risk of inadvertently creating multibody links attached in such a way that they would form anything but a tree structure.
:::
</center>

0 comments on commit 29afe9c

Please sign in to comment.