Search code examples
c#unity-game-enginemathgame-physics

Constant acceleration movement with minus acceleration


I making movement process on Unity.

I would like to make a process that moves the object to a specified position, but as the title suggests, I want the object not only to move, but also to reach a predetermined distance with its velocity decaying.

If the acceleration is negative, I can not to process it well. Specifically, I want to reach a position without turning back when the initial velocity is 10 as shown in the gif.

I used "s=v0t+1/2at^2" from the constant acceleration movement formula to find the acceleration "a", but that does not seem to be enough.

I would appreciate it if you could help me.

public class Test : MonoBehaviour
{
    public float t;
    public float initSpd;
    public Transform t1, t2;

    IEnumerator Start()
    {
        var p = t1.position;
        while (true) {
            t1.position = p;
            var v0t = initSpd * t;
            var distance = Vector2.Distance(t1.position, t2.position);
            var direction = (t2.position - t1.position).normalized;
            var a = (2 * (distance - v0t)) / (t * t);
            var v = initSpd;
            // update
            yield return Utils.Coroutine.WhileForSeconds(t, () =>
            {
                t1.Translate(direction * v * Time.deltaTime);
                v += a * Time.deltaTime;
            });
        }
    }
}

span=3, initial velocity=0 初速度=0 span=3, initial velocity=3 画像の説明をここに入力 span=3, initial velocity=10 画像の説明をここに入力

enter image description here


Solution

  • Your math to compute a is correct, but you have posed the problem in a way that cannot be solved to your satisfaction.

    As you said, with constant acceleration the position is a quadratic function of time, so it is described by

    s = b t^2 + c t + d
    

    for some constants b, c, d. The value of d is already fixed by the initial position. The value of c is already fixed by the initial velocity. There is only one free parameter left, and when you solve for s(finalTime) = goalPosition, you can't control whether or not the resulting parabola overshoots the goal or not.

    You can increase the polynomial degree, but there will always be some initial velocity that is too large and causes overshoot.

    Essentially, you have an optimal control / trajectory optimization problem, something like

      minimize: integral(acceleration(t)^2) from t = 0 to T
    subject to: x(0) given
                v(0) given
                x(T) given
                x(t) <= x(T) for all t in [0, T] (assuming x(0) < x(T))
    

    As you stated the problem, there was no optimization objective, but you need either a cost or a constraint on the acceleration, otherwise you could get solutions with infinite acceleration (e.g. accelerate really hard in the first time step, then coast to the goal at constant velocity).

    The inequality makes it complicated. If you want a continuous-time analytic solution, then Pontryagin's principle would be a hammer to solve it, but there might be easier tricks. If you discretize time and let the acceleration be piecewise-constant, then it's an easy convex optimization problem.

    If you are willing to relax the "never overshoot" and "get there at exactly this time" constraints, then very simple solution, that will scale better to more complex scenarios like external forces, is to use a feedback control law like a PD controller:

    a = kp * vectorToGoal - kd * velocityVector,
    

    where kp and kd are hand-tuned positive constants, and this expression is re-evaluated in every frame. You can tune kp and kd to minimize overshoot in your typical scenarios.

    Or, you could do what most games do - allow velocity to change instantaneously :)