Skip to content

Commit 70a9789

Browse files
authored
Merge pull request #883 from compas-dev/draw_acm
Attach meshes to a RobotModelArtist and draw them
2 parents bce3fbb + 2f20030 commit 70a9789

File tree

6 files changed

+105
-11
lines changed

6 files changed

+105
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
* Added `compas.data.is_sequence_of_uint`.
1515
* Added general plotter for geometry objects and data structures based on the artist registration mechanism.
1616
* Added support for multimesh files to OBJ reader/writer.
17+
* Added support for attaching and detaching meshes in `compas.robots.RobotModelArtist` and drawing them.
1718

1819
### Changed
1920

src/compas/robots/base_artist/_artist.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from compas.geometry import Scale
99
from compas.geometry import Transformation
1010
from compas.robots import Geometry
11+
from compas.robots.model.link import Item
1112

1213

1314
__all__ = [
@@ -75,6 +76,7 @@ def __init__(self, model):
7576
self.create()
7677
self.scale_factor = 1.
7778
self.attached_tool_model = None
79+
self.attached_items = {}
7880

7981
def attach_tool_model(self, tool_model):
8082
"""Attach a tool to the robot artist.
@@ -114,6 +116,61 @@ def detach_tool_model(self):
114116
"""
115117
self.attached_tool_model = None
116118

119+
def attach_mesh(self, mesh, name, link=None, frame=None):
120+
"""Rigidly attaches a compas mesh to a given link.
121+
122+
Parameters
123+
----------
124+
mesh : :class:`compas.datastructures.Mesh`
125+
The mesh to attach to the robot model.
126+
name : :obj:`str`
127+
The identifier of the mesh.
128+
link : :class:`compas.robots.Link`
129+
The link within the robot model or tool model to attach the mesh to. Optional.
130+
Defaults to the model's end effector link.
131+
frame : :class:`compas.geometry.Frame`
132+
The frame of the mesh. Defaults to :meth:`compas.geometry.Frame.worldXY`.
133+
134+
Returns
135+
-------
136+
``None``
137+
"""
138+
if not link:
139+
link = self.model.get_end_effector_link()
140+
transformation = Transformation.from_frame(frame) if frame else Transformation()
141+
142+
sample_geometry = None
143+
144+
while sample_geometry is None:
145+
sample_geometry = link.collision[0] if link.collision else link.visual[0] if link.visual else None
146+
link = self.model.get_link_by_name(link.parent_joint.parent.link)
147+
148+
native_mesh = self.create_geometry(mesh)
149+
init_transformation = transformation * sample_geometry.init_transformation
150+
self.transform(native_mesh, sample_geometry.current_transformation * init_transformation)
151+
152+
item = Item()
153+
item.native_geometry = [native_mesh]
154+
item.init_transformation = init_transformation
155+
item.current_transformation = sample_geometry.current_transformation
156+
157+
self.attached_items.setdefault(link.name, {})[name] = item
158+
159+
def detach_mesh(self, name):
160+
"""Removes attached collision meshes with a given name.
161+
162+
Parameters
163+
----------
164+
name : :obj:`str`
165+
The identifier of the mesh.
166+
167+
Returns
168+
-------
169+
``None``
170+
"""
171+
for _, items in self.attached_items:
172+
items.pop(name, None)
173+
117174
def create(self, link=None, context=None):
118175
"""Recursive function that triggers the drawing of the robot model's geometry.
119176
@@ -258,6 +315,8 @@ def _transform_link_geometry(self, link, transformation, collision=True):
258315
# some links have only collision geometry, not visual. These meshes have not been loaded.
259316
if item.native_geometry:
260317
self._apply_transformation_on_transformed_link(item, transformation)
318+
for item in self.attached_items.get(link.name, {}).values():
319+
self._apply_transformation_on_transformed_link(item, transformation)
261320

262321
def update_tool(self, joint_state=None, visual=True, collision=True, transformation=None):
263322
"""Triggers the update of the robot geometry of the tool.
@@ -302,6 +361,13 @@ def draw_collision(self):
302361
for native_geometry in self._iter_geometry(self.attached_tool_model, 'collision'):
303362
yield native_geometry
304363

364+
def draw_attached_meshes(self):
365+
"""Draws all meshes attached to the robot model."""
366+
for items in self.attached_items.values():
367+
for item in items.values():
368+
for native_mesh in item.native_geometry:
369+
yield native_mesh
370+
305371
@staticmethod
306372
def _iter_geometry(model, geometry_type):
307373
for link in model.iter_links():

src/compas/robots/model/joint.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,9 @@ class Joint(Data):
460460
SUPPORTED_TYPES = ('revolute', 'continuous', 'prismatic', 'fixed',
461461
'floating', 'planar')
462462

463-
def __init__(self, name, type, parent, child, origin=None, axis=None, calibration=None, dynamics=None, limit=None, safety_controller=None, mimic=None, **kwargs):
463+
def __init__(self, name, type, parent, child, origin=None, axis=None,
464+
calibration=None, dynamics=None, limit=None,
465+
safety_controller=None, mimic=None, **kwargs):
464466
type_idx = Joint.SUPPORTED_TYPES.index(type) if isinstance(type, str) else type
465467

466468
if type_idx not in range(len(Joint.SUPPORTED_TYPES)):

src/compas/robots/model/link.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,14 @@ def data(self, data):
168168
self.inertia = Inertia.from_data(data['inertia']) if data['inertia'] else None
169169

170170

171-
class Visual(Data):
171+
class Item(object):
172+
def __init__(self):
173+
self.init_transformation = None # to store the init transformation
174+
self.current_transformation = None # to store the current transformation
175+
self.native_geometry = None # to store the link's CAD native geometry
176+
177+
178+
class Visual(Item, Data):
172179
"""Visual description of a link.
173180
174181
Attributes
@@ -195,10 +202,6 @@ def __init__(self, geometry, origin=None, name=None, material=None, **kwargs):
195202
self.material = material
196203
self.attr = kwargs
197204

198-
self.init_transformation = None # to store the init transformation
199-
self.current_transformation = None # to store the current transformation
200-
self.native_geometry = None # to store the link's CAD native geometry
201-
202205
def get_urdf_element(self):
203206
attributes = {}
204207
if self.name is not None:
@@ -265,7 +268,7 @@ def from_primitive(cls, primitive, **kwargs):
265268
return cls(geometry, origin=origin, **kwargs)
266269

267270

268-
class Collision(Data):
271+
class Collision(Item, Data):
269272
"""Collidable description of a link.
270273
271274
Attributes
@@ -289,10 +292,6 @@ def __init__(self, geometry, origin=None, name=None, **kwargs):
289292
self.name = name
290293
self.attr = kwargs
291294

292-
self.init_transformation = None # to store the init transformation
293-
self.current_transformation = None # to store the current transformation
294-
self.native_geometry = None # to store the link's CAD native geometry
295-
296295
def get_urdf_element(self):
297296
attributes = {}
298297
if self.name is not None:

src/compas_blender/artists/robotmodelartist.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,8 @@ def draw_collision(self):
5757
collisions = super(RobotModelArtist, self).draw_collision()
5858
for collision in collisions:
5959
collision.hide_set(False)
60+
61+
def draw_attached_meshes(self):
62+
meshes = super(RobotModelArtist, self).draw_attached_meshes()
63+
for mesh in meshes:
64+
mesh.hide_set(False)

src/compas_rhino/artists/robotmodelartist.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,27 @@ def draw_visual(self):
150150
self._exit_layer()
151151
return new_guids
152152

153+
def draw_attached_meshes(self):
154+
"""Draw all the geometries attached to the robot model.
155+
156+
Returns
157+
-------
158+
list
159+
The GUIDs of the created Rhino objects.
160+
"""
161+
acms = super(RobotModelArtist, self).draw_attached_meshes()
162+
acms = list(acms)
163+
164+
self._enter_layer()
165+
166+
new_guids = []
167+
for mesh in acms:
168+
guids = self._add_mesh_to_doc(mesh)
169+
new_guids.extend(guids)
170+
171+
self._exit_layer()
172+
return new_guids
173+
153174
def draw(self):
154175
"""Same as draw_visual."""
155176
return self.draw_visual()

0 commit comments

Comments
 (0)