Physics PID system or something that tracks real life movement well?

edited in Questions and Answers
I've been trying to figure out a physics system that tracks real life positions (in VR) and moving in-game rigidbodies to that target. The point is to simulate physical movements without just setting position/orientation, so that physics can be applied with some sort of accuracy.

Use cases are like arm controllers in games like Gorn, and something like this:
https://www.reddit.com/r/Unity3D/comments/enqn5v/working_on_finger_physics_for_vr_quest_time_to/?utm_source=share&utm_medium=web2x

The best attempt I've had is using a PID system I found somewhere, but even then it's a bit of a difficult tweak and hit and miss (the outcome lags behind the input movement significantly)

This is what I've been using, but any ideas about improving it, or tips/pointers at a better system?

public static void MoveWithForceTo(Rigidbody targetRigid, Vector3 fromPoint, Vector3 toPoint, float ftoVel, float fmaxVel, float fmaxForce, float fgain)
	{
		Vector3 dist = toPoint - fromPoint;
		// calc a target vel proportional to distance (clamped to maxVel)
		Vector3 tgtVel = Vector3.ClampMagnitude(ftoVel * dist, fmaxVel);
		// calculate the velocity error
		Vector3 error = tgtVel - targetRigid.velocity;
		// calc a force proportional to the error (clamped to maxForce)
		Vector3 force = Vector3.ClampMagnitude(fgain * error, fmaxForce);
		targetRigid.AddForce(force);
	}


ftoVel, fmaxVel, fmaxForce, fgain are values that I just tweak a bunch. But still damn hard to get to oscillation-free or following actual movement at a convincing rate.

@raithza could you give input based on the excellent in Gorn's phyisics?

Thanks guys :)

Comments

  • edited
    Regarding PID controllers, choosing the right values for your PID controller makes a really big difference. It's also the hardest part about using a PID controller. :(

    If things lag behind a lot, then you usually want to increase the "P" value. (In your case, it looks like it's ftoVel and fmaxVel.)
    If things overshoot a lot, then you usually want to increase the "D" value. (I guess that's your fgain?)
    The "I" is a catch-up value, where the longer something takes to get somewhere, the more additional force it adds... which can work great, or lead to even more overshooting. Your implementation doesn't seem to include this (but it's arguably the least important and most difficult to guess).

    --
    I may be wrong, but I think you can also attach kinematic rigidbodies to your hands, and they'll move with your controller movement one-to-one. You can then use various joints to attach other rigidbodies to the kinematic ones, and let Unity physics solve that, instead of using PIDs. I think this is what was done in GORN -- the base of the weapon is a kinematic rigidbody, and the rest of the weapon is made up of non-kinematic rigidbodies that are attached to it with various joints.
    Thanked by 2Tuism ashashza
  • @Elyaradine yeah tweaking those values have been a huge headache. I got this from some googling a while back and I can't say I know how to put in an "I" or even if it's something that could work for me :/

    The major issue I'm trying to wrap my head around, is to let physics move a thing (hands usually, but in the video example above, fingers and bits of hands) to the target instead of setting the position. So the net effect is that the parts can get stopped against things or push things along, does that make sense?

    I get that kinematic attached to hands parts get their positions set "inside" a second world object, that object is mobile, can/will result in the solver pushing the second object out. But if the second object is immobile, it just bugs out instead of being stopped, right? I'm trying to get around that.

    Ah right basically the Boneworks effect.
  • It seems like PID controller problems pop up every now and then. I remember @francoisvn gave an explanation a while back about how you probably don't need a PID controller (Link).

    Just my 2c, I know PIDs seem tempting because of the results you can get with them but control engineering is really complicated and probably entirely unnecessary considering you won't be using the system in the physical world.

    I would suggest using a spring-damper system (I know Wilhelm Nylund from Landfall gets a huge amount of value out of them). The cool thing is that you aren't limited to using constants, depending on your situation you could sample animation curves to adjust the variables. Also, the variables are more understandable, and will probably be easier to tune.
    Thanked by 2francoisvn ashashza
  • So here is something I can mention, to help you wrap your head around how rigidbodies move (motion instead of explicit set values)

    The truth is unity also sets explicit values for rigidbodies after each fixedupdate...
    In the case of the rb having velocity, force or torque applied... those are just values it uses to orient and place the rb at the next physics step.

    If you calculate and set the position yourself, then it is the same thing. You are just jumping the line in terms of calculations. This is useful, because sometimes you might want to use certain physx functions without having actual physics motion.

    (If you DO use MovePosition instead of letting the built-in velocity resolve itself, then just remember to cancel/reset the built in velocity, or you could end up with unwanted additional drift after your careful positioning)

    So with that said, I am not very familiar with the PID system you are talking about, but in my mind, a naive approach would be to use a past point with recorded velocity, and a present point based on controller, and a future point with expected values...
    Then I would interpolate between them using bezier style code, (see catlike coding tutorial about splines) and apply the interpolated position (and rotation) explicitly with each fixedupdate, until the next readout comes in for a fresh set of bezier curve keypoints.

    Perhaps this naive rant will give you some helpful Ideas?


  • edited
    @Pierre If I'm understanding you correctly, you mean that I should just forgo the physics system and calculate positions myself? But the point is for my physics rigidbodies to interact with the world, in attempting to go to a location, rather than being at the target location. See what I mean?
  • edited
    You can. If you use rigidbody.moveposition, it still calculates collission and intersection. Obviously try not to move it too fast/far in a single frame.
    The point is, instead of using addforce, or addtorque, and letting the rigidbody move with simulated updates, you can calculate your own position for each update, and still have the benefit of physics.

    Take this as an example.
    If I have a rigidbody with a capsule collider...
    I freeze rotation on X and z, so it always stays upright.

    During fixedupdate I tell it to do the following...

    Vector3 velocity = rb.velocity;

    //clear dirty velocity to prevent unwanted drift (unless you actually do want simulated velocity in which case the none of this applies)
    Velocity.x = 0f;
    Velocity.y = 0f;
    // we don't clean y velocity, because we still want gravity to apply naturally.
    Rb.velocity = velocity:
    //now we explicitly move the character using moveposition;
    rb.moveposition(rb.position + vector3.forward * speed * Time.fixeddeltatime); **mind the typos***

    With this, I am explicitly updating the position without relying on force or torque.
    But
    The rigidbody will still Collide with the walls and terrain, and gravity, and it will move along the surface of small slopes in the terrain. (Provided "speed" is reasonable.... like 6 or something... at speeds of 10 I might start using sphere cast instead to predict collisions.)
    Thanked by 1critic
  • edited
    Also, keep in mind that if you use "iskinematic" true, then your object will not be deterred by other items... so if you want your object to stop when it hits a wall, then iskinematic should be false.
Sign In or Register to comment.