How much force do i need to apply in one frame in order for an object to stop at exact displacement?

Hi guys,

I am doing an experiment that I want to apply a force in one frame to a rigidbody using add force and I want it to be stop by friction at some displacement. I tried to calculate the force I need in the following code:

        hitPosition = this.transform.position;
        isHitRecord = true;
        hitTime = DateTime.Now;
        var gravityDivide = Vector3.ProjectOnPlane(Physics.gravity, groundNormal) * ridbody.mass;
        var gravityFrictionDivide = Physics.gravity - gravityDivide;
        var frictionForceAcceleration =  bodyCollider.material.dynamicFriction * gravityFrictionDivide.magnitude;

        var desiredV0 = (float)Math.Sqrt((2 * frictionForceAcceleration * distance));
        var acceleration = desiredV0 / Time.fixedDeltaTime;

to calculate my desired v0 and apply the force with m * a, but the result is not quite what I want. What am I doing wrong? Any help appreciated

Drag is a not a constant force, since it depends of the velocity.

However, you can approximate the behavior to an uniform accelerated motion if the displacement is small.

https://en.wikipedia.org/wiki/Acceleration#Uniform_acceleration

For instance, for displacement, the formula is speed = speed_initial^2 + 2*acceleration*displacement. Speed is 0, because you want to stop,
So drag (acceleration) = -speed_initial^2/(2*expected_displacement)

If you need an instant stop, you can generate an impulse opposite to the movement

Here's an example

using UnityEngine;

public class Stop : MonoBehaviour
{
    public Rigidbody rb;

    public Vector3 dragAcc;

    public bool doDrag;
    public float expectedTime = 1;
    public float expectedDisplacement = 5f;

    public Vector3 positionStamp;
    public float timeStamp;
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            OneFrameStop();
        }
        if (Input.GetKeyDown(KeyCode.X))
        {
            //dragAcc = CalculateDragWithTime(rb.velocity, expectedTime);
            dragAcc = CalculateDragWithDisplacement(rb.velocity, expectedDisplacement);
            rb.useGravity = false;
            doDrag = true;
            positionStamp = transform.position;
            timeStamp = Time.time;
        }
    }

    private void OneFrameStop()
    {
        Vector3 impulse = -rb.velocity; //just for testing
        rb.AddForce(impulse, ForceMode.VelocityChange);
        rb.useGravity = false;
    }

    private void FixedUpdate()
    {
        if (doDrag && rb.velocity.magnitude < 0.01f)
        {
            doDrag = false;

            float displacement = (transform.position - positionStamp).magnitude;
            float time = Time.time - timeStamp;

            print($"Time: Expected {expectedTime}. Actual {time}. Displacement: Expected {expectedDisplacement}. Actual {displacement}");
        }

        if (doDrag)
        {
            rb.AddForce(dragAcc, ForceMode.Acceleration);
        }
    }

    private static Vector3 CalculateDragWithTime(Vector3 velocity, float expectedTime)
    {

        return -velocity / expectedTime;
    }

    private static Vector3 CalculateDragWithDisplacement(Vector3 velocity, float expectedDisplacement)
    {

        float speed = velocity.magnitude;
        return (-speed * speed) / (2f * expectedDisplacement) * velocity.normalized;
    }
}