From 6117719ab66df78cc9e0464f1858391e74e5c065 Mon Sep 17 00:00:00 2001 From: Victor LEUNG Date: Wed, 4 Oct 2023 19:09:44 +0800 Subject: [PATCH 01/12] Changed classes to inherete from compas.Data --- src/compas_fab/robots/planning_scene.py | 10 +++++-- src/compas_fab/robots/robot.py | 40 ++++++++++++++++++++++--- src/compas_fab/robots/semantics.py | 3 +- src/compas_fab/robots/tool.py | 5 +++- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/compas_fab/robots/planning_scene.py b/src/compas_fab/robots/planning_scene.py index b1cb66e36..00f583a6b 100644 --- a/src/compas_fab/robots/planning_scene.py +++ b/src/compas_fab/robots/planning_scene.py @@ -2,6 +2,7 @@ from __future__ import division from __future__ import print_function +from compas.data import Data from compas.datastructures import Mesh from compas.geometry import Frame from compas.geometry import Scale @@ -13,7 +14,7 @@ ] -class CollisionMesh(object): +class CollisionMesh(Data): """Represents a collision mesh. Parameters @@ -55,6 +56,7 @@ class CollisionMesh(object): """ def __init__(self, mesh, id, frame=None, root_name=None): + super(CollisionMesh, self).__init__() self.id = id self.mesh = mesh self.frame = frame or Frame.worldXY() @@ -130,7 +132,7 @@ def data(self, data_obj): self.root_name = data_obj["root_name"] -class AttachedCollisionMesh(object): +class AttachedCollisionMesh(Data): """Represents a collision mesh that is attached to a :class:`Robot`'s :class:`~compas.robots.Link`. Parameters @@ -169,6 +171,7 @@ class AttachedCollisionMesh(object): """ def __init__(self, collision_mesh, link_name, touch_links=None, weight=1.0): + super(AttachedCollisionMesh, self).__init__() self.collision_mesh = collision_mesh if self.collision_mesh: self.collision_mesh.root_name = link_name @@ -224,7 +227,7 @@ def data(self, data_obj): self.weight = data_obj["weight"] -class PlanningScene(object): +class PlanningScene(Data): """Represents the planning scene. Parameters @@ -241,6 +244,7 @@ class PlanningScene(object): """ def __init__(self, robot): + super(PlanningScene, self).__init__() self.robot = robot @property diff --git a/src/compas_fab/robots/robot.py b/src/compas_fab/robots/robot.py index df3d54dfc..ec5297496 100644 --- a/src/compas_fab/robots/robot.py +++ b/src/compas_fab/robots/robot.py @@ -4,6 +4,7 @@ import random +from compas.data import Data from compas.geometry import Frame from compas.geometry import Sphere from compas.geometry import Transformation @@ -21,7 +22,7 @@ ] -class Robot(object): +class Robot(Data): """Represents a robot. This class binds together several building blocks, such as the robot's @@ -47,15 +48,44 @@ class Robot(object): Dictionary mapping planning groups to the tool currently attached to them, if any. """ - def __init__(self, model, artist=None, semantics=None, client=None): + def __init__(self, model=None, artist=None, semantics=None, client=None): + super(Robot, self).__init__() + # These attributes have to be initiated first, + # because they are used in the setters of the other attributes self._scale_factor = 1.0 - self.model = model self._attached_tools = {} # { planning_group_name: robots.tool.Tool } + self._current_ik = {"request_id": None, "solutions": None} + + self.model = model self.artist = artist self.semantics = semantics self.client = client self.attributes = {} - self._current_ik = {"request_id": None, "solutions": None} + + @property + def data(self): + data = { + '_scale_factor': self._scale_factor, + '_attached_tools': self._attached_tools, + '_current_ik': self._current_ik, + 'model': self.model.data, + # 'artist': self.artist.data if self.artist else None, + # 'semantics': self.semantics.data if self.semantics else None, + # 'client': self.client.data if self.client else None, + 'attributes': self.attributes, + } + return data + + @data.setter + def data(self, data): + self._scale_factor = data.get('_scale_factor', 1.0) + self._attached_tools = data.get('_attached_tools', {}) + self._current_ik = data.get('_current_ik', {"request_id": None, "solutions": None}) + self.model = RobotModel.from_data(data['model']) + # self.artist = data.get('artist', None) + # self.semantics = data.get('semantics', None) + # self.client = data.get('client', None) + self.attributes = data.get('attributes', {}) @property def artist(self): @@ -65,6 +95,8 @@ def artist(self): @artist.setter def artist(self, artist): self._artist = artist + if artist is None: + return if len(self.model.joints) > 0 and len(self.model.links) > 0: self.scale(self._scale_factor) for tool in self.attached_tools.values(): diff --git a/src/compas_fab/robots/semantics.py b/src/compas_fab/robots/semantics.py index d209d3c39..dc0b21d7b 100644 --- a/src/compas_fab/robots/semantics.py +++ b/src/compas_fab/robots/semantics.py @@ -3,13 +3,14 @@ from __future__ import print_function from compas.files import XML +from compas.data import Data __all__ = [ "RobotSemantics", ] -class RobotSemantics(object): +class RobotSemantics(Data): """Represents semantic information of a robot. The semantic model is based on the diff --git a/src/compas_fab/robots/tool.py b/src/compas_fab/robots/tool.py index fde614999..1c5f3e72a 100644 --- a/src/compas_fab/robots/tool.py +++ b/src/compas_fab/robots/tool.py @@ -4,6 +4,7 @@ import json +from compas.data import Data from compas.robots import Geometry from compas.robots import ToolModel @@ -14,7 +15,7 @@ __all__ = ["Tool"] -class Tool(object): +class Tool(Data): """Represents a tool to be attached to the robot's flange. Attributes @@ -39,8 +40,10 @@ class Tool(object): """ def __init__(self, visual, frame_in_tool0_frame, collision=None, name="attached_tool", link_name=None): + super(Tool, self).__init__() self.tool_model = ToolModel(visual, frame_in_tool0_frame, collision, name, link_name) + @classmethod def from_tool_model(cls, tool_model): tool = cls(None, None) From bf71c1f45bcd20d37fe500560f3a948dd70811b7 Mon Sep 17 00:00:00 2001 From: Victor LEUNG Date: Wed, 4 Oct 2023 19:52:33 +0800 Subject: [PATCH 02/12] Fix Lint Problems --- src/compas_fab/robots/robot.py | 32 +++++++++++++++----------------- src/compas_fab/robots/tool.py | 1 - 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/compas_fab/robots/robot.py b/src/compas_fab/robots/robot.py index ec5297496..86037d06e 100644 --- a/src/compas_fab/robots/robot.py +++ b/src/compas_fab/robots/robot.py @@ -50,7 +50,7 @@ class Robot(Data): def __init__(self, model=None, artist=None, semantics=None, client=None): super(Robot, self).__init__() - # These attributes have to be initiated first, + # These attributes have to be initiated first, # because they are used in the setters of the other attributes self._scale_factor = 1.0 self._attached_tools = {} # { planning_group_name: robots.tool.Tool } @@ -65,27 +65,25 @@ def __init__(self, model=None, artist=None, semantics=None, client=None): @property def data(self): data = { - '_scale_factor': self._scale_factor, - '_attached_tools': self._attached_tools, - '_current_ik': self._current_ik, - 'model': self.model.data, - # 'artist': self.artist.data if self.artist else None, - # 'semantics': self.semantics.data if self.semantics else None, - # 'client': self.client.data if self.client else None, - 'attributes': self.attributes, + "_scale_factor": self._scale_factor, + "_attached_tools": self._attached_tools, + "_current_ik": self._current_ik, + "model": self.model.data, + "attributes": self.attributes, + # The following attributes cannnot be serizlied + # "artist": self.artist.data if self.artist else None, + # "semantics": self.semantics.data if self.semantics else None, + # "client": self.client.data if self.client else None, } return data @data.setter def data(self, data): - self._scale_factor = data.get('_scale_factor', 1.0) - self._attached_tools = data.get('_attached_tools', {}) - self._current_ik = data.get('_current_ik', {"request_id": None, "solutions": None}) - self.model = RobotModel.from_data(data['model']) - # self.artist = data.get('artist', None) - # self.semantics = data.get('semantics', None) - # self.client = data.get('client', None) - self.attributes = data.get('attributes', {}) + self._scale_factor = data.get("_scale_factor", 1.0) + self._attached_tools = data.get("_attached_tools", {}) + self._current_ik = data.get("_current_ik", {"request_id": None, "solutions": None}) + self.model = RobotModel.from_data(data["model"]) + self.attributes = data.get("attributes", {}) @property def artist(self): diff --git a/src/compas_fab/robots/tool.py b/src/compas_fab/robots/tool.py index 1c5f3e72a..f6cfd39af 100644 --- a/src/compas_fab/robots/tool.py +++ b/src/compas_fab/robots/tool.py @@ -43,7 +43,6 @@ def __init__(self, visual, frame_in_tool0_frame, collision=None, name="attached_ super(Tool, self).__init__() self.tool_model = ToolModel(visual, frame_in_tool0_frame, collision, name, link_name) - @classmethod def from_tool_model(cls, tool_model): tool = cls(None, None) From 3dc93592182c11a4013a002b00fdc79130446391 Mon Sep 17 00:00:00 2001 From: Victor LEUNG Date: Thu, 5 Oct 2023 14:10:49 +0800 Subject: [PATCH 03/12] undo PlanningScene(Data) --- src/compas_fab/robots/planning_scene.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compas_fab/robots/planning_scene.py b/src/compas_fab/robots/planning_scene.py index 00f583a6b..9c025bbdf 100644 --- a/src/compas_fab/robots/planning_scene.py +++ b/src/compas_fab/robots/planning_scene.py @@ -227,7 +227,7 @@ def data(self, data_obj): self.weight = data_obj["weight"] -class PlanningScene(Data): +class PlanningScene(object): """Represents the planning scene. Parameters @@ -244,7 +244,6 @@ class PlanningScene(Data): """ def __init__(self, robot): - super(PlanningScene, self).__init__() self.robot = robot @property From d9e15b0f38f3cd23a2f3ce0783f575c9b8e5dba9 Mon Sep 17 00:00:00 2001 From: Victor LEUNG Date: Thu, 5 Oct 2023 14:26:59 +0800 Subject: [PATCH 04/12] Data setter getter for RobotSemantics --- src/compas_fab/robots/semantics.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/compas_fab/robots/semantics.py b/src/compas_fab/robots/semantics.py index dc0b21d7b..6d4ae7e45 100644 --- a/src/compas_fab/robots/semantics.py +++ b/src/compas_fab/robots/semantics.py @@ -42,6 +42,35 @@ def __init__( self.disabled_collisions = disabled_collisions or set() self.group_states = group_states or {} + @property + def data(self): + data = { + "robot_model": self.robot_model, + "groups": self.groups, + "main_group_name": self.main_group_name, + "passive_joints": self.passive_joints, + "end_effectors": self.end_effectors, + "disabled_collisions": self.disabled_collisions, + "group_states": self.group_states, + } + return data + + @data.setter + def data(self, data): + self.robot_model = data.get("robot_model", None) + self.groups = data.get("groups", {}) + self.main_group_name = data.get("main_group_name", None) + self.passive_joints = data.get("passive_joints", []) + self.end_effectors = data.get("end_effectors", []) + self.disabled_collisions = data.get("disabled_collisions", set()) + self.group_states = data.get("group_states", {}) + + @classmethod + def from_data(cls, data): + robot_semantics = cls(None) + robot_semantics.data = data + return robot_semantics + @property def group_names(self): return list(self.groups.keys()) From 03c657376631102a12df5061c0c99a80687bd3e6 Mon Sep 17 00:00:00 2001 From: Victor LEUNG Date: Thu, 5 Oct 2023 14:33:18 +0800 Subject: [PATCH 05/12] changelog --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e955420c..83f2c3ab2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +* `CollisionMesh` now inherit from `compas.data.Data` +* `AttachedCollisionMesh` now inherit from `compas.data.Data` +* `Robot` now inherit from `compas.data.Data` +* `RobotSemantics` now inherit from `compas.data.Data` +* `Tool` now inherit from `compas.data.Data` + ### Removed From 48893289ff6c5d9b768ad1a9d7a593442c919c25 Mon Sep 17 00:00:00 2001 From: Victor LEUNG Date: Thu, 5 Oct 2023 15:28:14 +0800 Subject: [PATCH 06/12] Serialization of disabled_collisions in RobotSemantics --- src/compas_fab/robots/robot.py | 3 ++- src/compas_fab/robots/semantics.py | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/compas_fab/robots/robot.py b/src/compas_fab/robots/robot.py index 86037d06e..f585c95a8 100644 --- a/src/compas_fab/robots/robot.py +++ b/src/compas_fab/robots/robot.py @@ -69,10 +69,10 @@ def data(self): "_attached_tools": self._attached_tools, "_current_ik": self._current_ik, "model": self.model.data, + "semantics": self.semantics, "attributes": self.attributes, # The following attributes cannnot be serizlied # "artist": self.artist.data if self.artist else None, - # "semantics": self.semantics.data if self.semantics else None, # "client": self.client.data if self.client else None, } return data @@ -83,6 +83,7 @@ def data(self, data): self._attached_tools = data.get("_attached_tools", {}) self._current_ik = data.get("_current_ik", {"request_id": None, "solutions": None}) self.model = RobotModel.from_data(data["model"]) + self.semantics = data.get("semantics", None) self.attributes = data.get("attributes", {}) @property diff --git a/src/compas_fab/robots/semantics.py b/src/compas_fab/robots/semantics.py index 6d4ae7e45..aa1fb13c6 100644 --- a/src/compas_fab/robots/semantics.py +++ b/src/compas_fab/robots/semantics.py @@ -33,6 +33,7 @@ def __init__( disabled_collisions=None, group_states=None, ): + super(RobotSemantics, self).__init__() self.robot_model = robot_model self.groups = groups or {} @@ -50,7 +51,7 @@ def data(self): "main_group_name": self.main_group_name, "passive_joints": self.passive_joints, "end_effectors": self.end_effectors, - "disabled_collisions": self.disabled_collisions, + "disabled_collisions": sorted(self.disabled_collisions), "group_states": self.group_states, } return data @@ -63,6 +64,8 @@ def data(self, data): self.passive_joints = data.get("passive_joints", []) self.end_effectors = data.get("end_effectors", []) self.disabled_collisions = data.get("disabled_collisions", set()) + if len(self.disabled_collisions) > 0: + self.disabled_collisions = {tuple(pair) for pair in self.disabled_collisions} self.group_states = data.get("group_states", {}) @classmethod From b2ab2488abfe131e1dcfbba43ac984842bece7b6 Mon Sep 17 00:00:00 2001 From: Victor LEUNG Date: Thu, 5 Oct 2023 15:29:11 +0800 Subject: [PATCH 07/12] Tests for RobotSemantics and Robot serialization --- tests/robots/test_robot.py | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/robots/test_robot.py b/tests/robots/test_robot.py index 6ec481fbd..f271e7145 100644 --- a/tests/robots/test_robot.py +++ b/tests/robots/test_robot.py @@ -3,6 +3,7 @@ import re import pytest +from compas.data import json_dumps, json_loads from compas.datastructures import Mesh from compas.geometry import Frame from compas.robots import RobotModel @@ -289,6 +290,43 @@ def test_get_configurable_joints_wo_semantics(panda_robot_instance_wo_semantics) assert all(matches) +def test_semantics_serialization(panda_srdf, panda_urdf): + model = RobotModel.from_urdf_file(panda_urdf) + semantics = RobotSemantics.from_srdf_file(panda_srdf, model) + semantics_string = json_dumps(semantics) + semantics2 = json_loads(semantics_string) + assert isinstance(semantics, RobotSemantics) + assert isinstance(semantics2, RobotSemantics) + assert ("panda_hand", "panda_link6") in semantics2.disabled_collisions + assert ("panda_hand", "panda_leftfinger") in semantics2.disabled_collisions + + +def test_robot_serialization(panda_robot_instance): + robot = panda_robot_instance + robot_string = json_dumps(robot) + robot2 = json_loads(robot_string) + robot2_string = json_dumps(robot2) + assert isinstance(robot, Robot) + assert isinstance(robot2, Robot) + assert robot_string == robot2_string + assert robot.model.data == robot2.model.data + assert robot.attributes == robot2.attributes + + +def test_robot_serialization_with_tool(ur5_robot_instance, robot_tool1): + robot = ur5_robot_instance + tool = robot_tool1 + robot.attach_tool(tool) + robot_string = json_dumps(robot) + robot2 = json_loads(robot_string) + robot2_string = json_dumps(robot2) + for tool in robot2.attached_tools.values(): + assert isinstance(tool, Tool) + assert robot_string == robot2_string + assert len(robot2.attached_tools) == 1 + assert robot2.main_group_name == robot2.main_group_name + + def test_inverse_kinematics_repeated_calls_will_return_next_result(ur5_with_fake_ik): robot = ur5_with_fake_ik From 4c5aa14291acd5088974cc99e8e308d281b42de4 Mon Sep 17 00:00:00 2001 From: Victor LEUNG Date: Thu, 5 Oct 2023 16:48:55 +0800 Subject: [PATCH 08/12] Avoid non str comparision in tests --- tests/robots/test_robot.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/tests/robots/test_robot.py b/tests/robots/test_robot.py index f271e7145..3ae759d21 100644 --- a/tests/robots/test_robot.py +++ b/tests/robots/test_robot.py @@ -297,20 +297,26 @@ def test_semantics_serialization(panda_srdf, panda_urdf): semantics2 = json_loads(semantics_string) assert isinstance(semantics, RobotSemantics) assert isinstance(semantics2, RobotSemantics) - assert ("panda_hand", "panda_link6") in semantics2.disabled_collisions - assert ("panda_hand", "panda_leftfinger") in semantics2.disabled_collisions + for disabled_collision in semantics.disabled_collisions: + assert disabled_collision in semantics2.disabled_collisions def test_robot_serialization(panda_robot_instance): robot = panda_robot_instance + robot.scale(0.001) robot_string = json_dumps(robot) robot2 = json_loads(robot_string) robot2_string = json_dumps(robot2) + assert robot2_string != "" assert isinstance(robot, Robot) assert isinstance(robot2, Robot) - assert robot_string == robot2_string - assert robot.model.data == robot2.model.data - assert robot.attributes == robot2.attributes + assert robot.model.name == robot2.model.name + assert robot._scale_factor == robot2._scale_factor + for index, joint in enumerate(robot.model.joints): + assert joint.name == robot2.model.joints[index].name + assert str(joint.origin) == str(robot2.model.joints[index].origin) + for index, link in enumerate(robot.model.links): + assert link.name == robot2.model.links[index].name def test_robot_serialization_with_tool(ur5_robot_instance, robot_tool1): @@ -319,12 +325,14 @@ def test_robot_serialization_with_tool(ur5_robot_instance, robot_tool1): robot.attach_tool(tool) robot_string = json_dumps(robot) robot2 = json_loads(robot_string) - robot2_string = json_dumps(robot2) for tool in robot2.attached_tools.values(): assert isinstance(tool, Tool) - assert robot_string == robot2_string assert len(robot2.attached_tools) == 1 - assert robot2.main_group_name == robot2.main_group_name + assert robot.main_group_name == robot2.main_group_name + tool1 = robot.attached_tool + tool2 = robot2.attached_tool + assert tool1.name == tool2.name + assert str(tool1.frame) == str(tool2.frame) def test_inverse_kinematics_repeated_calls_will_return_next_result(ur5_with_fake_ik): From 23376ab5c372559f55df417f2d583a64d2a9872d Mon Sep 17 00:00:00 2001 From: Victor LEUNG Date: Mon, 6 Nov 2023 10:38:09 +0800 Subject: [PATCH 09/12] lint --- tests/robots/test_robot.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/robots/test_robot.py b/tests/robots/test_robot.py index 3ae759d21..7f8c6e318 100644 --- a/tests/robots/test_robot.py +++ b/tests/robots/test_robot.py @@ -3,7 +3,8 @@ import re import pytest -from compas.data import json_dumps, json_loads +from compas.data import json_dumps +from compas.data import json_loads from compas.datastructures import Mesh from compas.geometry import Frame from compas.robots import RobotModel @@ -321,10 +322,11 @@ def test_robot_serialization(panda_robot_instance): def test_robot_serialization_with_tool(ur5_robot_instance, robot_tool1): robot = ur5_robot_instance - tool = robot_tool1 - robot.attach_tool(tool) + robot.attach_tool(robot_tool1) + # serialization and deserialization using compas data serialization robot_string = json_dumps(robot) robot2 = json_loads(robot_string) + for tool in robot2.attached_tools.values(): assert isinstance(tool, Tool) assert len(robot2.attached_tools) == 1 From da851d9e7e3cd3731ad34d35763bf100818e529d Mon Sep 17 00:00:00 2001 From: Victor LEUNG Date: Tue, 7 Nov 2023 21:08:26 +0800 Subject: [PATCH 10/12] removed the underscore keys of the serialized dictionary --- src/compas_fab/robots/robot.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/compas_fab/robots/robot.py b/src/compas_fab/robots/robot.py index f585c95a8..b7001533f 100644 --- a/src/compas_fab/robots/robot.py +++ b/src/compas_fab/robots/robot.py @@ -65,9 +65,10 @@ def __init__(self, model=None, artist=None, semantics=None, client=None): @property def data(self): data = { - "_scale_factor": self._scale_factor, - "_attached_tools": self._attached_tools, - "_current_ik": self._current_ik, + "scale_factor": self._scale_factor, + "attached_tools": self._attached_tools, + # The current_ik is an extrinsic state that is not serialized with the robot + # "current_ik": self._current_ik, "model": self.model.data, "semantics": self.semantics, "attributes": self.attributes, @@ -79,9 +80,8 @@ def data(self): @data.setter def data(self, data): - self._scale_factor = data.get("_scale_factor", 1.0) - self._attached_tools = data.get("_attached_tools", {}) - self._current_ik = data.get("_current_ik", {"request_id": None, "solutions": None}) + self._scale_factor = data.get("scale_factor", 1.0) + self._attached_tools = data.get("attached_tools", {}) self.model = RobotModel.from_data(data["model"]) self.semantics = data.get("semantics", None) self.attributes = data.get("attributes", {}) From 0883f0702a81cd37ad8a39b1e093fb4a3144921c Mon Sep 17 00:00:00 2001 From: Victor LEUNG Date: Tue, 7 Nov 2023 21:12:24 +0800 Subject: [PATCH 11/12] group name assertion --- tests/robots/test_robot.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/robots/test_robot.py b/tests/robots/test_robot.py index 7f8c6e318..e5acdbb99 100644 --- a/tests/robots/test_robot.py +++ b/tests/robots/test_robot.py @@ -296,6 +296,9 @@ def test_semantics_serialization(panda_srdf, panda_urdf): semantics = RobotSemantics.from_srdf_file(panda_srdf, model) semantics_string = json_dumps(semantics) semantics2 = json_loads(semantics_string) + assert semantics.main_group_name == semantics2.main_group_name + for group_name in semantics.group_names: + assert group_name in semantics2.group_names assert isinstance(semantics, RobotSemantics) assert isinstance(semantics2, RobotSemantics) for disabled_collision in semantics.disabled_collisions: From 28c814bff13a9b173d6bdf5e579b013dc285d540 Mon Sep 17 00:00:00 2001 From: Victor LEUNG Date: Tue, 7 Nov 2023 14:13:14 +0100 Subject: [PATCH 12/12] simplify comment line Co-authored-by: Gonzalo Casas --- src/compas_fab/robots/robot.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/compas_fab/robots/robot.py b/src/compas_fab/robots/robot.py index f585c95a8..c27231d5c 100644 --- a/src/compas_fab/robots/robot.py +++ b/src/compas_fab/robots/robot.py @@ -71,9 +71,7 @@ def data(self): "model": self.model.data, "semantics": self.semantics, "attributes": self.attributes, - # The following attributes cannnot be serizlied - # "artist": self.artist.data if self.artist else None, - # "client": self.client.data if self.client else None, + # The following attributes cannot be serialized: artist, client } return data