-
Notifications
You must be signed in to change notification settings - Fork 22
/
utils.py
159 lines (126 loc) · 5.61 KB
/
utils.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
147
148
149
150
151
152
153
154
155
156
157
158
'''
Adopted from
https://github.com/StanfordVL/iGibson/blob/master/igibson/external/pybullet_tools/utils.py
'''
from __future__ import print_function
import pybullet as p
from collections import defaultdict, deque, namedtuple
from itertools import product, combinations, count
BASE_LINK = -1
MAX_DISTANCE = 0.
def pairwise_link_collision(body1, link1, body2, link2=BASE_LINK, max_distance=MAX_DISTANCE): # 10000
return len(p.getClosestPoints(bodyA=body1, bodyB=body2, distance=max_distance,
linkIndexA=link1, linkIndexB=link2)) != 0 # getContactPoints
def pairwise_collision(body1, body2, **kwargs):
if isinstance(body1, tuple) or isinstance(body2, tuple):
body1, links1 = expand_links(body1)
body2, links2 = expand_links(body2)
return any_link_pair_collision(body1, links1, body2, links2, **kwargs)
return body_collision(body1, body2, **kwargs)
def expand_links(body):
body, links = body if isinstance(body, tuple) else (body, None)
if links is None:
links = get_all_links(body)
return body, links
def any_link_pair_collision(body1, links1, body2, links2=None, **kwargs):
# TODO: this likely isn't needed anymore
if links1 is None:
links1 = get_all_links(body1)
if links2 is None:
links2 = get_all_links(body2)
for link1, link2 in product(links1, links2):
if (body1 == body2) and (link1 == link2):
continue
if pairwise_link_collision(body1, link1, body2, link2, **kwargs):
# print('body {} link {} body {} link {}'.format(body1, link1, body2, link2))
return True
return False
def body_collision(body1, body2, max_distance=MAX_DISTANCE): # 10000
return len(p.getClosestPoints(bodyA=body1, bodyB=body2, distance=max_distance)) != 0 # getContactPoints`
def get_self_link_pairs(body, joints, disabled_collisions=set(), only_moving=True):
moving_links = get_moving_links(body, joints)
fixed_links = list(set(get_joints(body)) - set(moving_links))
check_link_pairs = list(product(moving_links, fixed_links))
if only_moving:
check_link_pairs.extend(get_moving_pairs(body, joints))
else:
check_link_pairs.extend(combinations(moving_links, 2))
check_link_pairs = list(
filter(lambda pair: not are_links_adjacent(body, *pair), check_link_pairs))
check_link_pairs = list(filter(lambda pair: (pair not in disabled_collisions) and
(pair[::-1] not in disabled_collisions), check_link_pairs))
return check_link_pairs
def get_moving_links(body, joints):
moving_links = set()
for joint in joints:
link = child_link_from_joint(joint)
if link not in moving_links:
moving_links.update(get_link_subtree(body, link))
return list(moving_links)
def get_moving_pairs(body, moving_joints):
"""
Check all fixed and moving pairs
Do not check all fixed and fixed pairs
Check all moving pairs with a common
"""
moving_links = get_moving_links(body, moving_joints)
for link1, link2 in combinations(moving_links, 2):
ancestors1 = set(get_joint_ancestors(body, link1)) & set(moving_joints)
ancestors2 = set(get_joint_ancestors(body, link2)) & set(moving_joints)
if ancestors1 != ancestors2:
yield link1, link2
#####################################
JointInfo = namedtuple('JointInfo', ['jointIndex', 'jointName', 'jointType',
'qIndex', 'uIndex', 'flags',
'jointDamping', 'jointFriction', 'jointLowerLimit', 'jointUpperLimit',
'jointMaxForce', 'jointMaxVelocity', 'linkName', 'jointAxis',
'parentFramePos', 'parentFrameOrn', 'parentIndex'])
def get_joint_info(body, joint):
return JointInfo(*p.getJointInfo(body, joint))
def child_link_from_joint(joint):
return joint # link
def get_num_joints(body):
return p.getNumJoints(body)
def get_joints(body):
return list(range(get_num_joints(body)))
get_links = get_joints
def get_all_links(body):
return [BASE_LINK] + list(get_links(body))
def get_link_parent(body, link):
if link == BASE_LINK:
return None
return get_joint_info(body, link).parentIndex
def get_all_link_parents(body):
return {link: get_link_parent(body, link) for link in get_links(body)}
def get_all_link_children(body):
children = {}
for child, parent in get_all_link_parents(body).items():
if parent not in children:
children[parent] = []
children[parent].append(child)
return children
def get_link_children(body, link):
children = get_all_link_children(body)
return children.get(link, [])
def get_link_ancestors(body, link):
# Returns in order of depth
# Does not include link
parent = get_link_parent(body, link)
if parent is None:
return []
return get_link_ancestors(body, parent) + [parent]
def get_joint_ancestors(body, joint):
link = child_link_from_joint(joint)
return get_link_ancestors(body, link) + [link]
def get_link_descendants(body, link, test=lambda l: True):
descendants = []
for child in get_link_children(body, link):
if test(child):
descendants.append(child)
descendants.extend(get_link_descendants(body, child, test=test))
return descendants
def get_link_subtree(body, link, **kwargs):
return [link] + get_link_descendants(body, link, **kwargs)
def are_links_adjacent(body, link1, link2):
return (get_link_parent(body, link1) == link2) or \
(get_link_parent(body, link2) == link1)