Incremental rotation towards target 3D

Started by
15 comments, last by JM33 11 years, 4 months ago
Sorry Alvaro, the documentation didn't help me as it does not show how they calculate the unreal part. If you say the unreal part is "0 + xi +yj +zk", then how do I get the value of i,j,k?

In my last post I had assumed the unreal part was 0 + q.x+q.y+q.z by making i,j and k equal to 1. As I said that produced bad results. I don't think setting them to zero would work, but I also tried multiplying each by the real part "w". Again bad results.

Sorry for not understanding, I think I'm struggling to understand the imaginary part of quaternions. It seems sometimes i,j,k just get dropped (meaning value of 1), and sometimes they are zero. I really appreciate your help.
Advertisement

Sorry Alvaro, the documentation didn't help me as it does not show how they calculate the unreal part. If you say the unreal part is "0 + xi +yj +zk", then how do I get the value of i,j,k?


The unreal part is what I said, and the documentation says the same thing: The unreal part of a quaternion is another quaternion, which happens to have the real part zeroed out. To get the values of x, y and z from q = w + xi + yj + zk, you use something like R_component_2(), R_component_3() and R_component_4(). But this should be irrelevant, since you aren't using Boost.Quaternions.


Sorry for not understanding, I think I'm struggling to understand the imaginary part of quaternions. It seems sometimes i,j,k just get dropped (meaning value of 1), and sometimes they are zero. I really appreciate your help.

i, j and k are never 1 and they are never 0. I am not sure what you have seen that gave you that impression.
Well, I have to create my own quaternion class, and I didn't have an unreal() method so I was just trying to figure that out. I found through a search that with quaternions, i = j = k = sqrt(-1).

[source lang="java"]public double unreal() {

double i = FloatMath.sqrt(-1);
double unreal = this.x*i + this.y*i + this.z*i;

return unreal;
}[/source]

However, I just plugged that in and it didn't work. So I will check over some of my code.
That is some very confused post. i, j and k are different things, which have something to do with rotating 180 degrees around the x, y and z axes, or something like that. It is true that i^2 = j^2 = k^2 = -1, but this should tell you that they are not real numbers and therefore cannot fit in a double.
public Quaternion unreal() {
return Quaternion(0, this.x, this.y, this.z); // or with `new', or however this is done in your language.
}
OK, yes I was very confused, and I never needed to solve for i,j,k in the first place.

The code you gave me works as often as the original code I had with angle/axis, however with the opposite effect. Basically if my plane is upside down I hit the target, otherwise not. If I remove the lines to negate the quaternion when q.real() is less than 0, I get the original results (plane upside down = miss & plane right side up = hit).

If you have any suggestion or insight please let me know. I feel like this is really close to the right solution as the rotation is being correctly limited to the maximum rotation, but still needs to be inverted properly. I am wondering if there is anything that can be referenced to determine when to negate the quaternion, such as the up vectors of the rocket and target?

Here is my code as-is:
[source lang="java"]Vector3D targvec = new Vector3D(targetmatrix[12], targetmatrix[13], targetmatrix[14]);
Vector3D R1pos = new Vector3D(R1Matrix[12], R1Matrix[13], R1Matrix[14]);
Vector3D R1head = new Vector3D(R1Matrix[8], R1Matrix[9], R1Matrix[10]);

Vector3D newtargvec = targvec.subtract(R1pos);
newtargvec = newtargvec.normalize();
R1head = R1head.normalize();

Quaternion head = new Quaternion(0, R1head.getX(), R1head.getY(), R1head.getZ()).normalize();
Quaternion newvec = new Quaternion(0, newtargvec.getX(), newtargvec.getY(), newtargvec.getZ()).normalize();
Quaternion rot = head.rotBetween(newvec).normalize();
float turn_threshold = 0.9998477f; // cos(maxrot/2) = cos(1)
Quaternion newq = rot.limit_rotation(rot, turn_threshold); // see Quaternion code below
float[] qmat = newq.toMatrix();
Matrix.multiplyMM(R1Matrix, 0, R1Matrix, 0, qmat, 0);[/source]

And my relative Quaternion functions:
[source lang="java"]public Quaternion limit_rotation(Quaternion q, float min_real_part) {
if (q.real() <= -min_real_part || q.real() >= min_real_part)
return q;
if(q.real() < 0){
q = q.multF(-1); // negate quaternion
}

float desired_unreal_length = FloatMath.sqrt(1 - min_real_part * min_real_part);
float old_unreal_length = q.unreal().abs();

Quaternion limit = new Quaternion(min_real_part, q.x * (desired_unreal_length / old_unreal_length), q.y * (desired_unreal_length / old_unreal_length), q.z * (desired_unreal_length / old_unreal_length));
Log.i("QuatLimit", "Result = w: " + Float.toString(min_real_part) + ", x:" + Float.toString(limit.x) + ", y:" + Float.toString(limit.y) + ", z:"+ Float.toString(limit.z));

return limit;
}

public Quaternion(float real) {
this.w = real;
this.x = 0;
this.y = 0;
this.z = 0;
}

public float real() {
return this.w;
}

public Quaternion unreal() {
return new Quaternion(0, this.x, this.y, this.z);
}

public float abs() {
return FloatMath.sqrt(x * x + y * y + z * z + w * w);
}
public Quaternion (float w, float x, float y, float z) {
this.set(w, x, y, z);
}

public Quaternion multF(float scalar) {
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
this.w *= scalar;
return this;
}


[/source]
The main suggestion I have is to try to isolate one instance of the computation where the code is not doing what you want it to do, look at the numbers, follow the code with a debugger and see where things are going wrong. That's a really boring thing to do, but also extremely useful.
Solved! Basically what I needed to do was orient the quaternion to the rocket's current orientation around the forward vector. I was only supplying the forward vector, which was not enough to know if I had any amount of "roll" around the forward vector.

So I ended up making a quaternion of the current rocket rotation from the current matrix, and multiplying that by the limit_rotation quaternion from before. Then I set that back to a matrix plugged that into the rotation portion of the rockets matrix(Instead of multiplying the two matrices).

[source lang="java"]Quaternion transform_rotation = Quaternion.setFromMatrix(R1Matrix).normalize();
Quaternion head = new Quaternion(0, R1head.getX(), R1head.getY(), R1head.getZ()).normalize();
Quaternion newvec = new Quaternion(0, newtargvec.getX(), newtargvec.getY(), newtargvec.getZ()).normalize();
Quaternion rot = head.rotBetween(newvec).normalize();

float turn_threshold = 0.999874f; // maxrot is the rockets maximum rotation angle (2)
rot = Quaternion.limit_rotation(rot, turn_threshold).multQ(transform_rotation);

float[] qmat = rot.toMatrix();

for (int i= 0; i< 10; i++){
R1Matrix = qmat;
}


[/source]

Thank you so much Álvaro, your code worked perfectly to limit the rotation of the quaternion. biggrin.png

This topic is closed to new replies.

Advertisement