Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bullet] Bullet Physics HingeJoint motor stops and restarts spinning every 360° #18351

Open
Tracked by #45022
Amil-francescolima74 opened this issue Apr 22, 2018 · 22 comments

Comments

@Amil-francescolima74
Copy link

Godot version:
Godot 3.0.2 official

OS/device including version:
macOS Sierra 10.12.6

Issue description:
Using HingeJoint and activating motor it stops and restarts spinning every 360°.
This happens only using default physics engine settings (Bullet).
Switching to Godot physic engine the motor spins regurarly.

Steps to reproduce:
Create a simple 3D scene and add a camera.
Add a StaticBody and a RigidBody with its own MeshInstance and CollisionShape using a cube as mesh.
Add a HingeJoint and in its nodes properties set the StaticBody (Node A) and the RigidBody (Node B).
In the HingeJoint properties enable the motor and run the project.

I made also a video, see the second half.
https://youtu.be/htBEKQu8Iy4

Minimal reproduction project:

HingeJoint_issue.zip

@lmjk
Copy link

lmjk commented Apr 24, 2018

On my machine (Fedora, 64bit) the cube does not resume spinning at all after the second time it stops. If I set motor/max_impulse as low as 0.06, the cube does not have full stops anymore, it only slows down temporarily instead.

@akien-mga
Copy link
Member

CC @AndreaCatania

@AndreaCatania
Copy link
Contributor

Thanks you for the issue report, I will let you know soon

@AndreaCatania
Copy link
Contributor

Can you please try to lower the max impulse?

It seems correctly implemented, I should check it with Erwin.

@Skwint
Copy link

Skwint commented May 19, 2018

I have this problem. Master branch, windows 7, 64 bit. I am having to lower my max impulse to 0.01 to prevent it happening - 0.03 and it pauses for half a second every time it reaches 180 degrees from the starting point. I can cheerfully provide a Godot project that demonstrates it if anyone needs. The default impulse is 1.0 on HingeJoints.

edit: Increasing the mass or target velocity also helps overcome the hiccup. I'd guess having a momentum significantly higher than the maximum impulse causes smaller problems. It is not going to sleep, although in the cases where it gets stuck forever I suspect it might be eventually going to sleep as a result of the bug, not the cause of it.

@Skwint
Copy link

Skwint commented May 21, 2018

OK, I've tracked it down. In
btHingeConstraint::getInfo2InternalUsingFrameOffset
there is a call to
btTypedConstraint::getMotorFactor
which passes in (and then uses) the angular limits of the constraint in calculating the force the motor will apply even if the limits are disabled. I consider this a bug in Bullet. We can work around it in Godot, however (well, for non extreme cases) by this. It's a one line change that means that the limits are pretty much never actually reached and so don't cause problems. I'm trying to attract the attention of some Bullet dudes to talk over their bit and see if it needs patching properly:

index 97ea7ca3d..cc8f18767 100644
--- a/modules/bullet/hinge_joint_bullet.cpp
+++ b/modules/bullet/hinge_joint_bullet.cpp
@@ -155,7 +155,7 @@ void HingeJointBullet::set_flag(PhysicsServer::HingeJointFlag p_flag, bool
p_val
        switch (p_flag) {
                case PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT:
                        if (!p_value) {
-                               hingeConstraint->setLimit(-Math_PI, Math_PI);
+                               hingeConstraint->setLimit(-1.5f * Math_PI, 1.5f * Math_PI);
                        }
                        break;
                case PhysicsServer::HINGE_JOINT_FLAG_ENABLE_MOTOR:

EDIT: I realize this may sound like I'm fixing it. I'm not. I'm just explaining how it can be!

@AndreaCatania
Copy link
Contributor

Erwin said me couple of times to not use Hinge joint since its implementation is really old, he told me to use btHinge2Constraint. It's a bit different compared to godot hinge and for this reason I didn't implemented it yet.

However I will change it soon, so this bug will be fixed

@MolbOrg
Copy link

MolbOrg commented Aug 27, 2018

3.1 still a problem

@wombatstampede
Copy link
Contributor

Confirming that this bug still occurs in 3.1beta3. (Bullet physics engine only)

The workaround (IMHO) is to use the Angular Motor of Generic6DOFJoint.

@theblacktiger59
Copy link

Wondering if there is any update on this issue ? (as it has been removed from the 3.2 milestone)
More specifically, is the Hinge joint in godot 3.2 still the old implementation ? (It does stop every turn still. And the Generic 6DOF Joint suffer a y axis gimbal lock.)

@pwab
Copy link

pwab commented Jun 12, 2020

More specifically, is the Hinge joint in godot 3.2 still the old implementation ?

As far as I can see nothing has changed since then. Went into this issue yesterday with current 3.2.1.stable.

Maybe this was dropped from 3.2 milestone because of the release in January and then it was forgotten to readd it to 4.0. Any chance this is getting on the list again @AndreaCatania?

@Zotyx
Copy link

Zotyx commented Nov 7, 2020

Hey @AndreaCatania, this problem still occrurs in v3.2.3. When will it be fixed please ?

@AndreaCatania
Copy link
Contributor

Hello, sorry for the delay I been busy this period and I can't tell an exact date when this will be fixed. Tho, the 6dof joint has a much better algorithm, you could consider using it in the meanwhile.

@pouleyKetchoupp pouleyKetchoupp changed the title Bullet Physics HingeJoint motor stops and restarts spinning every 360° [Bullet] Bullet Physics HingeJoint motor stops and restarts spinning every 360° Jan 20, 2021
@RedEagle09
Copy link

3.2.3, still not fixed >:(

@Calinou
Copy link
Member

Calinou commented Jul 22, 2021

3.2.3, still not fixed >:(

Can you reproduce this issue after upgrading to 3.3.2? The Godot 3.2.x series is not supported anymore.

@RedEagle09
Copy link

3.2.3, still not fixed >:(

Can you reproduce this issue after upgrading to 3.3.2? The Godot 3.2.x series is not supported anymore.

will try soon. will need to download it, as well as the export files...

@pwab
Copy link

pwab commented Jul 22, 2021

@Calinou I just opened the minimal reproduction project made by @Amil-francescolima74 in the web editor and the issue is still reproducible.

@RedEagle09
Copy link

@Calinou I just opened the minimal reproduction project made by @Amil-francescolima74 in the web editor and the issue is still reproducible.

how to workaround then?

@pwab
Copy link

pwab commented Aug 31, 2021

how to workaround then?

Well you could do the following:

  1. Deactivate the motor
  2. Add a constant angular_velocity
  3. Change the angular_damping to 0
  4. Add a script to give your body a constant push.

Now you have different possibilities:

  • Use add_torque in the _ready function
  • Use apply_impulse in the _process function
  • Use the PhysicsDirectBodyState to manipulate the velocity to your liking

Problem with the first two is, that if you want a (physically incorrect) motor that spins with a constant velocity even when under load you need to constantly check the angular_velocity and rise or lower the torque/impulse (you might need PID control then). With changing the state directly you can force the body to do what you want (haven't worked with states so this might be not correct).


I wanted to add a simple workaround example but I ran into #42842 so I really had to add a control sequence watching the velocity. I'm still not sure why the torque isn't applied constantly though (without readding torque the body slows down) 😕:

extends RigidBody

const torque = Vector3(0,0,1)

func _process(delta):
	if angular_velocity.z < 1:
		add_torque(torque)

I think it could be better to manipulate the velocity directly in the BodyState.

Give my solution a try if you wish:
hingejoint_issue_workaround.zip

@RedEagle09
Copy link

how to workaround then?

Well you could do the following:

1. Deactivate the motor

2. Add a constant `angular_velocity`

3. Change the `angular_damping` to 0

4. Add a script to give your body a constant push.

Now you have different possibilities:

* Use `add_torque` in the `_ready` function

* Use `apply_impulse` in the `_process` function

* Use the [PhysicsDirectBodyState](https://docs.godotengine.org/en/stable/classes/class_physicsdirectbodystate.html) to manipulate the velocity to your liking

Problem with the first two is, that if you want a (physically incorrect) motor that spins with a constant velocity even when under load you need to constantly check the angular_velocity and rise or lower the torque/impulse (you might need PID control then). With changing the state directly you can force the body to do what you want (haven't worked with states so this might be not correct).

I wanted to add a simple workaround example but I ran into #42842 so I really had to add a control sequence watching the velocity. I'm still not sure why the torque isn't applied constantly though (without readding torque the body slows down) 😕:

extends RigidBody

const torque = Vector3(0,0,1)

func _process(delta):
	if angular_velocity.z < 1:
		add_torque(torque)

I think it could be better to manipulate the velocity directly in the BodyState.

Give my solution a try if you wish:
hingejoint_issue_workaround.zip

will try that, except i think motor is in local coordinates, and angular velocity is in global, right? i dunno how to translate rotation from global to local space...

@pwab
Copy link

pwab commented Aug 31, 2021

will try that, except i think motor is in local coordinates, and angular velocity is in global, right? i dunno how to translate rotation from global to local space...

I think not. I'm pretty sure that the angular_velocity is a parameter based on the bodys local coordinate system.

But anyway: I found a better workaround!
As @AndreaCatania said you could use the Generic6DOFJoint. It also has the motor ability and the issue isn't present there.

Here is the reworked workaround (the one on the right is the 6DOFJoint):
hingejoint_issue_workaround.zip

@RedEagle09
Copy link

will try that, except i think motor is in local coordinates, and angular velocity is in global, right? i dunno how to translate rotation from global to local space...

I think not. I'm pretty sure that the angular_velocity is a parameter based on the bodys local coordinate system.

But anyway: I found a better workaround!
As @AndreaCatania said you could use the Generic6DOFJoint. It also has the motor ability and the issue isn't present there.

Here is the reworked workaround (the one on the right is the 6DOFJoint):
hingejoint_issue_workaround.zip

will try later. ty!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests