2 Copyright (c) 2020 INRIA 3 Inspired from Antonio El Khoury PhD: https://tel.archives-ouvertes.fr/file/index/docid/833019/filename/thesis.pdf 4 Section 3.8.1 Computing minimum bounding capsules 14 a, b: the two extremities of the capsule segment 15 r: radius of the capsule 19 CONSTRAINT_INFLATION_RATIO = 5e-3
23 return np.linalg.norm(b - a) * np.pi * r ** 2 + 4 / 3 * np.pi * r ** 3
29 t = ap.dot(ab) / ab.dot(ab)
31 p_witness = a[
None, :] + (b - a)[
None, :] * t[:,
None]
32 dist = np.linalg.norm(p - p_witness, axis=1).
max()
37 mean = vertices.mean(axis=0)
39 u, s, vh = np.linalg.svd(vertices, full_matrices=
True)
41 pca_proj = vertices.dot(components.T)
44 a0 = mean + components[0] * (pca_proj[:, 0].
min() - EPSILON)
45 b0 = mean + components[0] * (pca_proj[:, 0].
max() + EPSILON)
46 radius = np.linalg.norm(pca_proj[:, 1:], axis=1).
max()
52 constraint_inflation = CONSTRAINT_INFLATION_RATIO * r0
53 x0 = np.array(list(a0) + list(b0) + [r0])
56 constraint = optimize.NonlinearConstraint(
57 constraint_cap, lb=-np.inf, ub=-constraint_inflation
59 res = optimize.minimize(capsule_vol, x0, constraints=constraint)
60 res_constraint = constraint_cap(res.x)
62 res_constraint <= 1e-4
63 ),
"The computed solution is invalid, a vertex is at a distance {:.5f} of the capsule.".format(
66 a, b, r = res.x[:3], res.x[3:6], res.x[6]
70 mesh_loader = hppfcl.MeshLoader()
71 mesh = mesh_loader.load(filename, np.ones(3))
72 vertices = np.array([ lMg * mesh.vertices(i)
for i
in range(mesh.num_vertices) ])
73 assert vertices.shape == (mesh.num_vertices, 3)
78 from lxml
import etree
80 tree = etree.parse(infile)
83 if fn.startswith(
'package://'):
84 relpath = fn[len(
'package://'):]
86 for rospath
in os.environ[
'ROS_PACKAGE_PATH'].split(
':'):
87 abspath = os.path.join(rospath, relpath)
88 if os.path.isfile(abspath):
90 raise ValueError(
"Could not find " + fn)
93 def get_transform(origin):
94 from pinocchio
import SE3, rpy
95 _xyz = [ float(v)
for v
in origin.attrib.get(
'xyz',
'0 0 0').split(
' ') ]
96 _rpy = [ float(v)
for v
in origin.attrib.get(
'rpy',
'0 0 0').split(
' ') ]
97 return SE3 (rpy.rpyToMatrix(*_rpy), np.array(_xyz))
99 def set_transform(origin, a, b):
100 from pinocchio
import rpy, Quaternion
101 length = np.linalg.norm(b-a)
103 R = Quaternion.FromTwoVectors(np.array([0, 0, 1]), z).matrix()
104 origin.attrib[
'xyz'] =
" ".join([str(v)
for v
in ((a+b)/2) ])
105 origin.attrib[
'rpy'] =
" ".join([str(v)
for v
in rpy.matrixToRpy(R) ])
107 from tqdm
import tqdm
108 for mesh
in tqdm(tree.xpath(
'/robot/link/collision/geometry/mesh'), desc=
"Generating capsules"):
109 geom = mesh.getparent()
110 coll = geom.getparent()
111 link = coll.getparent()
112 if coll.find(
'origin')
is None:
113 o = etree.Element(
"origin")
116 origin = coll.find(
'origin')
117 lMg = get_transform(origin)
119 meshfile = get_path(mesh.attrib[
'filename'])
121 name = os.path.basename(meshfile)
123 a, b, radius = approximate_mesh (meshfile, lMg)
124 length = np.linalg.norm(b-a)
126 set_transform(origin, a, b)
128 mesh.tag =
"cylinder" 129 mesh.attrib.pop(
'filename')
130 mesh.attrib[
'radius'] = str(radius)
131 mesh.attrib[
'length'] = str(length)
132 coll.attrib[
'name'] = name
134 if link.find(
'collision_checking')
is None:
135 link.append(etree.Element(
'collision_checking'))
136 collision_checking = link.find(
'collision_checking')
137 collision_checking.append(etree.Element(
'capsule'))
138 collision_checking[-1].attrib[
'name'] = name
142 if __name__ ==
"__main__":
152 pinocchio_model_dir = join(dirname(dirname(str(abspath(__file__)))),
"models")
153 urdf_filename = pinocchio_model_dir +
"models/example-robot-data/robots/ur_description/urdf/ur5_gripper.urdf" 154 parse_urdf(urdf_filename,
"ur5_gripper_with_capsules.urdf")
JointCollectionTpl const DataTpl< Scalar, Options, JointCollectionTpl > const Eigen::MatrixBase< Mat > & min
def capsule_volume(a, b, r)
def pca_approximation(vertices)
AD< Scalar > max(const AD< Scalar > &x, const AD< Scalar > &y)
def approximate_mesh(filename, lMg)
def parse_urdf(infile, outfile)
def distance_points_segment(p, a, b)
def capsule_approximation(vertices)