I'd like to find out how far the player is pushing an Xbox controller analogue
stick. I don't need to know the angle it is being pushed, just how far. I'd like it to return a value of 0 to 1. Here are some examples!
If the player was pushing the stick fully down it would return 1.
If the stick was in the center it would return 0.
If they were pushing the stick to its full extent but at a 45 degree angle it would still return 1.
If they were pushing the stick only halfway and at a 135 degree angle it would return 0.5
Code I have tried so far
new Vector2(Input.GetAxisRaw("Horizontal"),Input.GetAxisRaw("Vertical")).magnitude
and I tried this code, despite not really understanding it :-/
float xAxis = (Input.GetAxis ("Player" + padNumber + "Horizontal"));
float yAxis = (Input.GetAxis ("Player" + padNumber + "Vertical"));
thumbStickDistance = Mathf.Sqrt(Mathf.Abs((xAxis*xAxis)+(yAxis*yAxis)));
However - Both these return different values depending on the angle the stick is pushed.
You have the answer, but you might think you don't because you are expecting to see different values. The magnitude is what you want.
First of all, your formula for thumbStickDistance is exactly what the magnitude property for a Vector2 does. Second, the difference between GetAxis and GetAxisRaw is that GetAxis applies some smoothing. This is best seen if you use the arrow keys. GetAxis will rise and fall, whereas GetAxisRaw will jump to -1, 0 or 1 immediately. Which you use for the xbox controller doesn't matter much.
Now, both the horizontal and vertical axes are in the range -1;1. If the xbox controller joystick had a square movement area then you could have both axes at 1 and the maximum distance you could measure would be sqrt(2) or about 1.414. If the controller had a perfectly circular movement area then the maximum distance you could measure would be 1 no matter which direction you pushed it in. As it turns out, although the xbox controller is closer to circular than square, it is neither. The maximum distance i was able to measure was about 1.16 which means that i reached a point just outside the circle around the centre.
So my advice would be to use the magnitude and if you need it use Clamp01 to limit the value to not exceed 1. The alternative would be to calibrate the controller, which could be complicated and it would need to be done each time you switch controllers as there are bound to be differences even between two otherwise identical xbox controllers.
Related
GameObject:
I have a gameObject "Sphere" with the following properties:
Starting scale of 1.5 (x, y, z).
A script that makes sure that the scale is between 0 and 150.
What do I have:
Now, I have implemented a function that the user can scale the GameObject by using the HTC Vive Controllers (we are using Virtual Reality).
This function checks the distance between the controllers (often between -1 and 1 to decide if we want to upscale or downscale the object).
So when I have this value between -1 and 1, I am scaling the GameObject by the value multiple the sensitivity (this is editable in the Unity Editor).
What do I want:
This works pretty fine, although, I want to increase the sensitivity over time on a not hard-coded way. So when the GameObject is very small, the scaling will be very slow. When the GameObject is pretty big, the scaling will go quick.
What have I tried:
I have this value (between -1 and 1), then I will multiply this value with the sensitivity.
Then I will multiply by the current scale / the maximum scale.
However, this is causing an issue that the zooming in is going faster then zooming out.
The code that I am using looks like below:
float currentControllerDistance = Vector3.Distance(LeftHand.transform.position, RightHand.transform.position);
float currentZoomAmount = currentControllerDistance - ControllersStartPostionDifference; // Value is between -1 and 1.
currentZoomAmount = currentZoomAmount * ScalingSensitivity; // Multiplying by the value in the Unity Editor.
float currentPercentage = ObjectToScale.transform.localScale.x / ObjectMaximumScale.x; // Current scale percentage in comparison to the maximum scale.
currentZoomAmount = currentZoomAmount * currentPercentage; // Changing the ObjectToScale by adding the currentZoomAmount.
ObjectToScale.transform.localScale = new Vector3(ObjectCurrentScale.x + currentZoomAmount, ObjectCurrentScale.y + currentZoomAmount, ObjectCurrentScale.z + currentZoomAmount);
Does someone have any idea how to do this kind of scaling?
Thanks in forward.
If I understood the question correctly, you're looking for way to specify the rate of change of your scaling so that it changes faster when closer to the maximum scale, which sounds like a job for an easing function.
If your project already uses a tweening library like DOTween, this should be easily done with that library's capabilities. If not, you can try using the equation for the cubic bézier, which is one of the simpler curves:
Cubic Bézier
This is simply y = x^3, so you can try ObjectMaximumScale.x * currentPercentage * currentPercentage * currentPercentage to get a value that goes from 0 to ObjectMaximumScale.x when fed a value between 0 and 1 respectively.
I am currently working on a project in C# where i play around with planetary gravitation, which i know is a hardcore topic to graps to it's fullest but i like challenges. I've been reading up on Newtons laws and Keplers Laws, but one thing i cannot figure out is how to get the correct gravitational direction.
In my example i only have 2 bodies. A Satellite and a Planet. This is to make is simplify it, so i can grasp it - but my plan is to have multiple objects that dynamically effect each other, and hopefully end up with a somewhat realistic multi-body system.
When you have an orbit, then the satellite has a gravitational force, and that is ofcourse in the direction of the planet, but that direction isn't a constant. To explain my problem better i'll try using an example:
let's say we have a satellite moving at a speed of 50 m/s and accelerates towards the planet at a speed of 10 m/s/s, in a radius of 100 m. (all theoretical numbers) If we then say that the framerate is at 1, then after one second the object will be 50 units forward and 10 units down.
As the satellite moves multiple units in a frame and about 50% of the radius, the gravitational direcion have shifted alot, during this frame, but the applied force have only been "downwards". this creates a big margin of error, especially if the object is moving a big percentage of the radius.
In our example we'd probably needed our graviational direction to be based upon the average between our current position and the position at the end of this frame.
How would one go about calculating this?
I have a basis understanding of trigonometry, but mainly with focus on triangles. Assume i am stupid, because compared to any of you, i probably am.
(I made a previous question but ended up deleting it as it created some hostility and was basicly not that well phrased, and was ALL to general - it wasn't really a specific question. i hope this is better. if not, then please inform me, i am here to learn :) )
Just for reference, this is the function i have right now for movement:
foreach (ExtTerBody OtherObject in UniverseController.CurrentUniverse.ExterTerBodies.Where(x => x != this))
{
double massOther = OtherObject.Mass;
double R = Vector2Math.Distance(Position, OtherObject.Position);
double V = (massOther) / Math.Pow(R,2) * UniverseController.DeltaTime;
Vector2 NonNormTwo = (OtherObject.Position - Position).Normalized() * V;
Vector2 NonNormDir = Velocity + NonNormTwo;
Velocity = NonNormDir;
Position += Velocity * Time.DeltaTime;
}
If i have phrased myself badly, please ask me to rephrase parts - English isn't my native language, and specific subjects can be hard to phrase, when you don't know the correct technical terms. :)
I have a hunch that this is covered in keplers second law, but if it is, then i'm not sure how to use it, as i don't understand his laws to the fullest.
Thank you for your time - it means alot!
(also if anyone see multi mistakes in my function, then please point them out!)
I am currently working on a project in C# where i play around with planetary gravitation
This is a fun way to learn simulation techniques, programming and physics at the same time.
One thing I cannot figure out is how to get the correct gravitational direction.
I assume that you are not trying to simulate relativistic gravitation. The Earth isn't in orbit around the Sun, the Earth is in orbit around where the sun was eight minutes ago. Correcting for the fact that gravitation is not instantaneous can be difficult. (UPDATE: According to commentary this is incorrect. What do I know; I stopped taking physics after second year Newtonian dynamics and have only the vaguest understanding of tensor calculus.)
You'll do best at this early stage to assume that the gravitational force is instantaneous and that planets are points with all their mass at the center. The gravitational force vector is a straight line from one point to another.
Let's say we have a satellite moving at a speed of 50 m/s ... If we then say that the framerate is one frame per second then after one second the object will be 50 units right and 10 units down.
Let's make that more clear. Force is equal to mass times acceleration. You work out the force between the bodies. You know their masses, so you now know the acceleration of each body. Each body has a position and a velocity. The acceleration changes the velocity. The velocity changes the position. So if the particle starts off having a velocity of 50 m/s to the left and 0 m/s down, and then you apply a force that accelerates it by 10 m/s/s down, then we can work out the change to the velocity, and then the change to the position. As you note, at the end of that second the position and the velocity will have both changed by a huge amount compared to their existing magnitudes.
As the satellite moves multiple units in a frame and about 50% of the radius, the gravitational direcion have shifted alot, during this frame, but the applied force have only been "downwards". this creates a big margin of error, especially if the object is moving a big percentage of the radius.
Correct. The problem is that the frame rate is enormously too low to correctly model the interaction you're describing. You need to be running the simulation so that you're looking at tenths, hundredths or thousanths of seconds if the objects are changing direction that rapidly. The size of the time step is usually called the "delta t" of the simulation, and yours is way too large.
For planetary bodies, what you're doing now is like trying to model the earth by simulating its position every few months and assuming it moves in a straight line in the meanwhile. You need to actually simulate its position every few minutes, not every few months.
In our example we'd probably needed our graviational direction to be based upon the average between our current position and the position at the end of this frame.
You could do that but it would be easier to simply decrease the "delta t" for the computation. Then the difference between the directions at the beginning and the end of the frame is much smaller.
Once you've got that sorted out then there are more techniques you can use. For example, you could detect when the position changes too much between frames and go back and redo the computations with a smaller time step. If the positions change hardly at all then increase the time step.
Once you've got that sorted, there are lots of more advanced techniques you can use in physics simulations, but I would start by getting basic time stepping really solid first. The more advanced techniques are essentially variations on your idea of "do a smarter interpolation of the change over the time step" -- you are on the right track here, but you should walk before you run.
I'll start with a technique that is almost as simple as the Euler-Cromer integration you've been using but is markedly more accurate. This is the leapfrog technique. The idea is very simple: position and velocity are kept at half time steps from one another.
The initial state has position and velocity at time t0. To get that half step offset, you'll need a special case for the very first step, where velocity is advanced half a time step using the acceleration at the start of the interval and then position is advanced by a full step. After this first time special case, the code works just like your Euler-Cromer integrator.
In pseudo code, the algorithm looks like
void calculate_accel (orbiting_body_collection, central_body) {
foreach (orbiting_body : orbiting_body_collection) {
delta_pos = central_body.pos - orbiting_body.pos;
orbiting_body.acc =
(central_body.mu / pow(delta_pos.magnitude(),3)) * delta_pos;
}
}
void leapfrog_step (orbiting_body_collection, central_body, delta_t) {
static bool initialized = false;
calculate_accel (orbiting_body_collection, central_body);
if (! initialized) {
initialized = true;
foreach orbiting_body {
orbiting_body.vel += orbiting_body.acc*delta_t/2.0;
orbiting_body.pos += orbiting_body.vel*delta_t;
}
}
else {
foreach orbiting_body {
orbiting_body.vel += orbiting_body.acc*delta_t;
orbiting_body.pos += orbiting_body.vel*delta_t;
}
}
}
Note that I've added acceleration as a field of each orbiting body. This was a temporary step to keep the algorithm similar to yours. Note also that I moved the calculation of acceleration to it's own separate function. That is not a temporary step. It is the first essential step to advancing to even more advanced integration techniques.
The next essential step is to undo that temporary addition of the acceleration. The accelerations properly belong to the integrator, not the body. On the other hand, the calculation of accelerations belongs to the problem space, not the integrator. You might want to add relativistic corrections, or solar radiation pressure, or planet to planet gravitational interactions. The integrator should be unaware of what goes into those accelerations are calculated. The function calculate_accels is a black box called by the integrator.
Different integrators have very different concepts of when accelerations need to be calculated. Some store a history of recent accelerations, some need an additional workspace to compute an average acceleration of some sort. Some do the same with velocities (keep a history, have some velocity workspace). Some more advanced integration techniques use a number of techniques internally, switching from one to another to provide the best balance between accuracy and CPU usage. If you want to simulate the solar system, you need an extremely accurate integrator. (And you need to move far, far away from floats. Even doubles aren't good enough for a high precision solar system integration. With floats, there's not much point going past RK4, and maybe not even leapfrog.)
Properly separating what belongs to whom (the integrator versus the problem space) makes it possible to refine the problem domain (add relativity, etc.) and makes it possible to easily switch integration techniques so you can evaluate one technique versus another.
So i found a solution, it might not be the smartest, but it works, and it's pretty came to mind after reading both Eric's answer and also reading the comment made by marcus, you could say that it's a combination of the two:
This is the new code:
foreach (ExtTerBody OtherObject in UniverseController.CurrentUniverse.ExterTerBodies.Where(x => x != this))
{
double massOther = OtherObject.Mass;
double R = Vector2Math.Distance(Position, OtherObject.Position);
double V = (massOther) / Math.Pow(R,2) * Time.DeltaTime;
float VRmod = (float)Math.Round(V/(R*0.001), 0, MidpointRounding.AwayFromZero);
if(V > R*0.01f)
{
for (int x = 0; x < VRmod; x++)
{
EulerMovement(OtherObject, Time.DeltaTime / VRmod);
}
}
else
EulerMovement(OtherObject, Time.DeltaTime);
}
public void EulerMovement(ExtTerBody OtherObject, float deltaTime)
{
double massOther = OtherObject.Mass;
double R = Vector2Math.Distance(Position, OtherObject.Position);
double V = (massOther) / Math.Pow(R, 2) * deltaTime;
Vector2 NonNormTwo = (OtherObject.Position - Position).Normalized() * V;
Vector2 NonNormDir = Velocity + NonNormTwo;
Velocity = NonNormDir;
//Debug.WriteLine("Velocity=" + Velocity);
Position += Velocity * deltaTime;
}
To explain it:
I came to the conclusion that if the problem was that the satellite had too much velocity in one frame, then why not seperate it into multiple frames? So this is what "it" does now.
When the velocity of the satellite is more than 1% of the current radius, it seperates the calculation into multiple bites, making it more precise.. This will ofcourse lower the framerate when working with high velocities, but it's okay with a project like this.
Different solutions are still very welcome. I might tweak the trigger-amounts, but the most important thing is that it works, then i can worry about making it more smooth!
Thank's everybody that took a look, and everyone who helped be find the conclusion myself! :) It's awesome that people can help like this!
I'm developing a 3D spaceshooter in XNA as a school project (basically Asteroids in 3D with power-ups), and have been working to implement roll, pitch, and yaw with respect to the ship's local axes. (I should emphasize: the rotation is not with respect to the absolute/world x, y, and z axes.) Sadly, I've been struggling with this for the last few weeks. Google and my neolithic monkey brain have failed me; maybe you folks can help!
Here's my setup:
Via keyboard input, I have the following variables ready to go:
yawRadians, which stores the desired yaw away from the ship's initial
position
pitchRadians, which stores the desired pitch away from the
ship's initial position
rollRadians, which stores the desired roll
away from the ship's initial position
The ship also maintains its own Front, Back, Right, Left, Top and Bottom unit vectors, which are used both for the rotations and also for propulsion. (Different keys will propel the ship toward the Front, Back, etc. This part is working great.)
Ultimately, I generate the rotation matrix mShipRotation, representing all of the ship's rotations, which is passed to the ship's draw method.
The problem I have is with the rotations themselves. Different solutions I've tried have had differing results. Here's what I've gone with so far:
Method 1 – Yaw, Pitch, and Roll relative to the absolute/world x, y, and z axes
At first, I naively tried using the following in my ship's Update method:
qYawPitchRoll = Quaternion.CreateFromYawPitchRoll(yawRadians, pitchRadians, rollRadians);
vFront = Vector3.Transform(vOriginalFront, qYawPitchRoll);
vBack = -1 * vFront;
vRight = Vector3.Transform(vOriginalRight, qYawPitchRoll);
vLeft = -1 * vRight;
vTop = Vector3.Transform(vOriginalTop, qYawPitchRoll);
vBottom = -1 * vTop;
mShipRotation = Matrix.CreateFromQuaternion(qYawPitchRoll);
(vOriginalFront, vOriginalRight, and vOriginalTop just store the ship's initial orientation.)
The above actually works without any errors, except that the rotations are always with respect to the x, y, and z axes, and not with respect to the ship's Front/Back/Right/Left/Top/Bottom vectors. This results in the ship not always yawing and pitching as expected. (Specifically, yawing degenerates to rolling if you have pitched up so the ship is pointing to the top. This makes sense, as yawing in this solution is just rotating about the world up axis.)
I heard about the Quarternion.CreateFromAxisAngle method, which sounded perfect. I could just combine three Quaternion rotations, one around each of the ship's local axis. What could go wrong?
Method 2 – Quaternion.CreateFromAxisAngle
Here's the second code snippet I used in my ship's Update method:
qPitch = Quaternion.CreateFromAxisAngle(vRight, pitchRadians);
qYaw = Quaternion.CreateFromAxisAngle(vTop, yawRadians);
qRoll = Quaternion.CreateFromAxisAngle(vFront, rollRadians);
qPitchYawAndRoll = Quaternion.Concatenate(Quaternion.Concatenate(qPitch, qYaw), qRoll);
vFront = Vector3.Normalize(Vector3.Transform(vOriginalFront, qPitchYawAndRoll));
vBack = -1 * vFront;
vRight = Vector3.Normalize(Vector3.Transform(vOriginalRight, qPitchYawAndRoll));
vLeft = -1 * vRight;
vTop = Vector3.Normalize(Vector3.Transform(vOriginalTop, qPitchYawAndRoll));
vBottom = -1 * vTop;
mShipRotation = Matrix.CreateFromQuaternion(qPitchYawAndRoll);
The above works perfectly if I only do one rotation at a time (yaw, pitch, or roll), but if I combine more than one rotation simultaneously, the ship begins to wildly spin and point in many different directions, getting more and more warped until it disappears entirely.
I've tried variants of the above where I first apply the Pitch to all the vectors, then the Yaw, then the Roll, but no luck.
I also tried it using Matrices directly, despite concerns of Gimbal Lock:
Method 3: Matrices
mShipRotation = Matrix.Identity;
mShipRotation *= Matrix.CreateFromAxisAngle(vRight, pitchRadians);
mShipRotation *= Matrix.CreateFromAxisAngle(vFront, rollRadians);
mShipRotation *= Matrix.CreateFromAxisAngle(vTop, yawRadians);
vFront = Vector3.Normalize(Vector3.Transform(vOriginalFront, mShipRotation));
vBack = -1 * vFront;
vRight = Vector3.Normalize(Vector3.Transform(vOriginalRight, mShipRotation));
vLeft = -1 * vRight;
vTop = Vector3.Normalize(Vector3.Transform(vOriginalTop, mShipRotation));
vBottom = -1 * vTop;
No luck; I got the same behavior. One rotation at a time is okay, but rotating about multiple axes resulted in the same bizarre spinning behavior.
After some brilliant debugging (read as: blindly outputting variables to the console), I noticed that the Front/Right/Top vectors were slowly, over time, becoming less orthogonal to one another. I added Normalization to vectors basically every step of the way, and also tried computing new vectors based on cross products, to try to ensure that they always remained perpendicular to one another, but even then they were not perfectly orthogonal. I'm guessing this is due to floating point math not being perfectly precise.
Note that I regenerate the mShipRotation matrix every Update method, so it cannot be accumulating drift or inaccuracies directly. I think that applying multiple Quarternion rotations may be accumulating error (as I can do one rotation just fine), but my attempts to fix it have not worked.
In short:
I can pitch/roll/yaw relative to the world axes x, y, and z just
fine. It's just not what the player would expect to happen as the
rolling/pitching/yawing is not relative to the ship, but to the
world.
I can roll, pitch, or yaw around the ship's local axes (Front/Back/Top/Bottom/Left/Right) just fine, but only one at a time. Any combination of them will cause the ship to spiral and deform rapidly.
I've tried Quaternions and Matrices. I've tried suggestions I've found in various forums, but ultimately do not wind up with a working solution. Often people recommend using Quaternion.CreateFromYawPitchRoll, not really realizing that the intent is to have a ship rotate about its own (constantly changing) axes, and not the (fixed) world axes.
Any ideas? Given a situation where you are given the roll, pitch, and yaw about a ship's front, right, and top vectors, how would you go about creating the rotation matrix?
You seem to be applying your overall angles (yawRadians, pitchRadians, rollRadians) to your local axis in your methods 2 & 3. These values are married to the world axis and have no meaning in local space. The root of your problem is wanting to hang onto the 3 angles.
In local space, use an angular amount that is the amount you want to rotate between frames. If you only pitched up 0.002f radians since the last frame, that would be what you would use when you rotate around the vRight axis.
This will screw with your overall angle values (yawRadians, pitchRadians, & rollRadians) and render them useless but most folks who stick with 3d programming quickly drop the angle approach to storing the orientation anyway.
Simply rotate your matrix or quaternion little by little each frame around your local axis and store the orientation in that structure (the quat or matrix) instead of the 3 angles.
There is no worries about gimbal lock when you are rotating a matrix about local axis like this. You would have to have 90 degree rotations between frames to bring that into the picture.
If you want to avoid error accumulation use a quat to store the orientation and normalize it each frame. Then the matrix you send to the effect will be made each frame from the quat and will be ortho-normal. Even if you didn't use a quat and stored your orientation in a matrix it would take hours or days to accumulate enough error to be visually noticeable.
This blog might help: http://stevehazen.wordpress.com/2010/02/15/matrix-basics-how-to-step-away-from-storing-an-orientation-as-3-angles/
I think this might be what you're looking for:
http://forums.create.msdn.com/forums/t/33807.aspx
I'm pretty sure that CreateFromAxisAngle is the way to go.
I'm working with Unity 3 and my total level size will be just a quadrilateral area with a wall on each side. Within this will be two additional walls that create an enclosure that restricts the player to a portion of the level that gradually expands.
I call these two walls ZBoundary and XBoundary, and so far for a prototype have mapped their movement to some keyboard keys. What I want to do is when one moves, the other grows in length so they are always joined at a perpendicular angle, so I want to be able to linearly interpolate between, for example, the ZBoundary's Z-coordinate and the Z-coordinate of the Xboundary so that they always meet and create a join. This creates a problem as well, because I don't know how to change the size of a GameComponent programmatically, and keep getting errors.
I know Vector3.lerp may help but I'm drowning in transforms and different scales and so would appreciate the help.
I'm halfway there by now getting the XBoundary to adjust its position in order to always lock to the ZBoundary at 90degrees
ZBoundaryRef.transform.Translate((-1 * distancePerZMovement), 0, 0, Space.World);
// using Space.World so transforms are using the global coordinate system!
// what I've done here is say, move the XBoundary Z-CoOrd so that it aligns with the ZBoundary Z-CoOrd.
// the origin of an object is at it's centre point so we need to take this in to account to ensure they join at the corners, not in a Tshape!
float difference = (ZBoundaryRef.transform.position.x - XBoundaryRef.transform.position.x);
float adjustment = difference + (ZBoundaryRef.transform.localScale.x/2);
XBoundaryRef.transform.Translate(adjustment,0,0,Space.World);
With reference to this programming game I am currently building.
I wrote the below method to move (translate) a canvas to a specific distance and according to its current angle:
private void MoveBot(double pix, MoveDirection dir)
{
if (dir == MoveDirection.Forward)
{
Animator_Body_X.To = Math.Sin(HeadingRadians) * pix;
Animator_Body_Y.To = ((Math.Cos(HeadingRadians) * pix) * -1);
}
else
{
Animator_Body_X.To = ((Math.Sin(HeadingRadians) * pix) * -1);
Animator_Body_Y.To = Math.Cos(HeadingRadians) * pix;
}
Animator_Body_X.To += Translate_Body.X;
Animator_Body_Y.To += Translate_Body.Y;
Animator_Body_X.From = Translate_Body.X;
Translate_Body.BeginAnimation(TranslateTransform.XProperty, Animator_Body_X);
Animator_Body_Y.From = Translate_Body.Y;
Translate_Body.BeginAnimation(TranslateTransform.YProperty, Animator_Body_Y);
TriggerCallback();
}
One of the parameters it accepts is a number of pixels that should be covered when translating.
As regards the above code, Animator_Body_X and Animator_Body_Y are of type DoubleAnimation, which are then applied to the robot's TranslateTransform object: Translate_Body
The problem that I am facing is that the Robot (which is a canvas) is moving at a different speed according to the inputted distance. Thus, the longer the distance, the faster the robot moves! So to put you into perspective, if the inputted distance is 20, the robot moves fairly slow, but if the inputted distance is 800, it literally shoots off the screen.
I need to make this speed constant, irrelevant of the inputted distance.
I think I need to tweak some of the Animator_Body_X and Animator_Body_Y properties in according to the inputted distance, but I don't know what to tweak exactly (I think some Math has to be done as well).
Here is a list of the DoubleAnimation properties that maybe you will want to take a look at to figure this out.
Is there are reason you're using DoubleAnimation? DoubleAnimation is designed to take a value from A to B over a specific time period using linear interpolation acceleration/deceleration at the start/end of that period if required (which is why it's "faster" for longer distance.. it has further to go in the same time!). By the looks of things what you are trying to do is move something a fixed distance each "frame" depending on what direction it is facing? That doesn't seem to fit to me.
You could calculate the length of the animation, depending on the distance, so the length is longer for longer distances, then the item is always moving at the same "speed". To me, it makes more sense to just move the item yourself though. You can calculate a objects velocity based on your angle criteria, then each "frame" you can manually move the item as far as it needs to go based on that velocity. With this method you could also easily apply friction etc. to the velocity if required.
The math you have to do is: velocity*time=distance
So, to keep the speed constant you have to change the animation's duration:
double pixelsPerSecond = 5;
animation.Duration = TimeSpan.FromSeconds(distance/pixelsPerSecond);
BTW, I don't think animations are the best solution for moving your robots.