# Relate Two Vectors to an Angle?

1. Dec 13, 2011

### VX967

Hey there, I'm new to these forums. I'm currently trying to steer an AI kart for a racing game I'm making in Blender. I'm not sure if anyone on these forums has experience with programming games or AI, but here it goes.

Basically, there is a steering actuator that returns a steering vector (x,y,z). This traces the path that the kart should go around the track, and updates in real-time.

I also have the kart's local orientation, also in the form of a vector (x,y,z).

What I'm trying to do is somehow relate those vectors into an equation of some sort and come out with an angle.

So if the steering vector points to the right [relative to the kart's local orientation vector], it will come out with a positive angle [relative to the kart's front] and will turn the wheels positively to turn right. If the steering vector points to the left of the kart's local orientation, it will return a negative angle and steer the kart to the left.

[Note that I'm only looking for a clear distinction of left or right by using positive or negative. The wheels will always turn by a set amount, so the extremities of the values are ignored.]

If anyone is familiar with Blender or Python, here's the code I was suggested:

Code (Text):
angle = obj.localOrientation[1].angle(steervector)
However, it always returns a positive value. I hope this question isn't too confusing. I can draw a diagram if necessary.

EDIT: I created a visual representation.

#### Attached Files:

• ###### Steering AI.png
File size:
14.9 KB
Views:
130
Last edited: Dec 13, 2011
2. Dec 14, 2011

### JHamm

Try creating a new variable which takes the local orientation angle and rotates it by a quarter turn clockwise (or anti-clockwise and reverse everything else I say), then if the angle between this new vector and the steer vector is acute you need to turn right and if it's obtuse you need to turn left.

3. Dec 14, 2011

### A.T.

Yes, the 3D angle between two 3D vectors is always positive. To make it a signed angle you have to define a plane of projection (here the horizontal plane). Lets say:

I assume the vertical axis (Z) of the vehicle is obj.localOrientation[2] ?

Code (Text):

angle = obj.localOrientation[1].angle(steervector)
if obj.localOrientation[1].crossProduct(steervector).dotProduct(obj.localOrientation[2]) < 0:
angle *= -1.0

Note: I don't know the exact vector method names blender uses for cross and dot product. But it should be similar.

Last edited: Dec 14, 2011
4. Dec 14, 2011

### dispersion123

I'm going to assume that z=0 for both vectors, otherwise you do not have enough information to determine the angle correctly within the kart's frame of reference (i.e. this solution assumes that 'up' for the kart is always (0,0,1)). Assuming that, you are only dealing with (x,y) vectors and the solution is two fold:

Find the angle using dot product rules, $\theta=arccos\left(\frac{A\cdot B}{\left\|A\right\|\;\left\|B\right\|}\right)$, which gives you angle but not direction.

What I do next is easy but hard to conceptualize. You 'rotate' the steering vector (x,y) into the kart's reference frame. This makes it appear that the kart's (x,y) = (1,0) then you just check the sign of the steering vector's y to determine direction.

$(x_k,y_k)$ - kart
$(x_s,y_s)$ - steering

$n_{xk}=x_k/\sqrt{x^2_k+y^2_k}$

$n_{yk}=y_k/\sqrt{x^2_k+y^2_k}$

$y_{s,kart}=-n_{yk}\; x_s+n_{xk}\;y_s$

If $y_{s,kart}<0$ turn right, if positive turn left. If you want to switch the signs, multiply by a negative.

Edit:
I like A.T.'s cross-product solution, it seems the PHP (which I don't know) is easy to implement. But it makes the same assumption that 'z' is always up.

Last edited: Dec 14, 2011
5. Dec 14, 2011

### A.T.

I used the local z-axis of the object. It could point anywhere in the global space, even downwards during a loop. He just has to make sure that the local system of his car object is:
x : towards the right door of the car
y : towards the front of the car
z : towards the roof of the car

6. Dec 14, 2011

### meldraft

I believe that the simplest solution would be to use the cross product formula directly. Unlike dot product, the angle in cross products is signed (you can tell from the fact that AxB = - BxA). This is because there is a sine instead of cosine.

Therefore, if you always place one of your vectors first in the cross product formula and solve for theta, "+" will always mean counterclockwise (so the other vector is on the first vector's "left"), and minus is always clockwise (so the other vector is on the first vector's "right").

7. Dec 14, 2011

### A.T.

How do you "solve the cross product formula for theta" to get a signed theta? Are you suggesting that you can get a signed angle from the two vectors alone, without a third vector?

8. Dec 14, 2011

### VX967

Thanks for the responses, guys. Unfortunately, I'm currently in high school physics, so a lot of the stuff you've said is way over my head. I apologize for that.

However, dispersion123, your second method seems plausible, and I was able to convert that formula into Python:

Code (Text):
import GameLogic as GL
import math

cont = GL.getCurrentController()
kart = cont.owner
turn = 0.06

steervec = cont.actuators['Steering'].steeringVec
kartvec = kart.localOrientation[1]

kx = kartvec.x
ky = kartvec.y
sx = steervec.x
sy = steervec.y

nkx = kx / math.sqrt(kx**2 + ky**2)
nky = ky / math.sqrt(kx**2 + ky**2)

dkart = -(nky)(sx) + (nkx)(sy)

if dkart < 0:
turn = turn

elif dkart > 0:
turn = -turn

else:
turn = 0.0
By the way, z is indeed the upward axis, so it can be ignored. The kart will already ride along the ground.

I haven't tried to implement this code just yet, but I will when I have time. Thanks for all the responses, guys! Hope this works.

Last edited: Dec 14, 2011
9. Dec 14, 2011

### BobG

If the coordinate system is car centered and the z component is always 0 (or whatever coordinate system used never has a z component for position or velocity), then meldraft is correct. There's only component to the cross product and that lies on the z, either positive or negative. (In other words, it's essentially the same solution you guys already stated).

Using positive x being in the direction of the door is fine, but that's a little non-standard. If the positive x is towards the front of the car, positive z is towards the bottom of the car, and y is perpendicular to both (using the right hand rule), you essentially have roll, pitch, and yaw.

Not a huge difference, but using a standard system makes it easier to find other people that have had to solve the same problem. Additionally, the solution you find will also be more likely to be useful on future problems.

10. Dec 14, 2011

### VX967

Alright, the good news is that it works! There's a clear distinction between the positive and negative values when running the script.

The only problem is that the steering actuator's velocity and steering settings seem to override the car's steering and gas, which is a problem that just relates to Blender. Otherwise, it works perfectly. I've been trying to figure this out for months, so thanks for all of your help, guys!

11. Dec 15, 2011

### meldraft

Indeed the solution is essentially the same, I merely pointed out that it should be simpler to just solve the formula for theta :)

Arcsin spans from -pi/2 to pi/2 (in contrast to acos which is always positive (0 to pi)) so that is how you get the signed angle (http://en.wikipedia.org/wiki/Inverse_trigonometric_functions)

12. Dec 16, 2011

### dispersion123

Glad it worked VX967! I just realized you may be able to just use $n_{xk}=x_k$ and $n_{yk}=y_k$. I believe that would be equivalent to the just using the 'z-term' of the cross-product. If you find yourself needing a bit more speed out of the code, you may try that.

That is the problem though, I don't believe he is keeping track of a local kart coordinate system. His orientation vector is measured in the global coordinate system, even if you assume his orientation vector is equal to (0,1,0)local, that doesn't give you the full orientation of the kart in 3D space, unless you assume that (0,0,1)local is always equal to (0,0,1)global. Even if he did have a full description, he would need to transform the vector obtained from the cross-product, which would be represented in the global frame, into the frame of the kart.