🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

SUVAT problem

Started by
9 comments, last by taby 5 years, 2 months ago

I'm trying to solve for the SUVAT equations. What is known is the start position and end position. The initial velocity is what I'm trying to solve for. Can anyone please help me with this problem? I don't know why I'm having so much trouble with such a simple thing.

Advertisement

Is this homework?

Hello to all my stalkers.

No. I'm doing an open-source tennis trajectory finder, and I have it working with RK4 integration, but there are some cases where a lob is required, and the easiest way to do that is by using a parabola. I realize that the SUVAT equations don't include wind, drag, or the Magnus effect, but I'm still interested in knowing how to get the initial velocity.

Fair enough :)

 

In your scenario (assuming constant acceleration = gravity), you will have to constrain it more somehow. There's an infinite amount of solutions, depending on the angle of the velocity.

Just imagine holding a ball, and wanting it to land 1m beneath its starting point. You can either drop it (0 initial velocity), or throw it directly up or down at any velocity (less than escape velocity), and it will eventually hit its target, although at different times.

 

I would suggest trying to constrain it either by angle, or by max height of the parabola. Once you have y displacement, you can calculate time needed for gravity to pull the ball to target level, to get your required time.

Using time, you can then solve for initial velocity.

Hello to all my stalkers.

I would like to constrain the initial direction, with only the speed to be variable. I was wondering if you had any code? I learn from code way faster than from English.

In any case, thank you for your posts. :)

OK so I got a bit further.

I have the equation final_velocity = sqrt(initial_velocity^2 + 2*acceleration*displacement), which I solve for each of the three dimensions.

However, I have the equation t = 2*displacement / (initial_velocity + final_velocity). How do I solve for that when t is a scalar and displacement, initial_velocity, and final_velocity are vectors? Like I said, I'm stuck on something simple here, but I just can't figure it out.

Now that I think of it, t = (v - u) / (2*a) is only valid for the y dimension, because the acceleration along the x and z dimensions is zero. Am I progressing?

I figured it out! It's unsatisfactory however, since it doesn't support wind, drag, or the Magnus effect -- for instance, the red path travels further into the opponent's side of the court because it is not affected by drag.


custom_math::vector_3 V(1, 1, 0);
V.normalize();
V *= out_server_vel.length();

custom_math::vector_3 V_norm = V;
V_norm.normalize();
custom_math::vector_3 basis(1, 0, 0);
float v0 = V.length();
float launch_angle = acos(V_norm.dot(basis));
float a = g / 2;
float b = v0 * sin(launch_angle);
float c = in_server_pos.y;
float t2 = (-b + sqrt(b*b - 4.0 * a*c)) / (2.0 * a);
float t3 = (-b - sqrt(b*b - 4.0 * a*c)) / (2.0 * a);
cout << t2 << endl;
cout << t3 << endl;
float pi = 4.0 *atan(1.0);

for (double i = 0; i <= t3; i += 0.01)
{
	custom_math::vector_3 s = in_server_pos + V * i + 0.5*g*i*i;
	parabola.push_back(s);
}

for (size_t i = 0; i < parabola.size(); i++)
{
	parabola[i].rotate_z(pi / 2.0);
}
	
custom_math::vector_3 end_position = parabola[parabola.size() - 1];
custom_math::vector_3 v1 = in_out_target_pos - in_server_pos;
v1.y = 0;
custom_math::vector_3 v2 = end_position - in_server_pos;
v2.y = 0;
v1.normalize();
v2.normalize();
double angle = acos(v1.dot(v2));

for (size_t i = 0; i < parabola.size(); i++)
{
	parabola[i].rotate_y(angle);
}
	
custom_math::vector_3 d = parabola[0] - in_server_pos;

for (size_t i = 0; i < parabola.size(); i++)
	parabola[i] = parabola[i] - d;
	 
	

court.png

This might be beyond your powers at this point, but there is a general solution that would work with all the complexity of a more complete Physics simulation. Start with a quick-and-dirty approximate solution (what you did above is probably fine). If you can quickly compute the trajectory going forward with the more complete Physics model, you can define a differentiable measure of error (e.g., the square of the distance between the landing point and the target) and use backpropagation (a.k.a. "reverse-mode automatic differentiation") to compute the gradient of the error with respect to whatever parameters you are trying to solve for. You can then use gradient descent to refine your solution.

This may or may not be too much work for what you are trying to do, but I think it would work.

I do calculate a slope of sorts, and use it to hone the server velocity so that the ball lands at the target point, using RK4 and symplectic4, etc.

The code is small, and reasonably fast (like, 2400 frames per second in C++). It's also due for replacement because it doesn't really take the input server velocity length into account. In the next version, which will be closed-source at first, will be better. :)

In any case, the code (my dog's breakfast) is something else, but is it gradient descent?


for (size_t i = 0; i < num_length_adjustment_iterations; i++)
{
    // adjust velocity length to get closer to the target position
    custom_math::vector_3 begin_pos = p[0];
    custom_math::vector_3 end_pos = p[p.size() - 1];
    custom_math::vector_3 diff_a = end_pos - begin_pos;
    custom_math::vector_3 diff_b = target_position - begin_pos;
    double len_a = diff_a.length();
    double len_b = diff_b.length();
    double slope = len_a / len_b;
    server_velocity /= slope;
	
    // refresh path using new input server velocity
    get_path(p,
        server_position,
        server_velocity,
        server_angular_velocity,
        target_position,
        0);
}

// rotate vectors on y axis to get closer to the target position
custom_math::vector_3 end_position = p[p.size() - 1];
custom_math::vector_3 v1 = server_position - target_position;
custom_math::vector_3 v2 = server_position - end_position;
v1.normalize();
v2.normalize();

double angle = acos(v1.dot(v2));

server_velocity.rotate_y(-angle);

// refresh path
get_path(p,
	server_position,
	server_velocity,
	server_angular_velocity,
	target_position,
	0);

This topic is closed to new replies.

Advertisement