How to drive Rigidbody.AddForce acceleration correctly from Update

I have a simulation which uses the Unity Rigidbody and some custom simple Euler integration (or similar models). It is required that all physics models can be driven (“steered”) by the same acceleration provider. This means I need to apply all forces in a predictable way.

For example, I move a Transform manually with a constant acceleration of 1 unit/second^2 over 10 seconds towards the z-axis in the Update loop. I can predict it will arrive at position z = 50. I can do the same thing by using the Rigidbody.AddForce method, if I apply the same acceleration at every FixedUpdate step.

// Move Transform via simple Euler integration
private void Update()
{
    velocity += acceleration * Time.deltaTime;
    transform.position += velocity * Time.deltaTime;
}

// Move Rigidbody the same distance
private void FixedUpdate()
{
   // Will be multiplied by fixedDeltaTime for me.
   rigidbody.AddForce(acceleration, ForceMode.Acceleration);
}

This works fine so far. However, I would actually like to be able to change the update step of the steering. For now, it would be perfect, if I could calculate and apply my acceleration variable in Update(). I can simply apply it to my custom models because they respect a variable timestep. But Unity’s Rigidbody force must be applied in FixedUpdate(), so I need to accumulate the steering acceleration and only apply it every physics step. How do I do this correctly? At the moment, my final traveled distance is too short, also I can’t be sure if, when and how many times Update vs FixedUpdate is called.

// Rigidbody physics model class
Vector3 acceleration;
float accumulatedTime;

public void Apply(Vector3 steeringForce) // Called from regular Update
{
    // While waiting for next physics step, accumulate per-frame force.
    acceleration += steeringForce;
    accumulatedTime += Time.deltaTime;
}

private void FixedUpdate()
{
   // This also jitters, so I was reverting back to accumulating force without the timestep
   // and applying it simply as ForceMode.Force
   rigidbody.AddForce(steeringForce * accumulatedTime, ForceMode.Impulse);
   acceleration = Vector.Zero;
   // We have applied the accumulated force and reset it for next round.
}

Maybe this approach is already wrong, but in theory it should make sense, if Update is called multiple times in between FixedUpdate. Because my steeringForce is calculated per-frame, I need to add it up until I can apply it. In practice however, it seems that I keep missing frames or something, because the rigidbody moves slower and travels only to around 46 units (it should land right on 50 as it does when applying the force the normal way in FixedUpdate).

Where’s my mistake or how can I solve this?

PS: Once the steering in Update works, I would like to upgrade to a system, where the steering is only calculated every 100ms or so. In this case much less frequent than the regular FixedUpdate loop. Is it possible to accomodate for both cases, a slower and a faster updated acceleration variable for the Rigidbody?

After spending way too long on this issue I found a solution for making the physics correct when input is applied via Update:

Vector3 acceleration;

public void Apply(Vector3 force) // called from Update
{
    acceleration += force * Time.deltaTime;
}

void FixedUpdate()
{
    rigidbody.AddForce(acceleration, ForceMode.Impulse);
    acceleration = Vector3.zero;
}

It makes sense, since my steering should be per-frame, so I multiply by deltaTime when accumulating. When adding the force to the body, the force is already multiplied by the time, so I can use ForceMode.Impulse or VelocityChange.

I don’t quite understand why my original example behaves differently, however. There I sum the acceleration and the deltaTimes separately, multiplying them later when adding force to the rigidbody. I thought this should give the same result as my now working solution, but apparently it’s different.