forked from ami-iit/adam
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathurdf_tree.py
146 lines (129 loc) · 5.52 KB
/
urdf_tree.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# Copyright (C) 2021 Istituto Italiano di Tecnologia (IIT). All rights reserved.
# This software may be modified and distributed under the terms of the
# GNU Lesser General Public License v2.1 or any later version.
import contextlib
import logging
from dataclasses import dataclass, field
from os import error
from typing import List
from prettytable import PrettyTable
from urdf_parser_py.urdf import URDF
@dataclass
class Tree:
joints: List[str] = field(default_factory=list)
links: List[str] = field(default_factory=list)
parents: List[str] = field(default_factory=list)
N: int = None
@dataclass
class Element:
name: str
idx: int = None
class URDFTree:
"""This class builds the branched tree graph from a given urdf and the list of joints"""
joint_types = ["prismatic", "revolute", "continuous"]
def __init__(
self,
urdfstring: str,
joints_name_list: list,
root_link: str = "root_link",
) -> None:
"""
Args:
urdfstring (str): path of the urdf
joints_name_list (list): list of the actuated joints
root_link (str, optional): the first link. Defaults to 'root_link'.
"""
self.robot_desc = URDF.from_xml_file(urdfstring)
self.joints_list = self.get_joints_info_from_reduced_model(joints_name_list)
self.NDoF = len(self.joints_list)
self.root_link = root_link
def get_joints_info_from_reduced_model(self, joints_name_list: list) -> list:
joints_list = []
for item in self.robot_desc.joint_map:
self.robot_desc.joint_map[item].idx = None
for [idx, joint_str] in enumerate(joints_name_list):
# adding the field idx to the reduced joint list
self.robot_desc.joint_map[joint_str].idx = idx
joints_list += [self.robot_desc.joint_map[joint_str]]
if len(joints_list) != len(joints_name_list):
raise error("Some joints are not in the URDF")
return joints_list
def load_model(self):
"""This function computes the branched tree graph.
Returns:
The list of links, frames, the connecting joints and the tree.
It also prints the urdf elements.
"""
links = []
frames = []
joints = []
tree = Tree()
# If the link does not have inertia is considered a frame
for item in self.robot_desc.link_map:
if self.robot_desc.link_map[item].inertial is not None:
links += [item]
else:
frames += [item]
table_links = PrettyTable(["Idx", "Link name"])
table_links.title = "Links"
for [i, item] in enumerate(links):
table_links.add_row([i, item])
logging.debug(table_links)
table_frames = PrettyTable(["Idx", "Frame name", "Parent"])
table_frames.title = "Frames"
for [i, item] in enumerate(frames):
with contextlib.suppress(Exception):
table_frames.add_row(
[
i,
item,
self.robot_desc.parent_map[item][1],
]
)
logging.debug(table_frames)
"""The node 0 contains the 1st link, the fictitious joint that connects the root the the world
and the world"""
tree.links.append(self.robot_desc.link_map[self.root_link])
joint_0 = Element("fictitious_joint")
tree.joints.append(joint_0)
parent_0 = Element("world_link")
tree.parents.append(parent_0)
table_joints = PrettyTable(["Idx", "Joint name", "Type", "Parent", "Child"])
table_joints.title = "Joints"
# Cicling on the joints. I need to check that the tree order is correct.
# An element in the parent list should be already present in the link list. If not, no element is added to the tree.
# If a joint is already in the list of joints, no element is added to the tree.
i = 1
for _ in self.robot_desc.joint_map:
for item in self.robot_desc.joint_map:
parent = self.robot_desc.joint_map[item].parent
child = self.robot_desc.joint_map[item].child
if (
self.robot_desc.link_map[parent]
in tree.links # this line preserves the order in the tree
and self.robot_desc.joint_map[item]
not in tree.joints # if the joint is present in the list of joints, no element is added
and self.robot_desc.link_map[child].inertial
is not None # if the child is a frame (massless link), no element is added
):
joints += [item]
table_joints.add_row(
[
i,
item,
self.robot_desc.joint_map[item].type,
parent,
child,
]
)
i += 1
tree.joints.append(self.robot_desc.joint_map[item])
tree.links.append(
self.robot_desc.link_map[self.robot_desc.joint_map[item].child]
)
tree.parents.append(
self.robot_desc.link_map[self.robot_desc.joint_map[item].parent]
)
tree.N = len(tree.links)
logging.debug(table_joints)
return links, frames, joints, tree