Commit 1a1c5d5
Add joint motors for revolute and prismatic joints (#913)
# Objective
Supports velocity and position control with optional
timestep-independent spring-damper parameters (frequency,
damping_ratio). Includes warm starting and motor force feedback via
JointForces.
**Partially** fixes #465
This implementation only works for joints with a single axis
(`PrismaticJoint`, `RevoluteJoint`).
Additional work is needed to support multiple axes (`SphericalJoint`).
## Solution
Add three `MotorModel`: `ForceBased` and `AccelerationBased` are
directly inspired from the Rapier eponymous models, the `SpringDamper`
model doesn't exists in Rapier but seems much easier to use to me. The
latter is the default.
The motors are solved through XPBD like any other joint constraint.
Relevant Rapier sources:
-
[src/dynamics/joint/motor_model.rs](https://github.com/dimforge/rapier/blob/134132900adfb73e8ae7d062b0fed83a06ab8c30/src/dynamics/joint/motor_model.rs)
-
[src/dynamics/joint/generic_joint.rs](https://github.com/dimforge/rapier/blob/134132900adfb73e8ae7d062b0fed83a06ab8c30/src/dynamics/joint/generic_joint.rs)
-
[dynamics/solver/joint_constraint/joint_constraint_builder.rs](https://github.com/dimforge/rapier/blob/134132900adfb73e8ae7d062b0fed83a06ab8c30/src/dynamics/solver/joint_constraint/joint_constraint_builder.rs)
-
[src/dynamics/joint/revolute_joint.rs](https://github.com/dimforge/rapier/blob/134132900adfb73e8ae7d062b0fed83a06ab8c30/src/dynamics/joint/revolute_joint.rs)
-
[src/dynamics/joint/prismatic_joint.rs](https://github.com/dimforge/rapier/blob/134132900adfb73e8ae7d062b0fed83a06ab8c30/src/dynamics/joint/prismatic_joint.rs)
## Breaking change
<details>
<summary>(first commit only, outdated by the second one)</summary>
The current implementation minimizes breaking changes, however, users
who directly add the XPBD solver systems instead of using the plugin
will have to make changes for motors to work:
<img width="1081" height="386" alt="Screenshot from 2026-01-04 14-22-18"
src="https://github.com/user-attachments/assets/59fa9c92-5f58-4036-b8b5-f17a7f06bdfb"
/>
Similarly, users who manually implemented `XpbdConstraint` for custom
joints may need to implement `XpbdMotorConstraint` instead if they want
motors to work.
</details>
Users who manually implemented `XpbdConstraint` for custom joints may
need to write a custom implementation for the new
`XpbdConstraint::warm_start_motors` method as its default implementation
does nothing.
Users who manually add the `solve_xpbd_joint` systems instead of using
the plugins may need to also add `warm_start_xpbd_motors`. (why would
anyone do that though?)
## Testing
- A reasonable series of unit tests is included in the PR,
- The `joint_motors_2d` and `joint_motors_3d` examples provide an
interactive way to test these,
- I used these examples to manually perform a brief test of
motors+limits, no surprises there,
- I couldn't find proper test vectors so there currently is no test
scenario where it is verified that a specific motor configuration
reaches a specific state in a precise time interval.
---
## Showcase
<details>
<summary>Concise showcase</summary>
```rust
// Position-controlled motor (e.g., servo arm)
RevoluteJoint::new(anchor, arm)
.with_motor(AngularMotor {
enabled: true,
target_position: PI / 4.0, // 45 degrees
max_torque: 100.0,
motor_model: MotorModel::SpringDamper {
frequency: 2.0,
damping_ratio: 1.0, // critically damped
},
..default()
})
// Velocity or position can then be set on demand
fn set_motor_position(mut joints: Query<&mut RevoluteJoint>) {
for mut joint in &mut joints {
if let Some(motor) = joint.motor.as_mut() {
motor.target_position = PI / 2.0; // 90 degrees
}
}
}
```
</details>
See the examples included in this PR for more detailed examples.
[Screencast from 2026-01-11
14-55-37.webm](https://github.com/user-attachments/assets/2246dad7-2638-4741-9bf0-4d74ae5c0cee)
---------
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>1 parent 1d7e7c2 commit 1a1c5d5
File tree
15 files changed
+2234
-17
lines changed- crates
- avian2d
- examples
- avian3d
- examples
- migration-guides
- src/dynamics
- joints
- solver/xpbd
- joints
15 files changed
+2234
-17
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
194 | 194 | | |
195 | 195 | | |
196 | 196 | | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
197 | 201 | | |
198 | 202 | | |
199 | 203 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
173 | 173 | | |
174 | 174 | | |
175 | 175 | | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
176 | 180 | | |
177 | 181 | | |
178 | 182 | | |
| |||
0 commit comments