Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

3d orientation problem

Discussion in 'Scripting' started by Wowo51, Oct 27, 2015.

  1. Wowo51

    Wowo51

    Joined:
    Oct 12, 2015
    Posts:
    25
    Given any number of 'servos' that can rotate an object to a specific rotational position and hold it there, what is the best configuration to orientate an object in 3 dimensions? The 'servos' are mathematical constructs that will accelerate an effector towards a target and decelerate upon approach in one dimension.

    I'll explain the problem that arises. Take the 3 dimensional positioning problem. One can allocate a servo to each of the 3 axis(x,y,z), but you get orbital motion. The sum effect of the servos is to accelerate the effector constantly towards the target, producing precisely the same effect as gravity. One can decompose the velocity of the effector into two vectors, one that points towards the target from the effector, and one orthogonal to that, and assign a servo to each of the two vectors just described. The servo assigned to the orthogonal vector can decelerate orbital motion while the other works at getting the effector to the target. This approach works and I have a functioning 3d positioning device that will move an effector to a target position and bring it to rest there, whatever the initial velocity of the effector.

    Now back to the orientation problem. A similar 'orbital' problem arises. My code:

    Quaternion rotationTowards = Quaternion.Inverse(inCurrentRotation) * inTargetRotation;
    Vector3 axis;
    float angle2;
    rotationTowards.ToAngleAxis(out angle2, out axis);
    float power = (float)rotationServo.Force(-angle2, 0, elapsedTime);
    return power * axis;

    Seems to work ok at accelerating the effector directly towards the desired orientation, similar to accelerating directly at the target in the positioning problem above. Instead of endless orbiting I get endless 'gyration' about the desired orientation. Is there a quaternion decomposition that is appropriate for my problem? The equivalent of an 'orthogonal quaternion'? That would allow me a similar approach to what worked for the positioning problem. Or am I just going about it all wrong. Is there some proven configuration of 'servos' that will orientate my effector appropriately?
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    You're throwing out half your information when you decompose that Quaternion... that being the axis.

    Note, the 'axis' portion that is returned might be any of the infinite number of possible axes.

    You're ignoring that axis, and just rotating your servo around its own axis the amount the quaternion says its rotated around some arbitrary axis.

    Of course, if you rotate your servos around they'll get really close to the target. Because as the rotation between the server rotation and the quats rotation shrink, the angle of rotation around the quats return axis shrinks. But the axis still spins around arbitrarily, so when you get too close, it just starts spitting out small varying changes, resulting in that 'gyrating' effect.


    What you need to be doing is defining what axis each servo rotates around. Then decompose the quaternion to the amount of rotation around that axis. Usually this is the standard euler angles with x,y,z axes. You could calculate for other axes, in the case where the servos rotate around a non-traditional, and/or, arbitrary axis. But unity doesn't supply a simple funciton to decompose around said axis.

    Especially noting that quaternions are NOT a position of rotation. But are rather more like vectors, in that they are a direction and magnitude of rotation. It's an "amount" of rotation to apply, unity just implies that the initial/default rotation is the orientation we see in game. Just like position vectors imply that <0,0,0> is initial/default position.
     
  3. Wowo51

    Wowo51

    Joined:
    Oct 12, 2015
    Posts:
    25
    I use the axis in the final line, it does not appear to be wasted.
     
  4. Wowo51

    Wowo51

    Joined:
    Oct 12, 2015
    Posts:
    25
    The 'power * axis' is then sent to the rigid body of the effector as a torque.
     
  5. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    I didn't notice that multiply by axis at the end there, you should try using the code tags in the future.

    Either way though, I was referring to this line here:

    Code (csharp):
    1.  
    2. float power = (float)rotationServo.Force(-angle2, 0, elapsedTime);
    3.  
    Is 'rotationServo' not a reference to the servo? And is this function not applying some force to that servo?

    What axis does that servo rotate around? You pass in angle2 to it, which is the angle that came back from ToAngleAxis. That angle is around some arbitrary axis... most likely not the one that 'rotationServo' rotates around.

    Unless that line of code doesn't do what I'm assuming. In which case... give me a better explanation of what you're doing in your code. You describe your situation very detailed, you include little to no description of the code.
     
  6. Wowo51

    Wowo51

    Joined:
    Oct 12, 2015
    Posts:
    25
    rotationTowards is a single rotation that takes one directly from the starting orientation, inCurrentRotation, to the desired orientation, inTargetRotation. rotationTowards is decomposed to angle2 and its axis of rotation. power is just the magnitude, a 1D quantity. Yes, rotationServo is the servo, it's a 1D servo that knows nothing of three dimensions, it is used as a 1D component and only calculates the magnitude of the force required. The axis of rotation of rotationTowards is then passed out in the next line. The 'power * axis' is then sent to the rigid body of the effector as a torque outside of this function.
     
  7. Wowo51

    Wowo51

    Joined:
    Oct 12, 2015
    Posts:
    25
    No, the servo is not having a force applied to it, it is calculating force required.
     
  8. Wowo51

    Wowo51

    Joined:
    Oct 12, 2015
    Posts:
    25
    Solved.

    This line:
    Quaternion rotationTowards = Quaternion.Inverse(inCurrentRotation) * inTargetRotation;

    should be:
    Quaternion rotationTowards = inTargetRotation * Quaternion.Inverse(inCurrentRotation);

    I also added deceleration/damping:
    effectorRigidBody.AddTorque(-effectorRigidBody.angularVelocity * decelerationFactor);


    My effector is now smoothly orientating.