Skip to content

Commit 88899fa

Browse files
authored
Merge pull request #135 from ichumuh/main
Implemented MinimalRobot
2 parents 334da29 + bceb89d commit 88899fa

3 files changed

Lines changed: 89 additions & 14 deletions

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from __future__ import annotations
2+
3+
from collections import defaultdict
4+
from dataclasses import dataclass
5+
from typing import Self
6+
7+
from ..datastructures.prefixed_name import PrefixedName
8+
from ..robots.abstract_robot import (
9+
AbstractRobot,
10+
)
11+
from ..world import World
12+
from ..world_description.world_entity import Body
13+
14+
15+
@dataclass
16+
class MinimalRobot(AbstractRobot):
17+
"""
18+
Creates the bare minimum semantic annotation.
19+
Used when you only care that there is a robot.
20+
"""
21+
22+
def __hash__(self):
23+
return hash(
24+
tuple(
25+
[self.__class__]
26+
+ sorted([kse.name for kse in self.kinematic_structure_entities])
27+
)
28+
)
29+
30+
def load_srdf(self):
31+
pass
32+
33+
@classmethod
34+
def from_world(cls, world: World) -> Self:
35+
"""
36+
Creates a minimal semantic robot annotation from the given world, starting at root_body
37+
"""
38+
39+
with world.modify_world():
40+
robot = cls(
41+
name=PrefixedName(name="generic_robot", prefix=world.name),
42+
root=world.root,
43+
_world=world,
44+
)
45+
46+
world.add_semantic_annotation(robot, skip_duplicates=True)
47+
48+
vel_limits = defaultdict(lambda: 1.0)
49+
robot.tighten_dof_velocity_limits_of_1dof_connections(new_limits=vel_limits)
50+
51+
return robot

src/semantic_digital_twin/testing.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,17 @@
22
import threading
33
import time
44

5+
import pytest
56
from krrood.entity_query_language.symbol_graph import SymbolGraph
6-
from krrood.entity_query_language.symbolic import Variable
77
from typing_extensions import Tuple
88

9-
import pytest
10-
119
from .adapters.urdf import URDFParser
10+
from .datastructures.prefixed_name import PrefixedName
11+
from .spatial_types import TransformationMatrix
12+
from .spatial_types.derivatives import DerivativeMap
13+
from .spatial_types.spatial_types import Vector3
1214
from .utils import rclpy_installed, tracy_installed, hsrb_installed
15+
from .world import World
1316
from .world_description.connections import (
1417
Connection6DoF,
1518
PrismaticConnection,
@@ -19,13 +22,8 @@
1922
)
2023
from .world_description.degree_of_freedom import DegreeOfFreedom
2124
from .world_description.geometry import Box, Scale, Sphere
22-
from .datastructures.prefixed_name import PrefixedName
23-
from .spatial_types import TransformationMatrix
24-
from .spatial_types.derivatives import DerivativeMap
25-
from .spatial_types.spatial_types import Vector3
26-
from .world import World
2725
from .world_description.shape_collection import ShapeCollection
28-
from .world_description.world_entity import KinematicStructureEntity, Body
26+
from .world_description.world_entity import Body
2927

3028

3129
@pytest.fixture
@@ -286,6 +284,7 @@ def cleanup_after_test():
286284
# Teardown: runs after each test
287285
SymbolGraph().clear()
288286

287+
289288
@pytest.fixture()
290289
def kitchen_world():
291290
path = os.path.join(

test/test_semantic_annotations/test_semantic_annotations.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,13 @@
77
) # You could replace this with numpy's regular assert for better compatibility
88

99
from semantic_digital_twin.reasoning.world_reasoner import WorldReasoner
10-
from semantic_digital_twin.testing import *
10+
from semantic_digital_twin.robots.minimal_robot import MinimalRobot
11+
from semantic_digital_twin.robots.pr2 import PR2
1112
from semantic_digital_twin.semantic_annotations.semantic_annotations import *
13+
from semantic_digital_twin.testing import *
14+
from semantic_digital_twin.world_description.world_entity import (
15+
KinematicStructureEntity,
16+
)
1217

1318
try:
1419
from ripple_down_rules.user_interface.gui import RDRCaseViewer
@@ -131,10 +136,7 @@ def test_aggregate_bodies(kitchen_world):
131136

132137
def test_handle_semantic_annotation_eql(apartment_world):
133138
with rule_mode():
134-
body = let(
135-
type_=Body,
136-
domain=apartment_world.bodies
137-
)
139+
body = let(type_=Body, domain=apartment_world.bodies)
138140
query = infer(entity(Handle(body=body), in_("handle", body.name.name.lower())))
139141

140142
handles = list(query.evaluate())
@@ -251,3 +253,26 @@ def test_semantic_annotation_serde_multiple(apartment_world):
251253
assert door == door_de2
252254
assert type(door.handle) == type(door_de2.handle)
253255
assert type(door.body) == type(door_de2.body)
256+
257+
258+
def test_minimal_robot_annotation(pr2_world):
259+
urdf_dir = os.path.join(
260+
os.path.dirname(os.path.abspath(__file__)), "..", "..", "resources", "urdf"
261+
)
262+
pr2 = os.path.join(urdf_dir, "pr2_kinematic_tree.urdf")
263+
pr2_parser = URDFParser.from_file(file_path=pr2)
264+
world_with_pr2 = pr2_parser.parse()
265+
with world_with_pr2.modify_world():
266+
MinimalRobot.from_world(world_with_pr2)
267+
pr2_root = world_with_pr2.root
268+
localization_body = Body(name=PrefixedName("odom_combined"))
269+
world_with_pr2.add_kinematic_structure_entity(localization_body)
270+
c_root_bf = OmniDrive.create_with_dofs(
271+
parent=localization_body, child=pr2_root, world=world_with_pr2
272+
)
273+
world_with_pr2.add_connection(c_root_bf)
274+
275+
robot = world_with_pr2.get_semantic_annotations_by_type(MinimalRobot)[0]
276+
pr2 = PR2.from_world(pr2_world)
277+
assert len(robot.bodies) == len(pr2.bodies)
278+
assert len(robot.connections) == len(pr2.connections)

0 commit comments

Comments
 (0)