Ok, now that I know what my problem is, I just need to find a solution to it. Accordingly, I need to know how to convert quaterion orientation into ( preferably canonical ) Euler angles. And yes, I've looked at Mark's geometry code - because I know he can do the conversion very well - but I don't see it in there. I do see a conversion to 3x3 matrix, but I know even less about matrices than I know about quaternions.
Convert Quat to Euler Angles?
Miscellaneous Forums/General Discussion/Convert Quat to Euler Angles? Maybe you could use Leadwerks function ? It is in this topic: http://www.blitzbasic.com/Community/posts.php?topic=51579
http://www.mathworks.com/access/helpdesk/help/toolbox/aeroblks/index.html?/access/helpdesk/help/toolbox/aeroblks/quaternionstoeulerangles.html&http://www.google.com/search?client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&channel=s&hl=en&q=convert+quaternion+to+euler&btnG=Google+Search
Looks like Halo's code there can help a bit for B3D. From that thread though ... I want to know how B3D's work different from others? I'm thinking someone is getting quaternions confused with axis-angle rotation which can also be written as a 4 component vector:
http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/AV0405/REDSTONE/AxisAngleRotation.html
http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/AV0405/REDSTONE/AxisAngleRotation.html
Maybe you could use Leadwerks function ?
That function does the opposite to what I want. From what I've read, converting that way is much simpler since there is only one possible answer.
www.mathworks.com/access/helpdesk/help/toolbox/aeroblks/index.html?/access/helpdesk/help/toolbox/aeroblks/quaternionstoeulerangles.html&http://www.google.com/search?client=firefox-a&rls=org.mozilla%3Aen-US%3Aofficial&channel=s&hl=en&q=convert+quaternion+to+euler&btnG=Google+Search
Thanks. At first glance that's all greek to me, but I'll have a fiddle with it and see if I can figure out what it all means. It's probably just the notation which I can look up.
As of 1/14/2007:
Const QuatToEulerAccuracy#=0.001 Function EulerAsQuat(pitch#,yaw#,roll#) cr#=Cos(-roll#/2.0) cp#=Cos(pitch#/2.0) cy#=Cos(yaw#/2.0) sr#=Sin(-roll#/2.0) sp#=Sin(pitch#/2.0) sy#=Sin(yaw#/2.0) cpcy#=cp#*cy# spsy#=sp#*sy# spcy#=sp#*cy# cpsy#=cp#*sy# vectorw#=cr#*cpcy#+sr#*spsy# vectorx#=sr#*cpcy#-cr#*spsy# vectory#=cr#*spcy#+sr#*cpsy# vectorz#=cr#*cpsy#-sr#*spcy# End Function Function QuatAsEuler(x#,y#,z#,w#) sint#=(2.0*w*y)-(2.0*x*z) cost_temp#=1.0-(sint#*sint#) If Abs(cost_temp#)>QuatToEulerAccuracy cost#=Sqr(cost_temp#) Else cost#=0.0 EndIf If Abs(cost#)>QuatToEulerAccuracy sinv#=((2.0*y*z)+(2.0*w*x))/cost# cosv#=(1.0-(2.0*x*x)-(2.0*y*y))/cost# sinf#=((2.0*x*y)+(2.0*w*z))/cost# cosf#=(1.0-(2.0*y*y)-(2.0*z*z))/cost# Else sinv#=(2.0*w*x)-(2.0*y*z) cosv#=1.0-(2.0*x*x)-(2.0*z*z) sinf#=0.0 cosf#=1.0 EndIf vectorx#=ATan2(sint#,cost#) vectory#=ATan2(sinf#,cosf#) vectorz#=-ATan2(sinv#,cosv#) End Function
Thanks Halo, but that is producing incorrect results. It's not inaccurate, just using completely wrong axes.
For example, the quaternion (Sqrt(0.5),Sqrt(0.5),0,0) should return 90,0,0 but yours returns 0,0,-90
Do your functions use a different coordinate system or something?
For example, the quaternion (Sqrt(0.5),Sqrt(0.5),0,0) should return 90,0,0 but yours returns 0,0,-90
Do your functions use a different coordinate system or something?
Isn't he working with OpenGL? It is a different coordinate system. Y and Z are reversed from Blitz.
OpenGL doesn't use Quaternions at all. It doesn't really matter what your quaternion conventions are, as long as you use the same method to convert from quat to eulers and back.
Good point. I had only planned to replace the GetRotation function, since I was assured that SetRotation did not suffer with the same problem. However, that's only true if the Quat<>Euler conversions match, so you're right, I should implement them both.
I've tested them with a lot of complex rotations, and they're very accurate on anything but the most complex three axis rotations, and I'm pretty sure complex three axis rotations cannot be converted to Eulers and back at all. So this looks to be perfect.
Thanks very much for sharing it.
I've tested them with a lot of complex rotations, and they're very accurate on anything but the most complex three axis rotations, and I'm pretty sure complex three axis rotations cannot be converted to Eulers and back at all. So this looks to be perfect.
Thanks very much for sharing it.
Actually Halo, I'm getting errors with your functions even with simple single-axis rotations.
If I feed in 91,0,0, convert to Quaternions, then convert back to Eulers, I have 90,0,0
Worse, if I feed in 95,0,0 convert to Quaternions, then convert to Eulers, I have 85,180,-180
Any ideas on this?
If I feed in 91,0,0, convert to Quaternions, then convert back to Eulers, I have 90,0,0
Worse, if I feed in 95,0,0 convert to Quaternions, then convert to Eulers, I have 85,180,-180
Any ideas on this?
Should you even be converting from Euler angles? Don't you really just need a function to convert from a Quaternion to Euler angles? (Because of gimbal lock problems, which is what you get with pitches close to +/- 90 degrees).
If so, then this should do it:
I haven't tried if it works, but that's what the math book says as far as I can tell. Gimme a yell if it doesn't work as expected.
Edit: Oh by the way, the textbook example above assumes angles are in radians. I'm too tired to figure out if using degrees is going to make a difference, but my hunch is "probably not".
If so, then this should do it:
ex = ATan( (2* (w*x + y*z )) / (1-2*(x^2 + y^2))) ey = ASin( 2* (w*y - z*x)) ez = ATan( (2* (w*z + x*y )) / (1-2*(y^2 + z^2)))Where ex is the eular x axis angle (Roll on a gyro), ey is the euler y axis angle (Pitch on a gyro - this is the gimbal that locks - and thus cannot nessecarilly be converted back), ez is the euler z axis angle (yaw on a gyro). For the Quaternion w is the rotation coefficient (the real part) x is the "x orientation" or first imaginary part, y is the "y orientation" or second imaginary part, and z is the "z orientation" or third imaginary part.
I haven't tried if it works, but that's what the math book says as far as I can tell. Gimme a yell if it doesn't work as expected.
Edit: Oh by the way, the textbook example above assumes angles are in radians. I'm too tired to figure out if using degrees is going to make a difference, but my hunch is "probably not".
Gabriel,
I am very familiar with this problem, when I was writing my Max->B3D convertor (don't worry if you've never heard of it, was a LONG time ago), I needed to do the same thing. Looking for a quick fix I downloaded a canned version from the code archieves and added it to my project, it looked ok for some simple tests (it wasn't Halo's version).
Further down the line I found all sorts of strange errors creeping in which I traced back to this code. I tried various other versions available on the forums and suggested by people and none of them worked properly.
Eventually I came across this:
http://www.dscho.co.uk/blitz/tutorials/quaternions.shtml
It has all the source you need and works 100% perfectly (I did numerous and some very complex tests) to my knowledge it's the ONLY set of really good quart->eular funcitons that work for Blitz anywhere and has a lot of other useful info.
I hope it helps you with whatever you want to do.
Darkheart
I am very familiar with this problem, when I was writing my Max->B3D convertor (don't worry if you've never heard of it, was a LONG time ago), I needed to do the same thing. Looking for a quick fix I downloaded a canned version from the code archieves and added it to my project, it looked ok for some simple tests (it wasn't Halo's version).
Further down the line I found all sorts of strange errors creeping in which I traced back to this code. I tried various other versions available on the forums and suggested by people and none of them worked properly.
Eventually I came across this:
http://www.dscho.co.uk/blitz/tutorials/quaternions.shtml
It has all the source you need and works 100% perfectly (I did numerous and some very complex tests) to my knowledge it's the ONLY set of really good quart->eular funcitons that work for Blitz anywhere and has a lot of other useful info.
I hope it helps you with whatever you want to do.
Darkheart
FlameDuck: No, I shouldn't be converting from Euler angles. That's just really for testing so that I can see precisely where the problem is.
I've tried putting that into code, and it works slightly better than some of the ones I've used but it still fails in the same places as Halo's. I haven't examined too carefully, but they're probably doing more or less the same thing. You're right about the radians/degrees, that doesn't matter because ATan and ASin return degrees in Blitz, and don't need to be converted.
DarkHeart: Thanks, but that code fails in exactly the same place as Halo's. Once the X rotation goes above 90, it goes all wrong. The quaternion orientation which should equate to 91,0,0 returns 90,0,0 and it gets worse from there.
I think I'm going to give this up as a bad job. I can do a better job than the way TV was doing it, but not significantly better to make it worth doing.
I'm going to have to find a different way of doing this.
I've tried putting that into code, and it works slightly better than some of the ones I've used but it still fails in the same places as Halo's. I haven't examined too carefully, but they're probably doing more or less the same thing. You're right about the radians/degrees, that doesn't matter because ATan and ASin return degrees in Blitz, and don't need to be converted.
DarkHeart: Thanks, but that code fails in exactly the same place as Halo's. Once the X rotation goes above 90, it goes all wrong. The quaternion orientation which should equate to 91,0,0 returns 90,0,0 and it gets worse from there.
I think I'm going to give this up as a bad job. I can do a better job than the way TV was doing it, but not significantly better to make it worth doing.
I'm going to have to find a different way of doing this.
Const QuatToEuler_Epsilon# = 0.001 Function MyEulerToQuat(Pitch#, Yaw#, Roll#) Pitch# = Pitch# / 2.0 Yaw# = Yaw# / 2.0 Roll# = Roll# / 2.0 Cos_Pitch# = Cos(Pitch#) Cos_Yaw# = Cos(Yaw#) Cos_Roll# = Cos(Roll#); Sin_Pitch# = Sin(Pitch#) Sin_Yaw# = Sin(Yaw#) Sin_Roll# = Sin(Roll#); CpCy# = Cos_Pitch# * Cos_Yaw# SpSy# = Sin_Pitch# * Sin_Yaw# SpCy# = Sin_Pitch# * Cos_Yaw# CpSy# = Cos_Pitch# * Sin_Yaw# QuatLib_Z# = ((Sin_Roll# * CpCy#) - (Cos_Roll# * SpSy#))*-1;x QuatLib_X# = ((Cos_Roll# * SpCy#) + (Sin_Roll# * CpSy#))*-1;y QuatLib_Y# = (Cos_Roll# * CpSy#) - (Sin_Roll# * SpCy#);z QuatLib_W# = (Cos_Roll# * CpCy#) + (Sin_Roll# * SpSy#);w End Function Function MyQuatToEuler(Qxx#, Qyy#, Qzz#, Qw#) Qx#=Qzz#*-1 Qy#=Qxx#*-1 Qz#=Qyy# Qx2# = Qx# * 2.0 Qy2# = Qy# * 2.0 Qz2# = Qz# * 2.0 Sin_T# = (Qy2# * Qw#) - (Qx2# * Qz#) Cos_T# = 1.0 - (Sin_T# * Sin_T#) If Abs(Cos_T#) > QuatToEuler_Epsilon# Cos_T# = Sqr(Cos_T#) Else Cos_T# = 0 EndIf If Abs(Cos_T#) > QuatToEuler_Epsilon# Sin_V# = ( (Qy2# * Qz#) + (Qx2# * Qw#)) / Cos_T# Cos_V# = (1.0 - (Qx2# * Qx#) - (Qy2# * Qy#)) / Cos_T# Sin_F# = ( (Qx2# * Qy#) + (Qz2# * Qw#)) / Cos_T# Cos_F# = (1.0 - (Qy2# * Qy#) - (Qz2# * Qz#)) / Cos_T# Else Sin_V# = (Qx2# * Qw#) - (Qy2# * Qz#) Cos_V# = 1.0 - (Qx2# * Qx#) - (Qz2# * Qz#) Sin_F# = 0 Cos_F# = 1.0 EndIf QuatLib_Pitch# = ATan2(Sin_T#, Cos_T#) QuatLib_Yaw# = ATan2(Sin_F#, Cos_F#) QuatLib_Roll# = ATan2(Sin_V#, Cos_V#) End Function
This is my tweaked variation of the functions - seems to work ok for me in Blitz3d at least.
The quaternion orientation which should equate to 91,0,0 returns 90,0,0 and it gets worse from there.
It should probably return -89,0,0 - if converted correctly. What Quatinion are you using to represent your rotation? Ricky: Thanks, but yours does the same. The quaternion which should come back as 91,0,0 ( or something similar, as FlameDuck points out, there are multiple ways to represent the same angle ) but comes back as 90,0,0
FlameDuck: 91,0,0 gives me a Quanternion ( w,x,y,z ) of (0.7009093,0.7132505,0,0)
I'm pretty sure my best bet will be to forget this and just handle all math in quaternions.
FlameDuck: 91,0,0 gives me a Quanternion ( w,x,y,z ) of (0.7009093,0.7132505,0,0)
I'm pretty sure my best bet will be to forget this and just handle all math in quaternions.
FlameDuck: 91,0,0 gives me a Quanternion ( w,x,y,z ) of (0.7009093,0.7132505,0,0)
Yup. That sounds about right. My example returns ( -88.999988943948296 , 0.00000000000000000 , 0.00000000000000000 ). Here is the code:w! = 0.7009093 x! = 0.7132505 y! = 0 z! = 0 ex! = ATan( (2!* (w*x + y*z )) / (1-2*(x^2 + y^2))) ey! = ASin( 2!* (w*y - z*x)) ez! = ATan( (2!* (w*z + x*y )) / (1-2*(y^2 + z^2))) Print ex Print ey Print ez
or something similar, as FlameDuck points out, there are multiple ways to represent the same angle
It's not really a matter of multiple ways to represent angles, so much as a limit to what range of degrees ATan / ATan2 returns (-90..90). I'm pretty sure my best bet will be to forget this and just handle all math in quaternions.
Unquestionable. Worse, if I feed in 95,0,0 convert to Quaternions, then convert to Eulers, I have 85,180,-180
This is correct!
Work out what angles the two Eulers give you in real life. They're identical.
The QuatToEuler functions given here just give you *one* correct Euler angle. There are many identical Euler angles that can be expressed in different numbers.
It's like a square-root function: what would you expect sqrt((-5) * (-5)) to return?
FlameDuck: Thank you, that indeed seems to be the most accurate way I've found. It's much, more more accurate than the inbuilt conversion so this will be a great replacement for me to provide my own GetRotation() method. Thanks again.
That seems to depend on the order of rotation. Perhaps it's correct for some engines, but it does not appear to be producing the same orientation with the engine I'm using.
And 91,0,0 converts back to 90,0,0 and that's definitely not correct, with any order of rotations.
The QuatToEuler functions given here just give you *one* correct Euler angle.
That seems to depend on the order of rotation. Perhaps it's correct for some engines, but it does not appear to be producing the same orientation with the engine I'm using.
And 91,0,0 converts back to 90,0,0 and that's definitely not correct, with any order of rotations.
That seems to depend on the order of rotation. Perhaps it's correct for some engines, but it does not appear to be producing the same orientation with the engine I'm using.
Apologies, I was assuming you were using Blitz3D.
And 91,0,0 converts back to 90,0,0 and that's definitely not correct, with any order of rotations.
Change the constant QuatToEulerAccuracy (or similar) to a smaller value to get the right answer (89, 180, -180). Or rather, a right answer.