Most of what you guys said lost me :) But, if I'm to take away one thing from this, is it correct to say that the reason it overshoots is because at any given time (including when you are arbitrarily close to the target) it is calculating the acceleration needed to reach that target in a certain amount of time, and as such even once you do reach the target your acceleration will be non-zero and thus you will continue moving?
I guess my next question is more about the design of such a controller framework. In general an entity has components such as position, velocity, acceleration, heading, and angular rotation. Maybe others but let's just use these as a starting point. In the example you gave above, the output of the controller is an acceleration to apply. Velocity and position are then integrated from acceleration. Other controllers might wish to output velocity directly, and only have position be integrated.
How should one deal with the fact that controllers can output values at various stages of the integration, and that they can be combined on top of that? If I combine 2 controllers that both output acceleration, it's easy to just add the accelerations, set the acceleration of the entity equal to the result, and then integrate velocity and position.
But if I have one controller outputting an acceleration, and one controller outputting a velocity, what does that even mean to combine them? Assuming that this even makes physical sense, let's assume I have two output structs:
struct acceleration_output { Vector3 new_accel; float new_alpha; };struct velocity_output { Vector3 new_velocity; float new_omega; };
I then combine two controllers, one which returns a velocity_output and one which returns an acceleration_output.
acceleration_output output1 = controller1.execute();velocity_output output2 = controller2.execute();//Suppose I have class member variables pos_, velocity_, rotation_, omega_. //What code follows to correctly update them in 1 iteration of an update loop?