dimforge / rapier

2D and 3D physics engines focused on performance.
https://rapier.rs
Apache License 2.0
3.93k stars 244 forks source link

Revolute joint motor target position is broken at and beyond 90 degree angles #378

Closed fatho closed 9 months ago

fatho commented 2 years ago

Summary

When setting the target angle of a 2D revolute joint motor to 90 degrees, it starts spinning uncontrollably.

When setting the target angle to something larger, e.g. 135 degrees, it instead converges to 45 degrees.

Reproducer

I added the following file to the examples2d testbed.

When setting the joint motor angle to 45f32.to_radians(), it behaves as expected (after some wobbling, it converges to the 45 degree position).

However, when setting it to 90f32.to_radians() as in the example below, it just keeps spinning.

Setting it to 135f32.to_radians() behaves the same as the 45 degree case.

`motor2.rs` testbed reproducer ```rust use rapier2d::prelude::*; use rapier_testbed2d::Testbed; pub fn init_world(testbed: &mut Testbed) { /* * World */ let mut bodies = RigidBodySet::new(); let mut colliders = ColliderSet::new(); let mut impulse_joints = ImpulseJointSet::new(); let multibody_joints = MultibodyJointSet::new(); /* * The ground */ let ground_size = 5.0; let ground_height = 0.1; let rigid_body = RigidBodyBuilder::fixed().translation(vector![0.0, -ground_height]); let ground_handle = bodies.insert(rigid_body); let collider = ColliderBuilder::cuboid(ground_size, ground_height); colliders.insert_with_parent(collider, ground_handle, &mut bodies); /* * A rectangle on a motor */ let rigid_body = RigidBodyBuilder::dynamic().translation(vector![0.0, 2.0]); let handle = bodies.insert(rigid_body); let collider = ColliderBuilder::cuboid(0.1, 0.5); colliders.insert_with_parent(collider, handle, &mut bodies); let joint = RevoluteJointBuilder::new() .local_anchor1(point![0.0, 2.0]) .motor_position(90f32.to_radians(), 5.0, 0.5); impulse_joints.insert(ground_handle, handle, joint, true); /* * Set up the testbed. */ testbed.set_world(bodies, colliders, impulse_joints, multibody_joints); testbed.look_at(point![0.0, 0.0], 40.0); } ```
pellico commented 1 year ago

Confirm same behavior with latest version 0.15.0. I find a workaround by changing stiffness to 100.0, and damping 40.0. However it is not possible to move outside the range [-90,90] degrees. It seems that the angles outside [-90,90] are modified angle -180 if angle is positive and +180 is angle is negative e.g setting 350 degree the body move to angle ~ 0 degrees.

tomsmalley commented 1 year ago

Also running into issues around this. Seems to also affect revolute joints using limits without motors.

Stepping through a range of limits from [0.0, 0.0] -> [180.0, 180.0] (degrees) works correctly (i.e. removing the remaining degree of freedom), but once you go beyond 180 the limit starts moving backwards in the wrong direction.

pellico commented 1 year ago

I posted a possible fix. I reused the example of @fatho to create one example to check the issue and the fix. Thanks @fatho 🥇