rbdl / rbdl-toolkit

Application for visualizing and working with rbdl models
European Union Public License 1.2
19 stars 11 forks source link

Joint rotation does not seem to obey right hand rule #22

Closed jfslin closed 3 years ago

jfslin commented 3 years ago

Starting with a basic lua model, and a basic csv:

rod_length = 1

meshes = {
  rod1 = {
    color = { 1, 0, 0},
    mesh_center = {0, 0, -rod_length/2},
    dimensions = { 0.2, 0.2, rod_length},
    src = "unit_cube.obj"
  }
}

model = {
  configuration = {
    axis_right = { 1, 0, 0 },
    axis_front = { 0, 1, 0 },
    axis_up =    { 0, 0, 1 },
  },

  frames = {
    {
      name = "segment1",
      parent = "ROOT",
      visuals = { meshes.rod1 },
      joint = {{ 1, 0, 0, 0, 0, 0 }},
      joint_frame = {
        E = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}
      }
    }
  }
}

return model
0, 0
1, 1.57
2, 3.14
3, 4.73
4, 6.28

I was testing the directions of movement. Using this model as is, I was expecting the movement to be in the X rotation direction, but it does not. Here's a few examples.

Using

# correct, moving the positive x direction
    axis_right = { 1, 0, 0 },
    axis_front = { 0, 1, 0 },
    axis_up =    { 0, 0, 1 },
 joint = {{ 0, 0, 0, 1, 0, 0 }},

gives me a motion to the right-down direction, telling me that is the +X axis direction.

https://user-images.githubusercontent.com/24707634/107701344-c7e4a500-6c86-11eb-82ce-8adb88e0cfa2.mp4

So I would expect the following

# incorrect, expecting counterclockwise movement
    axis_right = { 1, 0, 0 },
    axis_front = { 0, 1, 0 },
    axis_up =    { 0, 0, 1 },
 joint = {{ 1, 0, 0, 0, 0, 0 }},

to rotate by right hand rule around the +X direction. Instead, it incorrectly gives me the opposite motion:

https://user-images.githubusercontent.com/24707634/107701266-aedbf400-6c86-11eb-8863-65c183bc468f.mp4

The following are videos corresponding to flipping the axes direction by Z by 180 deg (so we are still respecting right hand rule global frame), as well as only mirroring the global X axis.

# correct, moving in the positive x direction
    axis_right = { -1, 0, 0 },
    axis_front = { 0, -1, 0 },
    axis_up =    { 0, 0, 1 },
 joint = {{ 0, 0, 0, 1, 0, 0 }},

https://user-images.githubusercontent.com/24707634/107702891-eb105400-6c88-11eb-88b3-f87a17ecb9d3.mp4

# incorrect, expecting clockwise movement
    axis_right = { -1, 0, 0 },
    axis_front = { 0, -1, 0 },
    axis_up =    { 0, 0, 1 },
 joint = {{ 1, 0, 0, 0, 0, 0 }},

https://user-images.githubusercontent.com/24707634/107702860-dcc23800-6c88-11eb-9cd5-05fa3e80c755.mp4

# correct, moving in the positive x direction
    axis_right = { -1, 0, 0 },
    axis_front = { 0, 1, 0 },
    axis_up =    { 0, 0, 1 },
 joint = {{ 0, 0, 0, 1, 0, 0 }},

https://user-images.githubusercontent.com/24707634/107702956-fb283380-6c88-11eb-8f58-f4b257a6a058.mp4

# correct, moving CW
    axis_right = { -1, 0, 0 },
    axis_front = { 0, 1, 0 },
    axis_up =    { 0, 0, 1 },
 joint = {{ 1, 0, 0, 0, 0, 0 }},

https://user-images.githubusercontent.com/24707634/107702970-ffece780-6c88-11eb-8f83-cac50b9692f2.mp4

ju6ge commented 3 years ago

So had some time to think about this. In short this is not a problem, because the axis configuration you started with is left handed:

configuration = {
    axis_right = { 1, 0, 0 },
    axis_front = { 0, 1, 0 },
    axis_up =    { 0, 0, 1 },
  },

Let me explain. OpenGL uses a fixed coordinate system that is centered around the perspective of the monitor. This means that the Up-Axis corresponds to the Y-Axis of the monitor and the rigth-axis corresponds to the X-axis of the monitor. The positive right axis points in the direction that corresponds to right on the monitor. The Front Axis then corresponds to the axis that is coming out of the monitor in direction of the viewer. This makes the OpenGL coordinate system right handed and the coordinate mapping is as follows:

{x, y, z} = {right, up, front}

So as you can see in the above configuration the up and front axis are swapped making it a left handed coordinate system.

Now the library RBDL does not in any way use this axis configuration. It is only used by the toolkit and formerly meshup with the intent of mapping the fixed right handed RBDL coordinates to the OpenGl-axis. But meshup screwed this up the are a lot of bugs in it that lead to completely broken models where meshes suddenly have a different orientation from the model depending on the configuration. But there where configurations that lead to the model looking correct. These Bugs are not present in the Toolkit any more but it also means that the configuration of old meshup models can not really be trusted to be correct, because people just changed it until it looked correct. And since the purpose of the configuration is to map the model axis to OpenGL axis I think it is much clearer if we think about the different configuration axis in terms of the OpenGl coordinates and how they are mapped to the model axis.

mjhmilla commented 3 years ago

Hello Jonathan,

Just a quick(ish) note to let you know that Felix and I went through the code that makes use of the configuration field. Since I'm stretched for time, I hope this response is sufficient. If necessary, I can provide a more detailed response at a later time. Here goes:

To start, the 'configuration' field affects only the animation. It has no effect on the RBDL model. The oddities that you are noticing are mostly due to two facts:

  1. The names of the axis are misleading (which means you expect one thing and get another). These axis are used to define a rotation matrix that rotates the model's Root frame into the frame used by OpenGL. It is important to know OpenGL's frame always has Y up, and so for things to look correct, the model's 'up' axis needs to be rotated to be in the Y direction. The vectors put into axis_right, axis_up, and axis_front are used to build the rotation matrix G_R_M. Here I use the following notation convention:

G_R_M G: OpenGL frame R: R for rotation matrix M: Model's root frame).

where the ordering is (To Frame)R(From Frame). And so the matrix G_R_M will transform vectors expressed in the coordinates of the M frame (M_r) into the coordinates of the G frame (G_r):

G_r = G_R_M * M_r

How is G_R_M built using axis_right, axis_up, and axis_front?

which in Matlab notation, G_R_M is built like this:

G_R_M = [axis_right;... axis_up;... axis_front]

This level of detail should have never been exposed because its unnecessary, and few people are able to use this correctly. Using the first example you gave

axis_right = { 1, 0, 0 }, axis_front = { 0, 1, 0 }, axis_up = { 0, 0, 1 },

will yield this rotation matrix

G_R_M = [ 1, 0, 0 0, 0, 1 0, 1, 0].

This rotation matrix will exchange the Y and Z model axis but leave the X untouched. You should notice something strange if you draw a right handed coordinate system (Z axis up, like the model) and try to draw what happens after this transformation. Which leads me to the second problem.

  1. The second problem, is that the 'axis' fields allow you to put in any mapping you want. Even one that breaks the cross-product rule or isn't a rotation matrix. This is not checked by any code and so it is completely up to the person using these fields to make sure that they haven't put in a rotation matrix in which the transformed vectors break the right hand rule. This is terrible software design. It's been a part of RBDL for ages, and there are many models that use these fields, so we haven't yet been able to get rid of it. The unnecessary flexibility of these fields have allowed many people in the past to put values in here that make no physical sense whatsoever. This is part of the reason why some of the older models do not display correctly.

In the first example, you gave the transformed basis do not obey the cross-product rule. As you correctly observe, the movement is consistent with a left-handed coordinate system. However the reason is not because anything has changed with the simulation: RBDL doesn't look at the configuration field at all. What has happened is that you have been allowed to enter a mapping for configuration that results in a left handed coordinate system, and were even encouraged to do so because of the poor names and unnecessary flexibility.

In the meantime, if you start with the setting below, you can be sure that your data is animated without any transformation applied to it. But it will be displayed with the Y axis up as is the convention used by OpenGL.

axis_right = {1,0,0} axis_up = {0,1,0} axis_front = {0,0,1}

If you want to build a different mapping, do so by building G_R_M, by applying rotation matrices until you have the correct 'up axis' in the y-row. Then put the rows of this matrix into the correct axis labels. With some practice you can do this quickly and correctly in your head. If you just play with the numbers until things look 'correct' you can inadvertently create a G_R_M that results in left-handed coordinate system.

As an example, lets start with the first example in this post. If you draw the OpenGL frame on the left (Y up), and your model frame on the right (Z up) it should be clear that this is a valid option

G_R_M = [ 1, 0, 0 0, 0, 1 0, -1, 0]

which means you'd set

axis_right = {1,0,0} axis_up = {0,0,1} axis_front = {0,-1,0}.

jfslin commented 3 years ago

Hi Felix, Matt,

Thanks for the detailed explaination, I understand the situation now. I have updated some of these comments into the Creating Model wiki page. I did find it odd that the axis is defined as "right, up, front" and as you've deduced, assumed incorrectly that I can freely define the axes directions. So ultimately, this axis mapping is applied only to during the visualization of RBDL and not within the RBDL itself, but it would still be nice to have a set of directions that is visually correct.

I do indeed want Z up. So to get the visualization to show X forward, Y left, and Z up, I used roty(-90)*rotx(-90) and got the following:

axis_right = { 0, 0, 1 },
axis_front = { 1, 0, 0 },
axis_up =    { 0, 1, 0 }

and have confirmed that this does respect right hand rule.

mjhmilla commented 3 years ago

Dear Jonathan,

I'm glad the explanation was clear enough to follow. Thank you for the excellent wiki entries! I'm sure any newcomers to RBDL/multibody dynamics will really appreciate the illustrations and concise descriptions.

Cheers,

Matt

On Fri, Apr 9, 2021 at 11:00 PM Jonathan Lin @.***> wrote:

Hi Felix, Matt,

Thanks for the detailed explaination, I understand the situation now. I have updated some of these comments into the Creating Model wiki page https://github.com/ORB-HD/rbdl-toolkit/wiki/Creating-Models. I did find it odd that the axis is defined as "right, up, front" and as you've deduced, assumed incorrectly that I can freely define the axes directions. So ultimately, this axis mapping is applied only to during the visualization of RBDL and not within the RBDL itself, but it would still be nice to have a set of directions that is visually correct.

I do indeed want Z up. So to get the visualization to show X forward, Y left, and Z up, I used roty(-90)*rotx(-90) and got the following:

axis_right = { 0, 0, 1 }, axis_front = { 1, 0, 0 }, axis_up = { 0, 1, 0 }

and have confirmed that this does respect right hand rule.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/ORB-HD/rbdl-toolkit/issues/22#issuecomment-816969039, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABDGG5CAL2XP34GFHB65443TH5TGHANCNFSM4XP6VI4A .

jcllau commented 3 years ago

Hello,

I'd like to make a note here about the axis configurations too. Originally, I also had the following and it affected the visual displays. configuration = { axis_right = {1, 0, 0}, axis_front = {0, 1, 0}, axis_up = {0, 0, 1}, }, For instance, I had two symmetrical stl files (left leg and right leg). When I defined the left leg mesh to show the left leg stl, rbdl-toolkit showed the "right leg", which really was the left leg flipped about the vertical axis. The visuals are correct after changing the axis config to: configuration = { axis_front = {1, 0, 0}, axis_right = {0, 1, 0}, axis_up = {0, 0, 1}, },

Thank you again @ju6ge for the help!!

Best, Jan

mjhmilla commented 3 years ago

Dear Jan,

It is true that the axis vectors are not checked, at the moment, and it is possible to manually enter any matrix (as noted here: https://github.com/ORB-HD/rbdl-toolkit/issues/22#issuecomment-811850104). In the future it would be great to check the axis vectors to make sure that they form a valid rotation matrix but for now this is something for the future, or to replace this with something better.

Best,

Matt