urdfeus 0.0.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- urdfeus/__init__.py +6 -0
- urdfeus/apps/__init__.py +0 -0
- urdfeus/apps/mesh2eus.py +31 -0
- urdfeus/apps/urdf2eus.py +34 -0
- urdfeus/common.py +23 -0
- urdfeus/mesh2eus.py +29 -0
- urdfeus/read_yaml.py +165 -0
- urdfeus/templates/__init__.py +9 -0
- urdfeus/templates/euscollada-robot.l +241 -0
- urdfeus/templates/urdf_template.py +23 -0
- urdfeus/urdf2eus.py +349 -0
- urdfeus-0.0.6.dist-info/LICENSE +19 -0
- urdfeus-0.0.6.dist-info/METADATA +25 -0
- urdfeus-0.0.6.dist-info/RECORD +17 -0
- urdfeus-0.0.6.dist-info/WHEEL +5 -0
- urdfeus-0.0.6.dist-info/entry_points.txt +3 -0
- urdfeus-0.0.6.dist-info/top_level.txt +1 -0
urdfeus/__init__.py
ADDED
urdfeus/apps/__init__.py
ADDED
|
File without changes
|
urdfeus/apps/mesh2eus.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
from urdfeus.mesh2eus import mesh2eus
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main():
|
|
9
|
+
parser = argparse.ArgumentParser(description='Convert mesh to Euslisp')
|
|
10
|
+
parser.add_argument('input_mesh_path', type=str,
|
|
11
|
+
help='Input mesh file path')
|
|
12
|
+
parser.add_argument('output_euslisp_path', type=str,
|
|
13
|
+
help='Output Euslisp path')
|
|
14
|
+
parser.add_argument(
|
|
15
|
+
'--simplify-vertex-clustering-voxel-size', '--voxel-size',
|
|
16
|
+
default=None,
|
|
17
|
+
type=float,
|
|
18
|
+
help='Specifies the voxel size for the simplify_vertex_clustering'
|
|
19
|
+
' function in open3d. When this value is provided, '
|
|
20
|
+
'it is used as the voxel size in the function to perform '
|
|
21
|
+
'mesh simplification. This process reduces the complexity'
|
|
22
|
+
' of the mesh by clustering vertices within the specified voxel size.')
|
|
23
|
+
args = parser.parse_args()
|
|
24
|
+
with open(args.output_euslisp_path, 'w') as f:
|
|
25
|
+
mesh2eus(args.input_mesh_path,
|
|
26
|
+
args.simplify_vertex_clustering_voxel_size,
|
|
27
|
+
fp=f)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
if __name__ == '__main__':
|
|
31
|
+
main()
|
urdfeus/apps/urdf2eus.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
|
|
5
|
+
from urdfeus.urdf2eus import urdf2eus
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main():
|
|
9
|
+
parser = argparse.ArgumentParser(description='Convert URDF to Euslisp')
|
|
10
|
+
parser.add_argument('input_urdf_path', type=str, help='Input URDF path')
|
|
11
|
+
parser.add_argument('output_euslisp_path', type=str,
|
|
12
|
+
help='Output Euslisp path')
|
|
13
|
+
parser.add_argument('--yaml-path', type=str,
|
|
14
|
+
default=None,
|
|
15
|
+
help='Config yaml path')
|
|
16
|
+
parser.add_argument(
|
|
17
|
+
'--simplify-vertex-clustering-voxel-size', '--voxel-size',
|
|
18
|
+
default=None,
|
|
19
|
+
type=float,
|
|
20
|
+
help='Specifies the voxel size for the simplify_vertex_clustering'
|
|
21
|
+
' function in open3d. When this value is provided, '
|
|
22
|
+
'it is used as the voxel size in the function to perform '
|
|
23
|
+
'mesh simplification. This process reduces the complexity'
|
|
24
|
+
' of the mesh by clustering vertices within the specified voxel size.')
|
|
25
|
+
args = parser.parse_args()
|
|
26
|
+
with open(args.output_euslisp_path, 'w') as f:
|
|
27
|
+
urdf2eus(args.input_urdf_path,
|
|
28
|
+
args.yaml_path,
|
|
29
|
+
args.simplify_vertex_clustering_voxel_size,
|
|
30
|
+
fp=f)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
if __name__ == '__main__':
|
|
34
|
+
main()
|
urdfeus/common.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from skrobot.model import FixedJoint
|
|
2
|
+
from skrobot.model import Joint
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
meter2millimeter = 1000.0
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def is_linear_joint(joint: Joint) -> bool:
|
|
9
|
+
return joint.__class__.__name__ == 'LinearJoint'
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def is_fixed_joint(joint: Joint) -> bool:
|
|
13
|
+
return joint.__class__.__name__ == 'FixedJoint'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def collect_all_joints_of_robot(robot):
|
|
17
|
+
"""Collects and returns all joints of the robot, including fixed joints.
|
|
18
|
+
|
|
19
|
+
"""
|
|
20
|
+
all_fixed_joints = [value for _, value in robot.__dict__.items()
|
|
21
|
+
if isinstance(value, FixedJoint)]
|
|
22
|
+
all_joints = robot.joint_list + all_fixed_joints
|
|
23
|
+
return all_joints
|
urdfeus/mesh2eus.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import os.path as osp
|
|
2
|
+
import sys
|
|
3
|
+
import tempfile
|
|
4
|
+
|
|
5
|
+
from urdfeus.templates.urdf_template import urdf_template
|
|
6
|
+
from urdfeus.urdf2eus import urdf2eus
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def mesh2eus(mesh_path, simplify_vertex_clustering_voxel_size=None,
|
|
10
|
+
fp=sys.stdout, mesh_name=None):
|
|
11
|
+
if mesh_name is None:
|
|
12
|
+
mesh_name, _ = osp.splitext(osp.basename(mesh_path))
|
|
13
|
+
collision_mesh_filepath = osp.abspath(mesh_path)
|
|
14
|
+
visual_mesh_filepath = osp.abspath(mesh_path)
|
|
15
|
+
|
|
16
|
+
formatted_urdf = urdf_template.format(
|
|
17
|
+
mesh_name=mesh_name,
|
|
18
|
+
collision_mesh_filepath=collision_mesh_filepath,
|
|
19
|
+
visual_mesh_filepath=visual_mesh_filepath
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
with tempfile.NamedTemporaryFile(delete=True) as temp:
|
|
23
|
+
temp_urdf_path = temp.name
|
|
24
|
+
temp.write(formatted_urdf.encode('utf-8'))
|
|
25
|
+
temp.seek(0)
|
|
26
|
+
voxel_size = simplify_vertex_clustering_voxel_size
|
|
27
|
+
urdf2eus(temp_urdf_path,
|
|
28
|
+
simplify_vertex_clustering_voxel_size=voxel_size,
|
|
29
|
+
fp=fp)
|
urdfeus/read_yaml.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
import yaml
|
|
4
|
+
|
|
5
|
+
from urdfeus.common import meter2millimeter
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def read_config_from_yaml(
|
|
9
|
+
robot, config_file,
|
|
10
|
+
fp=sys.stdout, add_link_suffix=True, add_joint_suffix=True):
|
|
11
|
+
print('\n', end='', file=fp)
|
|
12
|
+
with open(config_file, 'r') as file:
|
|
13
|
+
doc = yaml.load(file, Loader=yaml.FullLoader)
|
|
14
|
+
|
|
15
|
+
for limb in [k for k in doc.keys() if k.endswith('-end-coords')]:
|
|
16
|
+
suffix_to_remove = '-end-coords'
|
|
17
|
+
limb_name = limb[:-len(suffix_to_remove)]
|
|
18
|
+
end_coords_parent_name = doc[f"{limb_name}-end-coords"]["parent"]
|
|
19
|
+
|
|
20
|
+
if add_link_suffix:
|
|
21
|
+
print(f" (setq {limb_name}-end-coords (make-cascoords :coords (send {end_coords_parent_name}_lk :copy-worldcoords) :name :{limb_name}-end-coords))", file=fp) # NOQA
|
|
22
|
+
else:
|
|
23
|
+
print(f" (setq {limb_name}-end-coords (make-cascoords :coords (send {end_coords_parent_name} :copy-worldcoords) :name {limb_name}-end-coords))", file=fp) # NOQA
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
n = doc[f"{limb_name}-end-coords"]["translate"]
|
|
27
|
+
values = [meter2millimeter * val for val in n[:3]]
|
|
28
|
+
print(f" (send {limb_name}-end-coords :translate (float-vector {' '.join(map(str, values))}))", file=fp) # NOQA
|
|
29
|
+
except Exception as _: # NOQA
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
n = doc[f"{limb_name}-end-coords"]["rotate"]
|
|
34
|
+
if n:
|
|
35
|
+
values = [val for val in n[:3]]
|
|
36
|
+
rotation_value = (3.141592653589793/180) * n[3]
|
|
37
|
+
print(f" (send {limb_name}-end-coords :rotate {rotation_value} (float-vector {' '.join(map(str, values))}))", file=fp) # NOQA
|
|
38
|
+
except Exception as _: # NOQA
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
if add_link_suffix:
|
|
42
|
+
print(f" (send {end_coords_parent_name}_lk :assoc {limb_name}-end-coords)", file=fp) # NOQA
|
|
43
|
+
else:
|
|
44
|
+
print(f" (send {end_coords_parent_name} :assoc {limb_name}-end-coords)", file=fp) # NOQA
|
|
45
|
+
|
|
46
|
+
print("", file=fp)
|
|
47
|
+
print(" ;; limbs", file=fp)
|
|
48
|
+
|
|
49
|
+
limb_candidates = [k for k in doc.keys()
|
|
50
|
+
if not k.endswith('-coords')
|
|
51
|
+
and not k.endswith('-vector')]
|
|
52
|
+
limb_order = [(limb, idx) for idx, limb in enumerate(limb_candidates)]
|
|
53
|
+
limb_order.sort(key=lambda x: x[1])
|
|
54
|
+
|
|
55
|
+
limbs = []
|
|
56
|
+
for limb, _ in limb_order:
|
|
57
|
+
limb_name = limb
|
|
58
|
+
tmp_link_names = []
|
|
59
|
+
tmp_joint_names = []
|
|
60
|
+
try:
|
|
61
|
+
limb_doc = doc[limb_name]
|
|
62
|
+
except Exception as _: # NOQA
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
for item in limb_doc:
|
|
66
|
+
for key, value in item.items():
|
|
67
|
+
if key in robot.__dict__:
|
|
68
|
+
joint = robot.__dict__[key]
|
|
69
|
+
tmp_joint_names.append(key)
|
|
70
|
+
tmp_link_names.append(joint.child_link.name)
|
|
71
|
+
if tmp_link_names:
|
|
72
|
+
print(f" (setq {limb_name} (list", end="", file=fp)
|
|
73
|
+
if add_link_suffix:
|
|
74
|
+
for link in tmp_link_names:
|
|
75
|
+
print(f" {link}_lk", end="", file=fp)
|
|
76
|
+
else:
|
|
77
|
+
for link in tmp_link_names:
|
|
78
|
+
print(f" {link}", end="", file=fp)
|
|
79
|
+
print("))", file=fp)
|
|
80
|
+
print("", file=fp)
|
|
81
|
+
|
|
82
|
+
print(f" (setq {limb_name}-root-link", file=fp)
|
|
83
|
+
print(f" (labels ((find-parent (l) (if (find (send l :parent) {limb_name}) (find-parent (send l :parent)) l)))", file=fp) # NOQA
|
|
84
|
+
print(f" (find-parent (car {limb_name}))))", file=fp)
|
|
85
|
+
limbs.append((limb, (tmp_link_names, tmp_joint_names)))
|
|
86
|
+
print("", file=fp)
|
|
87
|
+
print(" ;; links", file=fp)
|
|
88
|
+
if add_link_suffix:
|
|
89
|
+
print(f" (setq links (list {robot.__dict__['root_link'].name}_lk", end="", file=fp) # NOQA
|
|
90
|
+
else:
|
|
91
|
+
print(f" (setq links (list {robot.__dict__['root_link'].name}", end="", file=fp) # NOQA
|
|
92
|
+
|
|
93
|
+
for limb, (link_names, joint_names) in limbs:
|
|
94
|
+
if add_link_suffix:
|
|
95
|
+
for link in link_names:
|
|
96
|
+
print(f" {link}_lk", end="", file=fp)
|
|
97
|
+
else:
|
|
98
|
+
for link in link_names:
|
|
99
|
+
print(f" {link}", end="", file=fp)
|
|
100
|
+
|
|
101
|
+
print("))", file=fp)
|
|
102
|
+
print("", file=fp)
|
|
103
|
+
print(" ;; joint-list", file=fp)
|
|
104
|
+
print(" (setq joint-list (list", end="", file=fp)
|
|
105
|
+
for limb, (link_names, joint_names) in limbs:
|
|
106
|
+
if add_joint_suffix:
|
|
107
|
+
for joint in joint_names:
|
|
108
|
+
print(f" {joint}_jt", end="", file=fp)
|
|
109
|
+
else:
|
|
110
|
+
for joint in joint_names:
|
|
111
|
+
print(f" {joint}", end="", file=fp)
|
|
112
|
+
print("))", file=fp)
|
|
113
|
+
print("", file=fp)
|
|
114
|
+
|
|
115
|
+
print(" ;; init-ending\n", file=fp)
|
|
116
|
+
print(" (send self :init-ending) ;; :urdf\n", file=fp)
|
|
117
|
+
print(" ;; overwrite bodies to return draw-things links not (send link :bodies)\n", file=fp) # NOQA
|
|
118
|
+
print(" (setq bodies (flatten (mapcar #'(lambda (b) (if (find-method b :bodies) (send b :bodies))) (list", end="", file=fp) # NOQA
|
|
119
|
+
for link in robot.link_list:
|
|
120
|
+
if add_link_suffix:
|
|
121
|
+
print(f" {link.name}_lk", end="", file=fp)
|
|
122
|
+
else:
|
|
123
|
+
print(f" {link.name}", end="", file=fp)
|
|
124
|
+
print("))))\n", file=fp)
|
|
125
|
+
|
|
126
|
+
print(" (when (member :reset-pose (send self :methods))", file=fp)
|
|
127
|
+
print(" (send self :reset-pose)) ;; :set reset-pose\n", file=fp)
|
|
128
|
+
print(" self)) ;; end of :init", file=fp)
|
|
129
|
+
|
|
130
|
+
if 'angle-vector' in doc:
|
|
131
|
+
n = doc['angle-vector']
|
|
132
|
+
if len(n) > 0:
|
|
133
|
+
print(" ;; pre-defined pose methods\n", file=fp)
|
|
134
|
+
|
|
135
|
+
for name, v in n.items():
|
|
136
|
+
limbs_symbols = " ".join([f":{limb[0]}" for limb in limbs])
|
|
137
|
+
print(f"\n (:{name} (&optional (limbs '({limbs_symbols})))\n",
|
|
138
|
+
file=fp)
|
|
139
|
+
print(f" \"Predefined pose named {name}.\"\n", file=fp)
|
|
140
|
+
print(" (unless (listp limbs) (setq limbs (list limbs)))\n",
|
|
141
|
+
file=fp)
|
|
142
|
+
print(" (dolist (limb limbs)\n", file=fp)
|
|
143
|
+
print(" (case limb", file=fp)
|
|
144
|
+
|
|
145
|
+
i_joint = 0
|
|
146
|
+
for limb in limbs:
|
|
147
|
+
limb_name = limb[0]
|
|
148
|
+
print(f"\n (:{limb_name} (send self limb :angle-vector (float-vector", file=fp) # NOQA
|
|
149
|
+
joint_names = limb[1][1]
|
|
150
|
+
|
|
151
|
+
for j in range(len(joint_names)):
|
|
152
|
+
try:
|
|
153
|
+
angle_value = v[i_joint]
|
|
154
|
+
print(f" {angle_value}", file=fp)
|
|
155
|
+
i_joint += 1
|
|
156
|
+
except IndexError as e: # NOQA
|
|
157
|
+
sys.stderr.write("****** Angle-vector may be shorter than joint-list, please fix .yaml ******\n") # NOQA
|
|
158
|
+
while j < len(joint_names):
|
|
159
|
+
print(" 0.0", file=fp) # padding dummy
|
|
160
|
+
j += 1
|
|
161
|
+
|
|
162
|
+
print(")))", file=fp)
|
|
163
|
+
|
|
164
|
+
print("\n (t (format t \"Unknown limb is passed: ~a~%\" limb))", file=fp) # NOQA
|
|
165
|
+
print("))\n (send self :angle-vector))", file=fp)
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
;;
|
|
2
|
+
;; copy euscollada-robot class definition from euscollada/src/euscollada-robot.l
|
|
3
|
+
;;
|
|
4
|
+
(defclass euscollada-robot
|
|
5
|
+
;; This euscollada-robot class is for robots converted from collada files.
|
|
6
|
+
;; This class provides :init-ending override.
|
|
7
|
+
:super robot-model
|
|
8
|
+
:slots ())
|
|
9
|
+
|
|
10
|
+
(defmethod euscollada-robot
|
|
11
|
+
(:init-ending
|
|
12
|
+
(&optional (type :urdf))
|
|
13
|
+
(when (eq type :collada)
|
|
14
|
+
;; fix all links' mass properties ;; root link relative (collada) -> link local (euslisp)
|
|
15
|
+
(dolist (l (append links
|
|
16
|
+
(mapcan #'(lambda (x) (if (and (derivedp (cdr x) bodyset-link)
|
|
17
|
+
(not (memq (cdr x) links)))
|
|
18
|
+
(list (cdr x)))) (send self :slots))))
|
|
19
|
+
(unless (= (send l :weight) 0.0)
|
|
20
|
+
(setq (l . acentroid) (send l :inverse-transform-vector
|
|
21
|
+
(send (send (car links) :worldcoords) :transform-vector
|
|
22
|
+
(l . acentroid))))
|
|
23
|
+
(setq (l . inertia-tensor) (m* (transpose (send l :worldrot))
|
|
24
|
+
(m* (send (car links) :worldrot)
|
|
25
|
+
(l . inertia-tensor)))))))
|
|
26
|
+
(send-super :init-ending)
|
|
27
|
+
(send self :make-collision-model-for-links)
|
|
28
|
+
;;
|
|
29
|
+
(dolist (j (mapcan #'(lambda (x) (if (and (derivedp (cdr x) joint)
|
|
30
|
+
(not (memq (cdr x) (send self :joint-list))))
|
|
31
|
+
(list (cdr x)))) (send self :slots)))
|
|
32
|
+
(send (send j :child-link) :add-joint j)
|
|
33
|
+
(send (send j :child-link) :add-parent-link (send j :parent-link))
|
|
34
|
+
(send (send j :parent-link) :add-child-links (send j :child-link))))
|
|
35
|
+
(:change-visual
|
|
36
|
+
(&optional (visual :convex))
|
|
37
|
+
(dolist (lk (send self :links))
|
|
38
|
+
(dolist (bd (send lk :bodies))
|
|
39
|
+
(when (derivedp bd collada-body)
|
|
40
|
+
(send bd :change-visual visual)))))
|
|
41
|
+
;; fullbody-inverse-kinematics overwrite
|
|
42
|
+
;; reduce root-link's weight based on leg's joint limit
|
|
43
|
+
;; increase stop and cog-gain
|
|
44
|
+
(:fullbody-inverse-kinematics
|
|
45
|
+
(target-coords &rest args &key (stop 250) (cog-gain 2.0) (additional-weight-list) (use-6dof-joint-leg-gain nil) &allow-other-keys)
|
|
46
|
+
(let* ((leg-ul (send self :calc-union-link-list (send self :legs :links))))
|
|
47
|
+
(send self :reset-joint-angle-limit-weight-old leg-ul)
|
|
48
|
+
(send-message* self robot-model :fullbody-inverse-kinematics
|
|
49
|
+
target-coords
|
|
50
|
+
:stop stop :cog-gain cog-gain
|
|
51
|
+
:additional-weight-list
|
|
52
|
+
(append
|
|
53
|
+
additional-weight-list
|
|
54
|
+
(if use-6dof-joint-leg-gain
|
|
55
|
+
(list
|
|
56
|
+
(list (car (send self :links))
|
|
57
|
+
#'(lambda ()
|
|
58
|
+
;; set root-link 6dof-joint's weight based on legs' joint limit
|
|
59
|
+
(let* ((min-weight
|
|
60
|
+
(reduce #'(lambda (x y) (min x y))
|
|
61
|
+
(coerce (send self :calc-inverse-kinematics-weight-from-link-list
|
|
62
|
+
leg-ul :union-link-list leg-ul) cons))))
|
|
63
|
+
(fill (instantiate float-vector 6) min-weight)))))))
|
|
64
|
+
args)))
|
|
65
|
+
;; make collision model from faces or gl-vertices
|
|
66
|
+
(:make-collision-model-for-links
|
|
67
|
+
(&key (fat 0) (collision-func 'pqp-collision-check) ((:links ls) (send self :links)))
|
|
68
|
+
(dolist (ll ls)
|
|
69
|
+
(let (fs glv usefs)
|
|
70
|
+
(dolist (bd (send ll :bodies))
|
|
71
|
+
(if (derivedp bd collada-body)
|
|
72
|
+
(push (send bd :glvertices) glv)
|
|
73
|
+
(push (send bd :faces) fs)))
|
|
74
|
+
(setq fs (flatten fs))
|
|
75
|
+
(cond
|
|
76
|
+
((and (not fs) glv) ;; if there is no faces, use glvertices for creating pqpmodel
|
|
77
|
+
(setq usefs (instance gl::glvertices :init nil))
|
|
78
|
+
(send usefs :transform (send ll :worldcoords))
|
|
79
|
+
(send usefs :append-glvertices glv)
|
|
80
|
+
(let ((m (send usefs (read-from-string
|
|
81
|
+
(format nil ":make-~Amodel"
|
|
82
|
+
(string-right-trim "-COLLISION-CHECK" (string collision-func))))
|
|
83
|
+
:fat fat)))
|
|
84
|
+
(setf (get ll :pqpmodel) m)))
|
|
85
|
+
(fs
|
|
86
|
+
(setq usefs
|
|
87
|
+
(append fs
|
|
88
|
+
(mapcar #'(lambda (gv) (send gv :convert-to-faces :wrt :world)) glv)))
|
|
89
|
+
(send ll
|
|
90
|
+
(read-from-string
|
|
91
|
+
(format nil ":make-~Amodel"
|
|
92
|
+
(string-right-trim "-COLLISION-CHECK" (string collision-func))))
|
|
93
|
+
:fat fat
|
|
94
|
+
:faces usefs)))))))
|
|
95
|
+
|
|
96
|
+
;; copy euscollada-body class definition from euscollada/src/euscollada-robot.l
|
|
97
|
+
;; This euscollada-body class is for bodies in robot model converted from collada files.
|
|
98
|
+
(defclass collada-body
|
|
99
|
+
:super gl::glbody
|
|
100
|
+
:slots (glvertices) ;; glvertices slot for backward compatibility
|
|
101
|
+
)
|
|
102
|
+
(defmethod collada-body
|
|
103
|
+
(:init (&key (name) (replace-obj))
|
|
104
|
+
(if replace-obj
|
|
105
|
+
(replace-object self replace-obj)
|
|
106
|
+
(replace-object self (make-cube 10 10 10)))
|
|
107
|
+
(if name (send self :name name))
|
|
108
|
+
(setq glvertices gl::aglvertices)
|
|
109
|
+
self)
|
|
110
|
+
(:change-visual
|
|
111
|
+
(&optional (visual :convex))
|
|
112
|
+
(case visual
|
|
113
|
+
((list :convex :hull :convex-hull)
|
|
114
|
+
(unless (send self :get :original-mesh)
|
|
115
|
+
(send self :put :original-mesh gl::aglvertices)) ;; store original mesh
|
|
116
|
+
(let* ((org-mesh (send self :get :original-mesh))
|
|
117
|
+
(org-cds (send org-mesh :copy-worldcoords))
|
|
118
|
+
(glv (gl::make-glvertices-from-faces (send self :faces))))
|
|
119
|
+
(send glv :set-offset (send org-cds :inverse-transformation))
|
|
120
|
+
(send glv :transform org-cds)
|
|
121
|
+
(send org-mesh :assoc glv)
|
|
122
|
+
(setq gl::aglvertices glv)
|
|
123
|
+
glv))
|
|
124
|
+
((list :original :mesh :glvertices :original-mesh)
|
|
125
|
+
(let ((org-mesh (send self :get :original-mesh)))
|
|
126
|
+
(when org-mesh
|
|
127
|
+
(dolist (d (send org-mesh :descendants)) ;; dissoc all discendants
|
|
128
|
+
(send org-mesh :dissoc d))
|
|
129
|
+
(setq gl::aglvertices org-mesh)
|
|
130
|
+
org-mesh))))))
|
|
131
|
+
|
|
132
|
+
;; copy mimic-joint class definition from euscollada/src/euscollada-robot.l
|
|
133
|
+
;; This mimic-joint class is for mimic-joints in URDF file
|
|
134
|
+
(defclass mimic-joint-param
|
|
135
|
+
:super propertied-object
|
|
136
|
+
:slots (joint multiplier offset))
|
|
137
|
+
(defmethod mimic-joint-param
|
|
138
|
+
(:init (j &key ((:multiplier m) 1) ((:offset o) 0))
|
|
139
|
+
(setq joint j multiplier m offset o)
|
|
140
|
+
self)
|
|
141
|
+
(:joint (&rest args) (forward-message-to joint args))
|
|
142
|
+
(:multiplier (&rest args) (forward-message-to multiplier args))
|
|
143
|
+
(:offset (&rest args) (forward-message-to offset args)))
|
|
144
|
+
|
|
145
|
+
(defun calc-jacobian-mimic
|
|
146
|
+
(mimic-joints
|
|
147
|
+
fik row column joint paxis child-link world-default-coords child-reverse
|
|
148
|
+
move-target transform-coords rotation-axis translation-axis
|
|
149
|
+
tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33)
|
|
150
|
+
(let* ((fik-tmp (copy-object fik))
|
|
151
|
+
(dim (* 6 (if (atom rotation-axis) 1 (length rotation-axis)))))
|
|
152
|
+
(dolist (axis (append (if (atom translation-axis)
|
|
153
|
+
(list translation-axis) translation-axis)
|
|
154
|
+
(if (atom rotation-axis)
|
|
155
|
+
(list rotation-axis) rotation-axis)))
|
|
156
|
+
(case axis
|
|
157
|
+
((:x :y :z :xx :yy :zz) (decf dim 1))
|
|
158
|
+
((:xy :yx :yz :zy :zx :xz) (decf dim 2))
|
|
159
|
+
(nil (decf dim 3))))
|
|
160
|
+
;;
|
|
161
|
+
(dolist (mj mimic-joints)
|
|
162
|
+
(let* ((j (send mj :joint))
|
|
163
|
+
(paxis (case (j . axis)
|
|
164
|
+
(:x #f(1 0 0)) (:y #f(0 1 0)) (:z #f(0 0 1))
|
|
165
|
+
(:xx #f(1 0 0)) (:yy #f(0 1 0)) (:zz #f(0 0 1))
|
|
166
|
+
(:-x #f(-1 0 0)) (:-y #f(0 -1 0)) (:-z #f(0 0 -1))
|
|
167
|
+
(t (j . axis))))
|
|
168
|
+
(child-link (send j :child-link))
|
|
169
|
+
(parent-link (send j :parent-link))
|
|
170
|
+
(default-coords (j . default-coords))
|
|
171
|
+
(world-default-coords (send (send parent-link :copy-worldcoords)
|
|
172
|
+
:transform default-coords)))
|
|
173
|
+
(fill (array-entity fik-tmp) 0)
|
|
174
|
+
(send j :calc-jacobian
|
|
175
|
+
fik-tmp row column j paxis child-link world-default-coords child-reverse
|
|
176
|
+
move-target transform-coords rotation-axis translation-axis
|
|
177
|
+
tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33)
|
|
178
|
+
;;
|
|
179
|
+
(dotimes (i dim)
|
|
180
|
+
(setf (aref fik (+ i row) column)
|
|
181
|
+
(+ (aref fik (+ i row) column)
|
|
182
|
+
(* (send mj :multiplier) (aref fik-tmp (+ i row) column)))))))
|
|
183
|
+
fik))
|
|
184
|
+
|
|
185
|
+
(defclass rotational-mimic-joint
|
|
186
|
+
:super rotational-joint
|
|
187
|
+
:slots (mimic-joints))
|
|
188
|
+
(defmethod rotational-mimic-joint
|
|
189
|
+
(:init (&rest args &key ((:mimic-joints mjs)) &allow-other-keys)
|
|
190
|
+
(send-super* :init args)
|
|
191
|
+
(setq mimic-joints mjs)
|
|
192
|
+
(dolist (j mimic-joints)
|
|
193
|
+
(send (send j :joint :child-link) :rotate (send j :offset) ((send j :joint) . axis))
|
|
194
|
+
(setq ((send j :joint) . default-coords) (send j :joint :child-link :copy-coords)))
|
|
195
|
+
self)
|
|
196
|
+
(:joint-angle (&rest args)
|
|
197
|
+
(prog1
|
|
198
|
+
(send-super* :joint-angle args)
|
|
199
|
+
(dolist (j mimic-joints)
|
|
200
|
+
(send j :joint :joint-angle (* joint-angle (send j :multiplier))))))
|
|
201
|
+
(:calc-jacobian (fik row column joint paxis child-link world-default-coords child-reverse
|
|
202
|
+
move-target transform-coords rotation-axis translation-axis
|
|
203
|
+
tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33)
|
|
204
|
+
(calc-jacobian-rotational fik row column joint paxis child-link world-default-coords child-reverse
|
|
205
|
+
move-target transform-coords rotation-axis translation-axis
|
|
206
|
+
tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33)
|
|
207
|
+
(calc-jacobian-mimic mimic-joints
|
|
208
|
+
fik row column joint paxis child-link world-default-coords child-reverse
|
|
209
|
+
move-target transform-coords rotation-axis translation-axis
|
|
210
|
+
tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33)))
|
|
211
|
+
|
|
212
|
+
(defclass linear-mimic-joint
|
|
213
|
+
:super linear-joint
|
|
214
|
+
:slots (mimic-joints))
|
|
215
|
+
(defmethod linear-mimic-joint
|
|
216
|
+
(:init (&rest args &key ((:mimic-joints mjs)) &allow-other-keys)
|
|
217
|
+
(send-super* :init args)
|
|
218
|
+
(setq mimic-joints mjs)
|
|
219
|
+
(dolist (j mimic-joints)
|
|
220
|
+
(send (send j :joint :child-link) :translate (scale (* 1000 (send j :offset)) ((send j :joint) . axis)))
|
|
221
|
+
(setq ((send j :joint) . default-coords) (send j :joint :child-link :copy-coords)))
|
|
222
|
+
self)
|
|
223
|
+
(:joint-angle (&rest args)
|
|
224
|
+
(prog1
|
|
225
|
+
(send-super* :joint-angle args)
|
|
226
|
+
(dolist (j mimic-joints)
|
|
227
|
+
(send j :joint :joint-angle (* joint-angle (send j :multiplier))))))
|
|
228
|
+
(:calc-jacobian (fik row column joint paxis child-link world-default-coords child-reverse
|
|
229
|
+
move-target transform-coords rotation-axis translation-axis
|
|
230
|
+
tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33)
|
|
231
|
+
(calc-jacobian-linear fik row column joint paxis child-link world-default-coords child-reverse
|
|
232
|
+
move-target transform-coords rotation-axis translation-axis
|
|
233
|
+
tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33)
|
|
234
|
+
(calc-jacobian-mimic mimic-joints
|
|
235
|
+
fik row column joint paxis child-link world-default-coords child-reverse
|
|
236
|
+
move-target transform-coords rotation-axis translation-axis
|
|
237
|
+
tmp-v0 tmp-v1 tmp-v2 tmp-v3 tmp-v3a tmp-v3b tmp-m33)))
|
|
238
|
+
|
|
239
|
+
;;
|
|
240
|
+
;; end of copy from jsk_model_tools/euscollada/src/euscollada-robot.l
|
|
241
|
+
;;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
urdf_template = """<?xml version="1.0" ?>
|
|
2
|
+
<robot name="{mesh_name}">
|
|
3
|
+
<link name="link0">
|
|
4
|
+
<inertial>
|
|
5
|
+
<origin rpy="0 0 0" xyz="0 0 0" />
|
|
6
|
+
<mass value="1.0" />
|
|
7
|
+
<inertia ixx="1.00E+00" ixy="0.00E+00" ixz="0.00E+00" iyy="1.00E+00" iyz="0.00E+00" izz="1.00E+00" />
|
|
8
|
+
</inertial>
|
|
9
|
+
<collision>
|
|
10
|
+
<origin rpy="0 0 0" xyz="0 0 0" />
|
|
11
|
+
<geometry>
|
|
12
|
+
<mesh filename="{collision_mesh_filepath}" scale="1 1 1" />
|
|
13
|
+
</geometry>
|
|
14
|
+
</collision>
|
|
15
|
+
<visual>
|
|
16
|
+
<origin rpy="0 0 0" xyz="0 0 0" />
|
|
17
|
+
<geometry>
|
|
18
|
+
<mesh filename="{visual_mesh_filepath}" scale="1 1 1" />
|
|
19
|
+
</geometry>
|
|
20
|
+
</visual>
|
|
21
|
+
</link>
|
|
22
|
+
</robot>
|
|
23
|
+
""" # NOQA
|
urdfeus/urdf2eus.py
ADDED
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import platform
|
|
3
|
+
import socket
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from skrobot.model import Link
|
|
8
|
+
from skrobot.model import RobotModel
|
|
9
|
+
from skrobot.utils.mesh import simplify_vertex_clustering
|
|
10
|
+
from skrobot.utils.mesh import split_mesh_by_face_color
|
|
11
|
+
import trimesh
|
|
12
|
+
|
|
13
|
+
from urdfeus.common import collect_all_joints_of_robot
|
|
14
|
+
from urdfeus.common import is_fixed_joint
|
|
15
|
+
from urdfeus.common import is_linear_joint
|
|
16
|
+
from urdfeus.common import meter2millimeter
|
|
17
|
+
from urdfeus.read_yaml import read_config_from_yaml
|
|
18
|
+
from urdfeus.templates import get_euscollada_string
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def print_link(link: Link, simplify_vertex_clustering_voxel_size=None,
|
|
22
|
+
add_link_suffix: bool = True, fp=sys.stdout):
|
|
23
|
+
if add_link_suffix:
|
|
24
|
+
link_name = link.name + "_lk"
|
|
25
|
+
else:
|
|
26
|
+
link_name = link.name
|
|
27
|
+
print(f" ;; link: {link_name}", file=fp)
|
|
28
|
+
print(" (let ((geom-lst (list ", end='', file=fp)
|
|
29
|
+
|
|
30
|
+
geom_counter = 0
|
|
31
|
+
if link.visual_mesh is not None and len(link.visual_mesh) > 0:
|
|
32
|
+
print(f"(send self :_make_instance_{link.name}_geom{geom_counter})", end='', file=fp) # NOQA
|
|
33
|
+
geom_counter += 1
|
|
34
|
+
|
|
35
|
+
print(")))", file=fp)
|
|
36
|
+
print(" (dolist (g (cdr geom-lst)) (send (car geom-lst) :assoc g))", file=fp) # NOQA
|
|
37
|
+
print(f" (setq {link_name}", file=fp)
|
|
38
|
+
print(" (instance bodyset-link", file=fp)
|
|
39
|
+
print(" :init (make-cascoords)", file=fp)
|
|
40
|
+
print(f" :bodies geom-lst", file=fp) # NOQA
|
|
41
|
+
print(f" :name \"{link.name}\"))", file=fp)
|
|
42
|
+
print(f" (progn (send {link_name} :weight 0.0) (setq ({link_name} . acentroid) (float-vector 0 0 0)) (send {link_name} :inertia-tensor #2f((0 0 0)(0 0 0)(0 0 0))))", file=fp) # NOQA
|
|
43
|
+
|
|
44
|
+
print(f" ;; global coordinates for {link_name}", file=fp)
|
|
45
|
+
print(" (let ((world-cds (make-coords :pos ", end="", file=fp)
|
|
46
|
+
x, y, z = meter2millimeter * link.worldpos()
|
|
47
|
+
print(f"(float-vector {x:.6f} {y:.6f} {z:.6f})", end="", file=fp)
|
|
48
|
+
|
|
49
|
+
qw, qx, qy, qz = link.copy_worldcoords().quaternion
|
|
50
|
+
print(f"\n :rot (quaternion2matrix (float-vector {qw:.6f} {qx:.6f} {qy:.6f} {qz:.6f}))", end="", file=fp) # NOQA
|
|
51
|
+
print(")))\n", end='', file=fp)
|
|
52
|
+
print(f" (send {link_name} :transform world-cds)))", file=fp) # NOQA
|
|
53
|
+
print("\n", end='', file=fp)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def print_joint(joint, add_joint_suffix=True, add_link_suffix=True,
|
|
57
|
+
fp=sys.stdout):
|
|
58
|
+
linear = is_linear_joint(joint)
|
|
59
|
+
|
|
60
|
+
joint_name = joint.name
|
|
61
|
+
if add_joint_suffix:
|
|
62
|
+
if is_fixed_joint(joint):
|
|
63
|
+
joint_name += "_fixed_jt"
|
|
64
|
+
else:
|
|
65
|
+
joint_name += "_jt"
|
|
66
|
+
|
|
67
|
+
print("\n", end='', file=fp)
|
|
68
|
+
print(f" ;; joint: {joint_name}", file=fp)
|
|
69
|
+
print(f" (setq {joint_name}", file=fp)
|
|
70
|
+
print(f" (instance {'linear-joint' if linear else 'rotational-joint'} :init", file=fp) # NOQA
|
|
71
|
+
print(f" :name \"{joint.name}\"", file=fp)
|
|
72
|
+
if add_link_suffix:
|
|
73
|
+
print(f" :parent-link {joint.parent_link.name}_lk :child-link {joint.child_link.name}_lk", file=fp) # NOQA
|
|
74
|
+
else:
|
|
75
|
+
print(f" :parent-link {joint.parent_link.name} :child-link {joint.child_link.name}", file=fp) # NOQA
|
|
76
|
+
|
|
77
|
+
x, y, z = joint.axis
|
|
78
|
+
if x == 0.0 and y == 0.0 and z == 0.0:
|
|
79
|
+
print(" :axis (float-vector 1 1 1) ;; fixed joint??", file=fp) # NOQA
|
|
80
|
+
else:
|
|
81
|
+
print(f" :axis (float-vector {x:.16f} {y:.16f} {z:.16f})", file=fp) # NOQA
|
|
82
|
+
|
|
83
|
+
min_val = joint.min_angle
|
|
84
|
+
max_val = joint.max_angle
|
|
85
|
+
print(" ", end="", file=fp)
|
|
86
|
+
if np.isinf(min_val) or np.isinf(max_val):
|
|
87
|
+
print(":min *-inf* :max *inf*", file=fp)
|
|
88
|
+
else:
|
|
89
|
+
if linear:
|
|
90
|
+
min_angle = meter2millimeter * min_val
|
|
91
|
+
max_angle = meter2millimeter * max_val
|
|
92
|
+
else:
|
|
93
|
+
min_angle = np.rad2deg(min_val)
|
|
94
|
+
max_angle = np.rad2deg(max_val)
|
|
95
|
+
min_str = "*-inf*" if min_val == -float('inf') else str(min_angle)
|
|
96
|
+
max_str = "*inf*" if max_val == float('inf') else str(max_angle)
|
|
97
|
+
print(f":min {min_str} :max {max_str}", file=fp)
|
|
98
|
+
print(f" :max-joint-velocity {joint.max_joint_velocity}", file=fp) # NOQA
|
|
99
|
+
print(f" :max-joint-torque {joint.joint_torque}", end='', file=fp) # NOQA
|
|
100
|
+
print("))", file=fp)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def print_mimic_joints(robot, fp=sys.stdout):
|
|
104
|
+
print("\n ;; mimic joint re-definition\n", file=fp)
|
|
105
|
+
mimic_joint_list = {}
|
|
106
|
+
|
|
107
|
+
for j in robot.urdf_robot_model.joints:
|
|
108
|
+
if j.mimic is None:
|
|
109
|
+
continue
|
|
110
|
+
joint_a = robot.__dict__[j.mimic.joint]
|
|
111
|
+
joint_b = robot.__dict__[j.name]
|
|
112
|
+
multiplier = j.mimic.multiplier
|
|
113
|
+
offset = j.mimic.offset
|
|
114
|
+
|
|
115
|
+
if joint_a not in mimic_joint_list:
|
|
116
|
+
mimic_joint_list[joint_a] = []
|
|
117
|
+
mimic_joint_list[joint_a].append((joint_b, multiplier, offset))
|
|
118
|
+
|
|
119
|
+
for mimic_joint, joints in mimic_joint_list.items():
|
|
120
|
+
linear = is_linear_joint(mimic_joint)
|
|
121
|
+
print(f" ;; re-define {mimic_joint.name} as mimic-joint", file=fp)
|
|
122
|
+
print(" (let (tmp-mimic-joint)", file=fp)
|
|
123
|
+
joint_type = "linear-mimic-joint" if linear else "rotational-mimic-joint" # NOQA
|
|
124
|
+
print(f" (setq tmp-mimic-joint (replace-object (instance {joint_type} :init :parent-link (make-cascoords) :child-link (make-cascoords) :max-joint-velocity 0 :max-joint-torque 0) {mimic_joint.name}_jt))", file=fp) # NOQA
|
|
125
|
+
print(f" (setq {mimic_joint.name}_jt tmp-mimic-joint))", file=fp)
|
|
126
|
+
print(f" (setq ({mimic_joint.name}_jt . mimic-joints)", file=fp)
|
|
127
|
+
print(" (list", file=fp)
|
|
128
|
+
for joint, multiplier, offset in joints:
|
|
129
|
+
print(f" (instance mimic-joint-param :init {joint.name}_jt :multiplier {multiplier} :offset {offset})", end='', file=fp) # NOQA
|
|
130
|
+
print("))", file=fp)
|
|
131
|
+
print(f" ;; set offset as default-coords", file=fp) # NOQA
|
|
132
|
+
print(f" (dolist (j ({mimic_joint.name}_jt . mimic-joints))", file=fp) # NOQA
|
|
133
|
+
print(" (cond ((derivedp (send j :joint) rotational-joint)", file=fp) # NOQA
|
|
134
|
+
print(" (send (send j :joint :child-link) :rotate (send j :offset) ((send j :joint) . axis)))", file=fp) # NOQA
|
|
135
|
+
print(" ((derivedp (send j :joint) linear-joint)", file=fp) # NOQA
|
|
136
|
+
print(" (send (send j :joint :child-link) :translate (scale (* 1000 (send j :offset)) ((send j :joint) . axis))))", file=fp) # NOQA
|
|
137
|
+
print(" (t (error \"unsupported mimic joint ~A\" (send j :joint))))", file=fp) # NOQA
|
|
138
|
+
print(" (setq ((send j :joint) . default-coords) (send j :joint :child-link :copy-coords)))", file=fp) # NOQA
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def print_geometry(link, simplify_vertex_clustering_voxel_size=None,
|
|
142
|
+
fp=sys.stdout):
|
|
143
|
+
x, y, z = link.translation
|
|
144
|
+
name = link.name + '_geom' + str(0)
|
|
145
|
+
print(f' (:_make_instance_{name} ()', file=fp)
|
|
146
|
+
print(' (let (geom glv qhull', file=fp)
|
|
147
|
+
print(' (local-cds (make-coords :pos ', end='', file=fp)
|
|
148
|
+
print(f'(float-vector {x * meter2millimeter:.6f} {y * meter2millimeter:.6f} {z * meter2millimeter:.6f})', end='', file=fp) # NOQA
|
|
149
|
+
|
|
150
|
+
qw, qx, qy, qz = link.quaternion
|
|
151
|
+
|
|
152
|
+
print('\n', end='', file=fp)
|
|
153
|
+
print(f' :rot (quaternion2matrix ', end='', file=fp) # NOQA
|
|
154
|
+
print(f'(float-vector {qw:.6f} {qx:.6f} {qy:.6f} {qz:.6f}))', end='', file=fp) # NOQA
|
|
155
|
+
print(')))', file=fp)
|
|
156
|
+
print(" (setq glv", file=fp)
|
|
157
|
+
print(" (instance gl::glvertices :init", end='', file=fp)
|
|
158
|
+
if link.visual_mesh is not None and len(link.visual_mesh) > 0:
|
|
159
|
+
# TODO(someone): use g.scale
|
|
160
|
+
print_mesh(link, simplify_vertex_clustering_voxel_size, fp=fp)
|
|
161
|
+
else:
|
|
162
|
+
print('))', file=fp)
|
|
163
|
+
print(" (send glv :transform local-cds)", file=fp)
|
|
164
|
+
print(" (send glv :calc-normals)", file=fp)
|
|
165
|
+
|
|
166
|
+
# TODO(someone) qhull
|
|
167
|
+
gname = link.name
|
|
168
|
+
print(f" (setq geom (instance collada-body :init :replace-obj nil :name \"{gname}\"))", file=fp) # NOQA
|
|
169
|
+
print(" (when glv", file=fp)
|
|
170
|
+
print(" (setq (geom . gl::aglvertices) glv)", file=fp)
|
|
171
|
+
print(" (send geom :assoc glv))", file=fp)
|
|
172
|
+
print(" geom))", file=fp)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def print_mesh(link, simplify_vertex_clustering_voxel_size=None,
|
|
176
|
+
fp=sys.stdout):
|
|
177
|
+
print("\n (list ;; mesh list", file=fp)
|
|
178
|
+
mesh = trimesh.util.concatenate(link.visual_mesh)
|
|
179
|
+
if simplify_vertex_clustering_voxel_size:
|
|
180
|
+
mesh = simplify_vertex_clustering(
|
|
181
|
+
mesh, simplify_vertex_clustering_voxel_size)[0]
|
|
182
|
+
for input_mesh in split_mesh_by_face_color(mesh):
|
|
183
|
+
print(" (list ;; mesh description", file=fp)
|
|
184
|
+
print(" (list :type :triangles)", file=fp)
|
|
185
|
+
print(" (list :material (list", file=fp)
|
|
186
|
+
print(f" (list :ambient (float-vector {input_mesh.visual.main_color[0] / 255.0} {input_mesh.visual.main_color[1]/ 255.0} {input_mesh.visual.main_color[2]/ 255.0} {input_mesh.visual.main_color[3]/ 255.0}))", file=fp) # NOQA
|
|
187
|
+
print(f" (list :diffuse (float-vector {input_mesh.visual.main_color[0]/ 255.0} {input_mesh.visual.main_color[1]/ 255.0} {input_mesh.visual.main_color[2]/ 255.0} {input_mesh.visual.main_color[3]/ 255.0}))", end="", file=fp) # NOQA
|
|
188
|
+
print("))", file=fp)
|
|
189
|
+
print(" (list :indices #i(", end="", file=fp)
|
|
190
|
+
print(' '.join(map(str, input_mesh.faces.reshape(-1))), end="", file=fp) # NOQA
|
|
191
|
+
print("))", file=fp)
|
|
192
|
+
print(f" (list :vertices (let ((mat (make-matrix {len(input_mesh.vertices)} 3))) (fvector-replace (array-entity mat) #f(", end="", file=fp) # NOQA
|
|
193
|
+
vertices = np.array(input_mesh.vertices)
|
|
194
|
+
vertices = link.inverse_transformation().transform_vector(vertices)
|
|
195
|
+
vertices = meter2millimeter * vertices
|
|
196
|
+
# Modified the vertex printing format to reduce mesh file size, considering the unit is in millimeters (mm). # NOQA
|
|
197
|
+
# Since the coordinates are in mm, having them formatted to just one decimal place is sufficiently precise for most applications. # NOQA
|
|
198
|
+
# This change not only preserves the necessary precision for mm-scale measurements but also effectively compresses the data, # NOQA
|
|
199
|
+
# resulting in a smaller file size due to reduced numerical precision in the vertex coordinates. # NOQA
|
|
200
|
+
print(' '.join(map(lambda x: '{0:.1f}'.format(x),
|
|
201
|
+
vertices.reshape(-1))),
|
|
202
|
+
end='', file=fp)
|
|
203
|
+
print(")) mat))", end="", file=fp)
|
|
204
|
+
# TODO(someone) normal
|
|
205
|
+
print(")", end='', file=fp)
|
|
206
|
+
print(")))", file=fp)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def print_end_coords(robot, config_yaml_path=None,
|
|
210
|
+
add_link_suffix=True, add_joint_suffix=True,
|
|
211
|
+
fp=sys.stdout):
|
|
212
|
+
if config_yaml_path is not None:
|
|
213
|
+
read_config_from_yaml(robot, config_yaml_path, fp=fp)
|
|
214
|
+
else:
|
|
215
|
+
print(" ;; init-ending\n", file=fp)
|
|
216
|
+
print(" (send self :init-ending) ;; :urdf\n", file=fp)
|
|
217
|
+
print(" ;; overwrite bodies to return draw-things links not (send link :bodies)\n", file=fp) # NOQA
|
|
218
|
+
print(" (setq bodies (flatten (mapcar #'(lambda (b) (if (find-method b :bodies) (send b :bodies))) (list", end="", file=fp) # NOQA
|
|
219
|
+
for link in robot.link_list:
|
|
220
|
+
if add_link_suffix:
|
|
221
|
+
print(f" {link.name}_lk", end="", file=fp)
|
|
222
|
+
else:
|
|
223
|
+
print(f" {link.name}", end="", file=fp)
|
|
224
|
+
print("))))\n", file=fp)
|
|
225
|
+
|
|
226
|
+
print(" (when (member :reset-pose (send self :methods))", file=fp)
|
|
227
|
+
print(" (send self :reset-pose)) ;; :set reset-pose\n", file=fp) # NOQA
|
|
228
|
+
print(" self)) ;; end of :init", file=fp)
|
|
229
|
+
|
|
230
|
+
print("\n", end='', file=fp)
|
|
231
|
+
print(" ;; all joints", file=fp)
|
|
232
|
+
# Assuming URDFDOM_1_0_0_API is a boolean variable
|
|
233
|
+
for joint in collect_all_joints_of_robot(robot):
|
|
234
|
+
joint_name = joint.name
|
|
235
|
+
if add_joint_suffix:
|
|
236
|
+
if is_fixed_joint(joint):
|
|
237
|
+
print(f" (:{joint_name} (&rest args) (forward-message-to {joint_name}_fixed_jt args))", file=fp) # NOQA
|
|
238
|
+
else:
|
|
239
|
+
print(f" (:{joint_name} (&rest args) (forward-message-to {joint_name}_jt args))", file=fp) # NOQA
|
|
240
|
+
else:
|
|
241
|
+
print(f" (:{joint_name} (&rest args) (forward-message-to {joint_name} args))", file=fp) # NOQA
|
|
242
|
+
|
|
243
|
+
if add_link_suffix:
|
|
244
|
+
print("\n ;; all links forwarding", file=fp)
|
|
245
|
+
print(" (:links (&rest args)", file=fp)
|
|
246
|
+
print(" (if (null args) (return-from :links (send-super :links)))", file=fp) # NOQA
|
|
247
|
+
print(" (let ((key (car args))\n (nargs (cdr args)))", file=fp) # NOQA
|
|
248
|
+
print(" (unless (keywordp key)\n (return-from :links (send-super* :links args)))\n (case key", file=fp) # NOQA
|
|
249
|
+
|
|
250
|
+
for link in robot.link_list:
|
|
251
|
+
link_name = link.name
|
|
252
|
+
print(f" (:{link_name} (forward-message-to {link_name}_lk nargs))", file=fp) # NOQA
|
|
253
|
+
print(" (t (send-super* :links args)))))", file=fp)
|
|
254
|
+
|
|
255
|
+
print("\n ;; all links", file=fp)
|
|
256
|
+
for link in robot.link_list:
|
|
257
|
+
link_name = link.name
|
|
258
|
+
if add_link_suffix:
|
|
259
|
+
print(f" (:{link_name}_lk (&rest args) (forward-message-to {link_name}_lk args))", file=fp) # NOQA
|
|
260
|
+
else:
|
|
261
|
+
print(f" (:{link_name} (&rest args) (forward-message-to {link_name} args))", file=fp) # NOQA
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def urdf2eus(urdf_path, config_yaml_path=None,
|
|
265
|
+
simplify_vertex_clustering_voxel_size=None,
|
|
266
|
+
fp=sys.stdout):
|
|
267
|
+
r = RobotModel()
|
|
268
|
+
with open(urdf_path, 'r') as f:
|
|
269
|
+
r.load_urdf_file(f)
|
|
270
|
+
robot_name = r.urdf_robot_model.name
|
|
271
|
+
|
|
272
|
+
current_time_str = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
273
|
+
print(f""";; DO NOT EDIT THIS FILE
|
|
274
|
+
;;
|
|
275
|
+
;; this file is automatically generated from {urdf_path} on ({sys.platform} {socket.gethostname()} {platform.platform()}) at {current_time_str}
|
|
276
|
+
;;
|
|
277
|
+
""", file=fp) # NOQA
|
|
278
|
+
|
|
279
|
+
print(get_euscollada_string(), file=fp)
|
|
280
|
+
|
|
281
|
+
joint_names = []
|
|
282
|
+
for joint in collect_all_joints_of_robot(r):
|
|
283
|
+
joint_name = joint.name
|
|
284
|
+
if is_fixed_joint(joint):
|
|
285
|
+
joint_name += "_fixed_jt"
|
|
286
|
+
else:
|
|
287
|
+
joint_name += "_jt"
|
|
288
|
+
joint_names.append(joint_name)
|
|
289
|
+
|
|
290
|
+
add_link_suffix = True
|
|
291
|
+
link_list = []
|
|
292
|
+
for link in r.link_list:
|
|
293
|
+
if add_link_suffix:
|
|
294
|
+
link_name = link.name + "_lk"
|
|
295
|
+
else:
|
|
296
|
+
link_name = link.name
|
|
297
|
+
link_list.append(link_name)
|
|
298
|
+
|
|
299
|
+
print('\n\n', end='', file=fp)
|
|
300
|
+
print(f"(defun {robot_name} () (setq *{robot_name}* (instance {robot_name}-robot :init)))", file=fp) # NOQA
|
|
301
|
+
print('\n\n', end='', file=fp)
|
|
302
|
+
print(f"(defclass {robot_name}-robot", file=fp)
|
|
303
|
+
print(" :super euscollada-robot", file=fp)
|
|
304
|
+
print(" :slots (;; link names", file=fp)
|
|
305
|
+
print(" " + " ".join(link_list), file=fp)
|
|
306
|
+
print(" ;; joint names", file=fp)
|
|
307
|
+
print(" " + ' '.join(joint_names), file=fp)
|
|
308
|
+
print(" ;; sensor names", file=fp)
|
|
309
|
+
print(" ;; non-default limb names", file=fp)
|
|
310
|
+
print(" ))", file=fp)
|
|
311
|
+
print('\n\n', end='', file=fp)
|
|
312
|
+
print(f"(defmethod {r.urdf_robot_model.name}-robot", file=fp)
|
|
313
|
+
print(" (:init", file=fp)
|
|
314
|
+
print(" (&rest args)", file=fp)
|
|
315
|
+
print(" (let ()", file=fp)
|
|
316
|
+
print(f" (send-super* :init :name \"{r.urdf_robot_model.name}\" args)", file=fp) # NOQA
|
|
317
|
+
print("\n\n", file=fp)
|
|
318
|
+
|
|
319
|
+
for link in r.link_list:
|
|
320
|
+
print_link(link, fp=fp)
|
|
321
|
+
|
|
322
|
+
add_link_suffix = True
|
|
323
|
+
checked_pairs = {}
|
|
324
|
+
for link in r.link_list:
|
|
325
|
+
for child_link in link.child_links:
|
|
326
|
+
if checked_pairs.get((link.name, child_link.name)) \
|
|
327
|
+
or checked_pairs.get((child_link.name, link.name)):
|
|
328
|
+
continue
|
|
329
|
+
if add_link_suffix:
|
|
330
|
+
print(f" (send {link.name}_lk :assoc {child_link.name}_lk)", file=fp) # NOQA
|
|
331
|
+
else:
|
|
332
|
+
print(f" (send {link.name} :assoc {child_link.name})", file=fp) # NOQA
|
|
333
|
+
checked_pairs[(link.name, child_link.name)] = True
|
|
334
|
+
if add_link_suffix:
|
|
335
|
+
print(f" (send self :assoc {r.root_link.name}_lk)", file=fp)
|
|
336
|
+
else:
|
|
337
|
+
print(f" (send self :assoc {r.root_link.name})", file=fp)
|
|
338
|
+
|
|
339
|
+
for j in collect_all_joints_of_robot(r):
|
|
340
|
+
print_joint(j, fp=fp)
|
|
341
|
+
print_mimic_joints(r, fp=fp)
|
|
342
|
+
print_end_coords(r, config_yaml_path, fp=fp)
|
|
343
|
+
|
|
344
|
+
for link in r.link_list:
|
|
345
|
+
print_geometry(link,
|
|
346
|
+
simplify_vertex_clustering_voxel_size, fp=fp)
|
|
347
|
+
print(' )', file=fp)
|
|
348
|
+
print(file=fp)
|
|
349
|
+
print(f'(provide :{robot_name} "({socket.gethostname()} {platform.platform()}) at {current_time_str}")', file=fp) # NOQA
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2023 Iori Yanokura.
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
+
in the Software without restriction, including without limitation the rights
|
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
+
furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: urdfeus
|
|
3
|
+
Version: 0.0.6
|
|
4
|
+
Summary: URDF converter for Euslisp
|
|
5
|
+
Home-page: https://github.com/iory/urdfeus
|
|
6
|
+
Author: iory
|
|
7
|
+
Author-email: ab.ioryz@gmail.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Natural Language :: English
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.5
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
17
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: open3d
|
|
21
|
+
Requires-Dist: pyglet <=1.5.17
|
|
22
|
+
Requires-Dist: pyyaml
|
|
23
|
+
Requires-Dist: scikit-robot >=0.0.35
|
|
24
|
+
|
|
25
|
+
# urdfeus
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
urdfeus/__init__.py,sha256=Ug8GqHUzOXJzq1G1zVEuFRJz4j1t9Ppt-0_vj_masf8,103
|
|
2
|
+
urdfeus/common.py,sha256=bjPU2LrHzwikPZiHIqLwETZI0PjWA-YaLvqEj5R4S3M,621
|
|
3
|
+
urdfeus/mesh2eus.py,sha256=-_90i5jxYlhp2NAiief-L7NzVqYxEY6E4D2omWmQDIo,987
|
|
4
|
+
urdfeus/read_yaml.py,sha256=PUwT-GaSSz0iRnc6pWu-67vaahEcdVEF4ntnPZpNgkU,7032
|
|
5
|
+
urdfeus/urdf2eus.py,sha256=NCRJ7I77NxrWCSys64D7rkn2LLwvzTSBomB3javt9TU,17040
|
|
6
|
+
urdfeus/apps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
urdfeus/apps/mesh2eus.py,sha256=JKg0flKRsg6RhBvLIlSouVAkuD893PeejH-rhUQmUN4,1112
|
|
8
|
+
urdfeus/apps/urdf2eus.py,sha256=F-S9iuk2S15FLM7F-2RwaoKrWRYVmvL8jmnJLOJ5OP4,1252
|
|
9
|
+
urdfeus/templates/__init__.py,sha256=f118QjZue3fxxsB6YpNbGko1EVAaK_yyAZQhH3mlgUQ,187
|
|
10
|
+
urdfeus/templates/euscollada-robot.l,sha256=dNrCguOD4gqPDsW4Gr4HubS8hDk3bj3twaWrxa9f8MY,12226
|
|
11
|
+
urdfeus/templates/urdf_template.py,sha256=h52qOWOGkkCBERFJ4Aw6grbx-DxFtt9BjCmm5NAm8Yk,674
|
|
12
|
+
urdfeus-0.0.6.dist-info/LICENSE,sha256=32sGF5yxCI5h7Ii-UqFOUAMeChgbTttAvpoW6w3WMQw,1058
|
|
13
|
+
urdfeus-0.0.6.dist-info/METADATA,sha256=tkn3HVVC_n8n9KkdI9Bysd_vJCrmT5Wz1wqxED1--Xc,830
|
|
14
|
+
urdfeus-0.0.6.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
15
|
+
urdfeus-0.0.6.dist-info/entry_points.txt,sha256=b1PIL8Ps8ryD5iTPfFnbnx3a20BYyO2Y1CpSg7_dfuU,94
|
|
16
|
+
urdfeus-0.0.6.dist-info/top_level.txt,sha256=NaalN7YfuV0m4TT6vNs2efjsgTqY0iyErAU9JQQwuFo,8
|
|
17
|
+
urdfeus-0.0.6.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
urdfeus
|