Hacker News new | past | comments | ask | show | jobs | submit login

>Your company can still use quaternions to represent the rotations of each axis

I don't understand this can you elaborate? My company does indeed use motorized pan tilt units.




I meant when you want to compute the final orientation (lets ignore position): Each axis results in some orientation change which can be expressed as a quaternion. The final orientation can then be computed by combining the quaternions into one quaternion. This is very similar to the computation of forward kinematics (https://en.wikipedia.org/wiki/Forward_kinematics) for robots, which just have additional translations for the transformations.

As said before you still want to retain the actual angles somewhere.

Depending on your physical configuration one of the Euler angle variants (Tait–Bryan angles is another term to search for) could perfectly describe your case and you could just use these to store the angles. Euler angles can also be converted to quaternion. But you can't recover the original used angles from the quaternion alone because of the 2pi wrapping of angles.

For others still wondering why quaternion or orientation alone won't suffice, here is a different example: Imagine an axis which can rotate more than only one revolution, i.e. can have angles like 4 pi, for example motorized volume knobs. An orientation alone can't represent that as it wraps the angles to 2pi. User manually turns the knob to two full revolutions (4pi) and then increases the value by remote control, which results in motorized knob to rotate. Should the knob turn back to nearly zero revolutions (rotate back 4pi) plus the increase? No, it should rotate to 4pi+increase.

By the way, when you have internally stored the "multi revolution" angle and have a sensor reading in range [0..2pi[ you can recover an multi revolution angle equivalent to the sensor reading with wrapToPiSeq( angle in radians before, sensor reading).

  # to equivalent angle in [0,2pi[ range
  def wrapTo2Pi(rad): 
    return rad % (2*pi)

  # to equivalent angle in ]-pi,pi] range
  def wrapToPi(rad):
    return wrapTo2Pi(rad + pi) - pi
  
  # angle difference between rad0 and rad1, in range ]-pi,pi]
  def angleDiff(rad0, rad1):
    r0 = wrapToPi(rad0)
    r1 = wrapToPi(rad1)
    return wrapToPi(r1-r0)
  
  # rad1 to equivalent angle so the jump from rad0won't be greater than |PI|
  def wrapToPiSeq(rad0, rad1):
    r0 = wrapToPi(rad0)
    r1 = wrapToPi(rad1)
    diff = wrapToPi(r1-r0)
    return rad0+diff


I get what what your saying here. So use 3 quaternions to represent the orientation rather then 1. Right?

But doesn't that magnify the problem by 3x? Extracting the angle from the quat again can yield multiple possibilities. If you have 3 quats you now have 3x more possibilities. This can only be done if you assume certain restrictions for each quat such that they yield a singular axis angle when you do a back conversion.

Additionally doesn't that technique yield more possibility to encode axises that are incorrect? A quaternion representing the x axis can be accidentally encoded with rotations along other axises. It's better to keep the type of your domain restricted to be able to encode only possible answers.

Still this can be done as a valid-ish workaround. I give you credit for that, I wouldn't of thought of this so thanks for ur explanation. Although I might use this idea it is far from ideal imo because of the problems I mentioned above. That is if I interpreted what you're saying correctly?

Also addressing your example, the bigger problem in my mind is that there are still issues that arise even if the physical gimbal is restricted on all axises to (0, 2pi). Any gimbal that can go 4pi likely can go infinite pi and that knob will likely be the same so losing rotational information greater than 2pi is ok for most cases in my mind. (If the system yawed 790pi, users are usually only interested in some value under 2pi). The insidious thing imo, is that information is lost even in (0, 2pi) and a lot of people don't realize this.


Noooo, I didn't clarify enough.

Represent your axes with the actual angles. These probably correspond to motor position or revolutions.

Use the quaternions only when you want an orientation for these angles.

Maybe you want to know in which direction the PTU is pointing for a particular set of motor positions, or axis angles. Compute the kinematic chain by multiplying the quaternions corresponding to each axis in the order they are physically applied, but multiply from right to left. Your final result is one quaternion representing the direction the PTU is pointing at. (You could also use 3x3 matrices or other representations) Depending on your physical configuration one of the Euler angle variants (Tait–Bryan angles is another term to search for) could perfectly describe your case and you could just use these to store the angles and compute the orientation.

If you don't actually need the final orientation, then you can omit the quaternions altogether.

If you have orientations as input and need to control the motors so the PTUs are pointing in the required direction: I would compute the current orientation of the PTU. Then compute a trajectory of quaternions interpolating from the current orientation to the target orientation (use quaternion slerp for interpolation). Then at each timestep you compute the required motor positions using inverse kinematics [1].

It is a common problem that multiple motor positions are possible and actually an unfinished research problem. Now that I wrote this, I think this might be the problem you are encountering.

For PTU I think it would be ok to try to recover the current target angles from the target quaternions of the trajectory using one of the Euler configurations. There are papers [2] listing all together, so one can try which is correct. Having a configuration chosen there is still the problem of multiple solutions. In this case use the one closest to the actual current angles. For cases when all angles are possible for an axis, use the current angle as target (i.e. motor doesn't change). When you then have an target angle use `wrapToPiSeq` to get an equivalent angle close the current actual angle as input for the motor controller.

[1] https://en.wikipedia.org/wiki/Inverse_kinematics In computer animation and robotics, inverse kinematics is the mathematical process of calculating the variable joint parameters needed to place the end of a kinematic chain, such as a robot manipulator or animation character's skeleton, in a given position and orientation relative to the start of the chain.

[2] In the past I used this (but be careful in which direction they apply the transformations, I stumbled over this): Diebel, J. (2006). Representing attitude: Euler angles, unit quaternions, and rotation vectors. Matrix, 58(15-16), 1-35. https://www.astro.rug.nl/software/kapteyn/_downloads/fa29752...


When switching target orientation while already approaching one I would use quadratic bezier splines to get a smooth switch (https://ibiblio.org/e-notes/Splines/bezier.html). These just use linear interpolation, multiple times. In the case of quaternions replace the linear interpolations with quaternion slerps and you get quadratic bezier splines over orientations.


I'm not sure how we do it in this case. I know we already follow a trapezoidal velocity profile when approaching a target, but mid switch to another target I'm not sure what we're using. Thanks for this, I will look into it.


> In this case use the one closest to the actual current angles. For cases when all angles are possible for an axis, use the current angle as target (i.e. motor doesn't change). When you then have an target angle use `wrapToPiSeq` to get an equivalent angle close the current actual angle as input for the motor controller.

Yeah that's how I solved this issue. But still if we avoided quaternions we wouldn't have this problem all together, which is my point.

Specifically what's going on is that we're sending quaternion values over the network and the person on the receiving end needs YPR so we're basically like wtf, there's no transformations being performed on the quat, the source of info is a YPR and the output is needed is the same exact YPR so we're only converting to a company wide Quat Protobuf type to send over the wire. I submitted a request to make a new protobuf type that included YPR but I was met with huge company resistance from other engineers saying that a YPR was redundant to a Quat (It's not).

>In computer animation and robotics, inverse kinematics is the mathematical process of calculating the variable joint parameters needed to place the end of a kinematic chain, such as a robot manipulator or animation character's skeleton, in a given position and orientation relative to the start of the chain.

Interesting, but yeah the application in my company is just a single gimbal so there's no chain of "joints" here. I don't think this would apply to our my specific case.

>https://www.astro.rug.nl/software/kapteyn/_downloads/fa29752...

Thanks for all your input. I'll take a look at the link above, it looks interesting.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: