Matt Greenhalgh
Matt Greenhalgh

Reputation: 23

How to implement arriving behavior with time delta?

I'm trying to create an autonomous agent with arriving behaviour based on Reynolds classic Boids paper and more specifically Dan Shiffman's implementation on natureofcode.com. Both of these approaches are easy to understand (and work) but they both assume a fixed nominal update step rather than querying the elapsed time since the last frame update and applying this time delta during the Euler integration step. Ie they suggest simply:

//pseudocode
acceleration.add(force);
velocity.add(acceleration);
location.add(velocity);

however if I want to include a time delta then various physics papers suggest I should rewrite this as:

//pseudocode
delta = timeElpasedSinceLastFrameUpdate();
acceleration.add(force);
deltaAcceleration = acceleration.mult(delta);
velocity.add(deltaAcceleration );
deltaVelocity = velocity.mult(delta);
location.add(deltaVelocity);

This also works until I try to implement the steering behaviours and specifically the arriving behaviour. For reference to the methodology see example 6.2 in the link here:

Nature of Code Steering Behaviours

The problematic step (in pseudocode) is steeringForce = desired - velocity;

Without a time delta applied the contribution of '- velocity' to the steering force correctly counteracts the currently held velocity vector and brings the object to a decelerating stop at the arrival destination.

With a time delta applied however the steeringForce is effectively moderated by the fractional time delta when I multiply acceleration by delta and hence doesn't apply sufficient deceleration to the accumulated velocity to bring the object to a halt in time and I get oscillating behaviour.

I can 'fix' this by not multiplying accumulated forces (i.e. acceleration) by time delta but this doesn't seem correct.

So, my question:

How should a steeringForce for arrival behaviour be generated to account for variable delta time?

Any help gratefully appreciated!

Upvotes: 2

Views: 485

Answers (1)

pingul
pingul

Reputation: 3473

EDIT: I missed the main part of your question. There are many ways to get the result you want, but they do so by different means. The easiest I can come up with is probably to skip the steeringForce for now all together and instead just modify the velocity.

We want a vector such that

desired_velocity = velocity + correction

This is the same as you wrote previously (but for 'steeringForce'):

correction = desired_velocity - velocity

By doing velocity + correction you will immediately get to the desired velocity, which is usually not what you want as it leads to a very jerky motion. Instead, you could clamp the correction to some value which would lead to a smoother motion:

len = length(correction)
corr_length = len > max_correction ? max_correction : len
correction = correction/len*corr_length

And now you can do

velocity += correction

This should lead to a somewhat dynamic motion, without oscillation.


Explicit time step integration (e.g. an forward Euler in your case) is usually written as

new_acceleration = old_acceleration + (delta_t/mass)*force
                                              ^^ note

And similarly,

new_velocity = old_velocity + delta_t*acceleration
new_position = old_position + delta_t*velocity

So to answer your question, you need to multiply by the time step before accumulating:

acceleration.add(force.mult(delta_t/mass));
velocity.add(acceleration.mult(delta_t));
location.add(velocity.mult(delta_t));

Upvotes: 1

Related Questions