There is a problem I am struggling with, and I need some help. I will try to explain it thoroughly.
I am working on a simulation of a tank. The tank is composed this way: I have the chassis. On the chassis is the turret, which can rotate only in azimuth. On the turret are several other things, like the barrel (which can rotate in elevation), the gunner sight system (GSS) azimuth part, and the commander sight system (CSS) azimuth part. On the GSS azimuth part is the GSS elevation part, and on the CSS azimuth part is the CSS elevation part. Of course, the azimuth parts of the GSS and CSS can only rotate in azimuth, and the same is true for the elevation parts which can only rotate in elevation. Of course, as the GSS is on the Turret, if the Turret rotates, it makes the GSS rotate too.
So, let's recap a bit:
Chassis <- Turret (AZ) <- Barrel (EL).
Chassis <- Turret (AZ) <- GSS (AZ) <- GSS (EL).
Chassis <- Turret (AZ) <- CSS (AZ) <- CSS (EL).
Each part can be considered as a DOF (domain of freedom) locked on one axis only (azimuth or elevation).
Now, each part has some movement limits:
The turret can rotate in the range [-360°, +360°] (so no limits on this one).
The barrel can rotate in the range [-10°, +50°] relative to its parent the turret.
The GSS AZ can rotate in the range [-5°, +5°].
The GSS EL can rotate in the range [-10°, +50°].
The CSS AZ can rotate in the range [-360°, +360°].
The CSS EL can rotate in the range [-10°, +50°].
Each part also has some physical limitations:
GSS AZ, GSS EL, CSS AZ, and CSS EL have a maximum acceleration of 570°/s², a maximum deceleration of 570°/s² too, and a maximum velocity of 57°/s.
Turret has a maximum acceleration of 32°/s², a maximum deceleration of 160°/s², and a maximum velocity of 40°/s.
Barrel has a maximum acceleration of 57°/s², a maximum deceleration of 114°s², and a maximum velocity of 34°/s.
Now, the problem is the following. For the GSS, I have two fixed values which represent a world direction. One is for the azimuth, the other is for the elevation. Let's imagine it's 25° (AZ) and 3° (EL). That means the GSS part must be in that direction in the world referential. Those values can be updated in real time (for example, we could control those values with a joystick, to move the camera). What I want is the GSS to always be aligned with those values (I can tolerate a small error of 5*10^(-5) radians only), even when we are driving and the chassis is moving (both in position and orientation). Of course, because the GSS has some limits, it cannot always be aligned with the direction. To solve this, the Turret must also be aligned with those values (and so, when the Turret is rotating in order to be aligned in azimuth, it makes the GSS closer to the wanted direction).
At any moment, I have access to the position (azimuth or elevation) of an object relative to its parent (and thus I can have its direction in world referential) and to its rotational velocity relative to its parent.
The only parameter on which I can play to control each part is the velocity of a part relative to its parent.
What I did is convert all world directions in the referential of its parent. From here, I simply compute the desired velocity, while respecting the different constraints I have (in acceleration, deceleration, and velocity). Here is the code I use to compute the velocity:
double desiredVelocity = (wrappedDesiredPosition - wrappedCurrentPosition) / deltaTime;
if (std::abs(desiredVelocity) > object.maximumVelocity)
desiredVelocity *= object.maximumVelocity / std::abs(desiredVelocity);
const double maximumForce = (std::abs(desiredVelocity) < std::abs(object.velocity) || Sign(desiredVelocity) == -Sign(object.velocity)) ? object.maximumDeceleration : object.maximumAcceleration;
double requiredForce = (desiredVelocity - object.velocity) / deltaTime;
if (std::abs(requiredForce) > maximumForce)
{
requiredForce *= maximumForce / std::abs(requiredForce);
desiredVelocity = object.velocity + requiredForce * deltaTime;
if (std::abs(desiredVelocity) > object.maximumVelocity)
desiredVelocity *= object.maximumVelocity / std::abs(desiredVelocity);
}
Limits in position are already taken care of here (wrappedDesiredPosition has been clamped).
This does work, however, I am definitely not precise enough. The camera tends to sometimes oscillate a bit (not much though) before it stabilizes correctly. I took some measurements, and I am stabilized with a precision of about 3.5*10^(-3)
radians when the chassis is moving (at 16km/h with some bumps). This is definitely not good enough, as I want to achieve 5.0*10^(-5)
radians in precision.
What can I do to improve my stabilization? I need to improve it by a magnitude of ~70, which seems enormous. I am aware of PID controllers, which may help, but I am not sure how to apply it correctly here, and I am not sure it can help me achieve my target.
If anyone has some tips on how to improve that, I would be happy to hear about it.