This is a continuation of a previous post, to demonstrate how to solve the inverse problem of determining user input from trajectories.
Say we know that, at a particular instant in time, a user was controlling a vehicle in the air (without being hit by another car, or air dodging). Is it possible to use information about the car's dynamic state to determine what inputs the users issued?
Let's take a look: from the previous post, we have the following update procedure for the angular velocity:
If we knew what the beginning and end step values of
furthermore, by using our expression for
where
Thankfully, they are decoupled, so they can be solved individually:
Roll:
Pitch:
Yaw:
Where
If the norm of angular velocity exceeds 5.5, Rocket League scales it back down, until it is 5.5. How does this affect our ability to guess the inputs of a trajectory?
In short, this means there will be more than one net torque
These examples show how well the recovered user input (dashed lines) compares to the exact values (solid lines). The trace in red is the norm of the angular velocity-- note that when it hits 5.5, the inputs do not coincide. However, it is the case that the exact inputs and the recovered would still have the same effect on the car.
An example where angular velocities do not clip shows almost exact agreement:
xxxxxxxxxx
const float T_r = -36.07956616966136; // torque coefficient for roll
const float T_p = -12.14599781908070; // torque coefficient for pitch
const float T_y = 8.91962804287785; // torque coefficient for yaw
const float D_r = -4.47166302201591; // drag coefficient for roll
const float D_p = -2.798194258050845; // drag coefficient for pitch
const float D_y = -1.886491900437232; // drag coefficient for yaw
float sgn(float x) {
return return (0.0f < x) - (x < 0.0f);
}
vec3 aerial_inputs(
vec3 omega_start,
vec3 omega_end,
mat3x3 theta_start,
float dt) {
// net torque in world coordinates
vec3 tau = (omega_end - omega_start) / dt;
// net torque in local coordinates
tau = dot(transpose(theta_start), tau);
// beginning-step angular velocity, in local coordinates
vec3 omega_local = dot(transpose(theta_start), omega_start);
vec3 rhs{
tau[0] - D_r * omega_local[0],
tau[1] - D_p * omega_local[1],
tau[2] - D_y * omega_local[2]
};
// user inputs: roll, pitch, yaw
vec3 u{
rhs[0] / T_r,
rhs[1] / (T_p + sgn(rhs[1]) * omega_local[1] * D_p),
rhs[2] / (T_y - sgn(rhs[2]) * omega_local[2] * D_y)
};
// ensure that values are between -1 and +1
u[0] *= fmin(1.0, 1.0 / fabs(u[0]));
u[1] *= fmin(1.0, 1.0 / fabs(u[1]));
u[2] *= fmin(1.0, 1.0 / fabs(u[2]));
return u;
}