03-26-08 - 1

Well I promised that I would eventually take my controller stuff out of testdd and put in a .h so it's actually useful to people. Yeah, I'm probably not gonna do that. What I did do is fix my quartic curve solver to actually be correct, and added a "hybrid" cubic version. (hmm, I'm a retard, I just added a ComplexDouble class to cblib and then noticed that std::complex is totally fine and I should've just used that. doh)

Hybrid cubic works like this : if the target is stationary, the max time to converge is set by a user parameter. A shorter time can be used at any time as long as max accel (user parameter) is not exceeded. The result is that you get the desired behavior of the original cubic controller of reaching the target exactly within a certain time interval, and it avoids the weird quirk of sometimes taking extra long curves because it was always taking the same amount of time - now it can take a shorter time in a reasonable non-hacky way. Note that this is not some tweaked out fudgy solution. There are two user parameters : max time to converge & max acceleration on the path, and the cubic path that fits those constraints is found exactly each frame.

I wrote something about this on game-tech but I never posted it here I don't think. To me, PD controllers and this cubic controller thingy seem like very opposite ends of a theoretical spectrum of controllers. On the one end, the cubic curve is exactly symmetric. That is, the path from P0->P1 and the path from P1->P0 are identical under time reversal. The cubic goes from point A to point B in controllable finite time, and basically never overshoots. The PD is sort of the opposite in every way - it's very asymmetric, it attacks hard to cover distance fast initially, then slows down and comes in to settle very slowly (eventually infinitely slowly for a pure PD). A standard critically damped PD will definitely overshoot as part of the price to attacking quick and then stopping gently. In hand-wavey terms the PD feels very "springy" while the cubic feels very "robotic".

Now in theory it would be awesome to have this as a parameter. So if parameter is 0, you get a cubic, if parameter is 1, you get a PD, and in between you can play with how robotic or how springy your controller is. And of course that's easy. You can just blend the controllers. It's important to note why you can blend the controllers - they are stateless and linear. You could just get the acceleration from each and blend that, but that's not exact since with both the PD and the cubic I've solved them to take exact time steps, going to a discrete integrator with a constant acceleration would be lame. But of course Newton's equations are linear too, so I don't need to blend the accelerations, I can just run both controllers independently and blend the resulting position & velocities. This is now in testdd as "mode 10" ("blend").

A quick note on PD's. You generally want a critically damped PD. PD's will never exactly converge, so you need to fudge it. The best fudge I found was a "min velocity" parameter. This make the controller try to at least move you at a speed of "min velocity" towards the target, which cuts off the long exponentail tail of PD convergence and make the end part linear. Now, with this you might go ahead and try using an overdamped PD to reduce overshooting. That does work but it's a little weird looking. I can't imagine why anyone would ever want an underdamped PD, they're just gross. I couldn't find a clean stateless way to give a PD controller a max acceleration. If you do it naively, you prevent it from stopping fast enough and get horrible oscillation. If you try to prevent that naively by allowing decceleration, you get weird looking curves when your points move around in 3D space because you've created a splitting plane where your controller changes discontinuously.

No comments:

old rants