@@ -14,18 +14,15 @@ class TreeTransforms:
14
14
kinematic_tree : KinematicTree = dataclasses .dataclass (init = False )
15
15
16
16
@staticmethod
17
- def build (
18
- model : "rod.Model" ,
19
- is_top_level : bool = True ,
20
- prevent_switching_frame_convention : bool = False ,
21
- ) -> "TreeTransforms" :
17
+ def build (model : "rod.Model" , is_top_level : bool = True ) -> "TreeTransforms" :
18
+
19
+ # Operate on a deep copy of the model to avoid side effects.
22
20
model = copy .deepcopy (model )
23
21
22
+ # Make sure that all elements have a pose attribute with explicit 'relative_to'.
24
23
model .resolve_frames (is_top_level = is_top_level , explicit_frames = True )
25
24
26
- if not prevent_switching_frame_convention :
27
- model .switch_frame_convention (frame_convention = rod .FrameConvention .Urdf )
28
-
25
+ # Build the kinematic tree and return the TreeTransforms object.
29
26
return TreeTransforms (
30
27
kinematic_tree = KinematicTree .build (model = model , is_top_level = is_top_level )
31
28
)
@@ -54,30 +51,54 @@ def transform(self, name: str) -> npt.NDArray:
54
51
55
52
return W_H_E
56
53
57
- if (
58
- name in self .kinematic_tree .link_names ()
59
- or name in self .kinematic_tree .frame_names ()
60
- ):
61
- element = (
62
- self .kinematic_tree .links_dict [name ]
63
- if name in self .kinematic_tree .link_names ()
64
- else self .kinematic_tree .frames_dict [name ]
65
- )
66
- assert element .name () == name
54
+ if name in self .kinematic_tree .link_names ():
67
55
68
- # Get the pose of the frame in which the node's pose is expressed
56
+ element = self .kinematic_tree .links_dict [name ]
57
+
58
+ assert element .name () == name
69
59
assert element ._source .pose .relative_to not in {"" , None }
70
- x_H_N = element ._source .pose .transform ()
60
+
61
+ # Get the pose of the frame in which the link's pose is expressed.
62
+ x_H_L = element ._source .pose .transform ()
71
63
W_H_x = self .transform (name = element ._source .pose .relative_to )
72
64
73
- # Compute and cache the world-to-node transform
74
- W_H_N = W_H_x @ x_H_N
65
+ # Compute the world transform of the link.
66
+ W_H_L = W_H_x @ x_H_L
67
+ return W_H_L
68
+
69
+ if name in self .kinematic_tree .frame_names ():
70
+
71
+ element = self .kinematic_tree .frames_dict [name ]
72
+
73
+ assert element .name () == name
74
+ assert element ._source .pose .relative_to not in {"" , None }
75
75
76
- return W_H_N
76
+ # Get the pose of the frame in which the frame's pose is expressed.
77
+ x_H_F = element ._source .pose .transform ()
78
+ W_H_x = self .transform (name = element ._source .pose .relative_to )
79
+
80
+ # Compute the world transform of the frame.
81
+ W_H_F = W_H_x @ x_H_F
82
+ return W_H_F
77
83
78
84
raise ValueError (name )
79
85
80
86
def relative_transform (self , relative_to : str , name : str ) -> npt .NDArray :
81
- return np .linalg .inv (self .transform (name = relative_to )) @ self .transform (
82
- name = name
87
+
88
+ world_H_name = self .transform (name = name )
89
+ world_H_relative_to = self .transform (name = relative_to )
90
+
91
+ return TreeTransforms .inverse (world_H_relative_to ) @ world_H_name
92
+
93
+ @staticmethod
94
+ def inverse (transform : npt .NDArray ) -> npt .NDArray :
95
+
96
+ R = transform [0 :3 , 0 :3 ]
97
+ p = np .vstack (transform [0 :3 , 3 ])
98
+
99
+ return np .block (
100
+ [
101
+ [R .T , - R .T @ p ],
102
+ [0 , 0 , 0 , 1 ],
103
+ ]
83
104
)
0 commit comments