luckyrobots 0.1.66__py3-none-any.whl → 0.1.72__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.
- luckyrobots/__init__.py +30 -12
- luckyrobots/client.py +997 -0
- luckyrobots/config/robots.yaml +231 -71
- luckyrobots/engine/__init__.py +23 -0
- luckyrobots/{utils → engine}/check_updates.py +108 -48
- luckyrobots/{utils → engine}/download.py +61 -39
- luckyrobots/engine/manager.py +427 -0
- luckyrobots/grpc/__init__.py +6 -0
- luckyrobots/grpc/generated/__init__.py +18 -0
- luckyrobots/grpc/generated/agent_pb2.py +69 -0
- luckyrobots/grpc/generated/agent_pb2_grpc.py +283 -0
- luckyrobots/grpc/generated/camera_pb2.py +47 -0
- luckyrobots/grpc/generated/camera_pb2_grpc.py +144 -0
- luckyrobots/grpc/generated/common_pb2.py +43 -0
- luckyrobots/grpc/generated/common_pb2_grpc.py +24 -0
- luckyrobots/grpc/generated/hazel_rpc_pb2.py +43 -0
- luckyrobots/grpc/generated/hazel_rpc_pb2_grpc.py +24 -0
- luckyrobots/grpc/generated/media_pb2.py +39 -0
- luckyrobots/grpc/generated/media_pb2_grpc.py +24 -0
- luckyrobots/grpc/generated/mujoco_pb2.py +51 -0
- luckyrobots/grpc/generated/mujoco_pb2_grpc.py +230 -0
- luckyrobots/grpc/generated/scene_pb2.py +66 -0
- luckyrobots/grpc/generated/scene_pb2_grpc.py +317 -0
- luckyrobots/grpc/generated/telemetry_pb2.py +47 -0
- luckyrobots/grpc/generated/telemetry_pb2_grpc.py +143 -0
- luckyrobots/grpc/generated/viewport_pb2.py +50 -0
- luckyrobots/grpc/generated/viewport_pb2_grpc.py +144 -0
- luckyrobots/grpc/proto/agent.proto +213 -0
- luckyrobots/grpc/proto/camera.proto +41 -0
- luckyrobots/grpc/proto/common.proto +36 -0
- luckyrobots/grpc/proto/hazel_rpc.proto +32 -0
- luckyrobots/grpc/proto/media.proto +26 -0
- luckyrobots/grpc/proto/mujoco.proto +64 -0
- luckyrobots/grpc/proto/scene.proto +104 -0
- luckyrobots/grpc/proto/telemetry.proto +43 -0
- luckyrobots/grpc/proto/viewport.proto +45 -0
- luckyrobots/luckyrobots.py +252 -0
- luckyrobots/models/__init__.py +15 -0
- luckyrobots/models/camera.py +97 -0
- luckyrobots/models/observation.py +135 -0
- luckyrobots/models/randomization.py +77 -0
- luckyrobots/{utils/helpers.py → utils.py} +75 -40
- luckyrobots-0.1.72.dist-info/METADATA +262 -0
- luckyrobots-0.1.72.dist-info/RECORD +47 -0
- {luckyrobots-0.1.66.dist-info → luckyrobots-0.1.72.dist-info}/WHEEL +1 -1
- luckyrobots/core/luckyrobots.py +0 -624
- luckyrobots/core/manager.py +0 -236
- luckyrobots/core/models.py +0 -68
- luckyrobots/core/node.py +0 -273
- luckyrobots/message/__init__.py +0 -18
- luckyrobots/message/pubsub.py +0 -145
- luckyrobots/message/srv/client.py +0 -81
- luckyrobots/message/srv/service.py +0 -135
- luckyrobots/message/srv/types.py +0 -83
- luckyrobots/message/transporter.py +0 -427
- luckyrobots/utils/event_loop.py +0 -94
- luckyrobots/utils/sim_manager.py +0 -406
- luckyrobots-0.1.66.dist-info/METADATA +0 -253
- luckyrobots-0.1.66.dist-info/RECORD +0 -24
- {luckyrobots-0.1.66.dist-info → luckyrobots-0.1.72.dist-info}/licenses/LICENSE +0 -0
luckyrobots/message/pubsub.py
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Publisher/subscriber implementation with WebSocket transport.
|
|
3
|
-
|
|
4
|
-
This module provides Publisher and Subscriber classes for implementing
|
|
5
|
-
publisher/subscriber patterns with WebSocket transport for distributed
|
|
6
|
-
communication.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
import logging
|
|
10
|
-
import threading
|
|
11
|
-
from typing import Any, Callable, Dict, List, Type
|
|
12
|
-
|
|
13
|
-
logging.basicConfig(
|
|
14
|
-
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
15
|
-
)
|
|
16
|
-
logger = logging.getLogger("pubsub")
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class Publisher:
|
|
20
|
-
# Class dictionary to keep track of all publishers by topic
|
|
21
|
-
_publishers_by_topic: Dict[str, List["Publisher"]] = {}
|
|
22
|
-
_lock = threading.RLock()
|
|
23
|
-
|
|
24
|
-
def __init__(self, topic: str, message_type: Type, queue_size: int = 10):
|
|
25
|
-
self.topic = topic
|
|
26
|
-
self.message_type = message_type
|
|
27
|
-
self.queue_size = queue_size
|
|
28
|
-
self._subscribers: List[Callable[[Any], None]] = []
|
|
29
|
-
|
|
30
|
-
# Register this publisher in the class dictionary
|
|
31
|
-
with Publisher._lock:
|
|
32
|
-
if topic not in Publisher._publishers_by_topic:
|
|
33
|
-
Publisher._publishers_by_topic[topic] = []
|
|
34
|
-
Publisher._publishers_by_topic[topic].append(self)
|
|
35
|
-
|
|
36
|
-
logger.debug(f"Created publisher for topic: {topic}")
|
|
37
|
-
|
|
38
|
-
def __del__(self):
|
|
39
|
-
"""Delete the publisher"""
|
|
40
|
-
with Publisher._lock:
|
|
41
|
-
if self.topic in Publisher._publishers_by_topic:
|
|
42
|
-
if self in Publisher._publishers_by_topic[self.topic]:
|
|
43
|
-
Publisher._publishers_by_topic[self.topic].remove(self)
|
|
44
|
-
if not Publisher._publishers_by_topic[self.topic]:
|
|
45
|
-
del Publisher._publishers_by_topic[self.topic]
|
|
46
|
-
|
|
47
|
-
def publish(self, message: Any) -> None:
|
|
48
|
-
# Type check the message
|
|
49
|
-
if not isinstance(message, self.message_type):
|
|
50
|
-
raise TypeError(
|
|
51
|
-
f"Expected message of type {self.message_type.__name__}, got {type(message).__name__}"
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
# Publish to all local subscribers
|
|
55
|
-
for subscriber in self._subscribers:
|
|
56
|
-
try:
|
|
57
|
-
subscriber(message)
|
|
58
|
-
except Exception as e:
|
|
59
|
-
logger.error(
|
|
60
|
-
f"Error in subscriber callback for topic {self.topic}: {e}"
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
# Note: Remote publishing is handled by the Node class, which
|
|
64
|
-
# wraps this publish method to publish to the WebSocket transport
|
|
65
|
-
|
|
66
|
-
def add_subscriber(self, subscriber: Callable[[Any], None]) -> None:
|
|
67
|
-
"""Add a subscriber to the publisher"""
|
|
68
|
-
if subscriber not in self._subscribers:
|
|
69
|
-
self._subscribers.append(subscriber)
|
|
70
|
-
logger.debug(f"Added subscriber to topic: {self.topic}")
|
|
71
|
-
|
|
72
|
-
def remove_subscriber(self, subscriber: Callable[[Any], None]) -> None:
|
|
73
|
-
"""Remove a subscriber from the publisher"""
|
|
74
|
-
if subscriber in self._subscribers:
|
|
75
|
-
self._subscribers.remove(subscriber)
|
|
76
|
-
logger.debug(f"Removed subscriber from topic: {self.topic}")
|
|
77
|
-
|
|
78
|
-
@classmethod
|
|
79
|
-
def get_publishers_for_topic(cls, topic: str) -> List["Publisher"]:
|
|
80
|
-
"""Get all publishers for a given topic"""
|
|
81
|
-
with cls._lock:
|
|
82
|
-
return cls._publishers_by_topic.get(topic, [])
|
|
83
|
-
|
|
84
|
-
@classmethod
|
|
85
|
-
def get_all_topics(cls) -> List[str]:
|
|
86
|
-
"""Get all topics"""
|
|
87
|
-
with cls._lock:
|
|
88
|
-
return list(cls._publishers_by_topic.keys())
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
class Subscriber:
|
|
92
|
-
# Class dictionary to keep track of all subscribers
|
|
93
|
-
_subscribers_by_topic: Dict[str, List["Subscriber"]] = {}
|
|
94
|
-
_lock = threading.RLock()
|
|
95
|
-
|
|
96
|
-
def __init__(
|
|
97
|
-
self,
|
|
98
|
-
topic: str,
|
|
99
|
-
message_type: Type,
|
|
100
|
-
callback: Callable[[Any], None],
|
|
101
|
-
queue_size: int = 10,
|
|
102
|
-
):
|
|
103
|
-
self.topic = topic
|
|
104
|
-
self.message_type = message_type
|
|
105
|
-
self.callback = callback
|
|
106
|
-
self.queue_size = queue_size
|
|
107
|
-
|
|
108
|
-
# Find publishers for this topic and subscribe
|
|
109
|
-
self._connect_to_publishers()
|
|
110
|
-
|
|
111
|
-
# Register this subscriber in the class dictionary
|
|
112
|
-
with Subscriber._lock:
|
|
113
|
-
if topic not in Subscriber._subscribers_by_topic:
|
|
114
|
-
Subscriber._subscribers_by_topic[topic] = []
|
|
115
|
-
Subscriber._subscribers_by_topic[topic].append(self)
|
|
116
|
-
|
|
117
|
-
logger.debug(f"Created subscriber for topic: {topic}")
|
|
118
|
-
|
|
119
|
-
def __del__(self):
|
|
120
|
-
"""Delete the subscriber"""
|
|
121
|
-
# Unsubscribe from all publishers
|
|
122
|
-
publishers = Publisher.get_publishers_for_topic(self.topic)
|
|
123
|
-
for publisher in publishers:
|
|
124
|
-
publisher.remove_subscriber(self.callback)
|
|
125
|
-
|
|
126
|
-
# Remove from class dictionary
|
|
127
|
-
with Subscriber._lock:
|
|
128
|
-
if self.topic in Subscriber._subscribers_by_topic:
|
|
129
|
-
if self in Subscriber._subscribers_by_topic[self.topic]:
|
|
130
|
-
Subscriber._subscribers_by_topic[self.topic].remove(self)
|
|
131
|
-
if not Subscriber._subscribers_by_topic[self.topic]:
|
|
132
|
-
del Subscriber._subscribers_by_topic[self.topic]
|
|
133
|
-
|
|
134
|
-
def _connect_to_publishers(self) -> None:
|
|
135
|
-
"""Connect to all publishers for a given topic"""
|
|
136
|
-
publishers = Publisher.get_publishers_for_topic(self.topic)
|
|
137
|
-
for publisher in publishers:
|
|
138
|
-
if publisher.message_type == self.message_type:
|
|
139
|
-
publisher.add_subscriber(self.callback)
|
|
140
|
-
|
|
141
|
-
@classmethod
|
|
142
|
-
def get_subscribers_for_topic(cls, topic: str) -> List["Subscriber"]:
|
|
143
|
-
"""Get all subscribers for a given topic"""
|
|
144
|
-
with cls._lock:
|
|
145
|
-
return cls._subscribers_by_topic.get(topic, [])
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
from typing import Generic, Optional, Type, TypeVar
|
|
3
|
-
|
|
4
|
-
from .service import (
|
|
5
|
-
ServiceNotFoundError,
|
|
6
|
-
ServiceServer,
|
|
7
|
-
)
|
|
8
|
-
|
|
9
|
-
T = TypeVar("T") # Request type
|
|
10
|
-
R = TypeVar("R") # Response type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class ServiceClient(Generic[T, R]):
|
|
14
|
-
def __init__(self, service_type: Type[T], service_name: str):
|
|
15
|
-
# ServiceClient attributes
|
|
16
|
-
self.service_type = service_type
|
|
17
|
-
self.service_name = service_name
|
|
18
|
-
|
|
19
|
-
# Initialize the ServiceServer object
|
|
20
|
-
self._service: Optional[ServiceServer] = None
|
|
21
|
-
|
|
22
|
-
async def connect(self, retry_count: int = 3, retry_delay: float = 1.0) -> bool:
|
|
23
|
-
"""Connect to the service server"""
|
|
24
|
-
for attempt in range(retry_count):
|
|
25
|
-
self._service = ServiceServer.get_service(self.service_name)
|
|
26
|
-
if self._service is not None:
|
|
27
|
-
return True
|
|
28
|
-
|
|
29
|
-
if attempt < retry_count - 1:
|
|
30
|
-
await asyncio.sleep(retry_delay)
|
|
31
|
-
|
|
32
|
-
return False
|
|
33
|
-
|
|
34
|
-
async def call(
|
|
35
|
-
self, request: T, service_name: str = None, timeout: float = 30.0
|
|
36
|
-
) -> R:
|
|
37
|
-
"""Call the service server"""
|
|
38
|
-
# Default to the client's service name if none provided
|
|
39
|
-
if service_name is None:
|
|
40
|
-
service_name = self.service_name
|
|
41
|
-
|
|
42
|
-
if self.service_name != service_name:
|
|
43
|
-
raise ValueError(
|
|
44
|
-
f"Service name mismatch. Expected {self.service_name}, got {service_name}"
|
|
45
|
-
)
|
|
46
|
-
|
|
47
|
-
# Validate request type if possible
|
|
48
|
-
request_type = getattr(self.service_type, "Request", self.service_type)
|
|
49
|
-
if not isinstance(request, request_type):
|
|
50
|
-
raise TypeError(
|
|
51
|
-
f"Expected request of type {request_type.__name__}, got {type(request).__name__}"
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
if self._service is None:
|
|
55
|
-
connected = await self.connect()
|
|
56
|
-
if not connected:
|
|
57
|
-
raise ServiceNotFoundError(f"Service {self.service_name} not found")
|
|
58
|
-
|
|
59
|
-
# Check service type compatibility if possible
|
|
60
|
-
if (
|
|
61
|
-
hasattr(self.service_type, "Request")
|
|
62
|
-
and hasattr(self._service.service_type, "Request")
|
|
63
|
-
and self.service_type.Request != self._service.service_type.Request
|
|
64
|
-
):
|
|
65
|
-
raise TypeError(
|
|
66
|
-
f"Service request type mismatch. Expected {self.service_type.Request.__name__}, "
|
|
67
|
-
f"got {self._service.service_type.Request.__name__}"
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
if (
|
|
71
|
-
hasattr(self.service_type, "Response")
|
|
72
|
-
and hasattr(self._service.service_type, "Response")
|
|
73
|
-
and self.service_type.Response != self._service.service_type.Response
|
|
74
|
-
):
|
|
75
|
-
raise TypeError(
|
|
76
|
-
f"Service response type mismatch. Expected {self.service_type.Response.__name__}, "
|
|
77
|
-
f"got {self._service.service_type.Response.__name__}"
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
# Call the service server
|
|
81
|
-
return await self._service.call(request, service_name, timeout=timeout)
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import logging
|
|
3
|
-
from typing import Callable, Dict, Generic, List, Optional, Type, TypeVar
|
|
4
|
-
|
|
5
|
-
logging.basicConfig(
|
|
6
|
-
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
7
|
-
)
|
|
8
|
-
logger = logging.getLogger("service")
|
|
9
|
-
|
|
10
|
-
T = TypeVar("T") # Request type
|
|
11
|
-
R = TypeVar("R") # Response type
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class ServiceError(Exception):
|
|
15
|
-
"""Base exception for service-related errors"""
|
|
16
|
-
|
|
17
|
-
pass
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class ServiceTimeoutError(ServiceError):
|
|
21
|
-
"""Exception raised when a service call times out"""
|
|
22
|
-
|
|
23
|
-
pass
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class ServiceNotFoundError(ServiceError):
|
|
27
|
-
"""Exception raised when a service is not found"""
|
|
28
|
-
|
|
29
|
-
pass
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class ServiceHandlerError(ServiceError):
|
|
33
|
-
"""Exception raised when a service handler raises an exception"""
|
|
34
|
-
|
|
35
|
-
pass
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class ServiceServer(Generic[T, R]):
|
|
39
|
-
"""Enhanced service implementation with timeout and error handling"""
|
|
40
|
-
|
|
41
|
-
# Class dictionary to keep track of all services
|
|
42
|
-
_services: Dict[str, "ServiceServer"] = {}
|
|
43
|
-
_lock = asyncio.Lock()
|
|
44
|
-
|
|
45
|
-
def __init__(
|
|
46
|
-
self, service_type: Type[T], service_name: str, handler: Callable[[T], R]
|
|
47
|
-
):
|
|
48
|
-
self._handler: Optional[Callable[[T], R]] = None
|
|
49
|
-
|
|
50
|
-
self.service_type = service_type
|
|
51
|
-
self.service_name = service_name
|
|
52
|
-
|
|
53
|
-
self.set_handler(handler)
|
|
54
|
-
|
|
55
|
-
# Register this service in the class dictionary
|
|
56
|
-
ServiceServer._services[service_name] = self
|
|
57
|
-
|
|
58
|
-
logger.debug(f"Created service: {service_name}")
|
|
59
|
-
|
|
60
|
-
def set_handler(self, handler: Callable[[T], R]) -> None:
|
|
61
|
-
"""Set the handler for the service"""
|
|
62
|
-
self._handler = handler
|
|
63
|
-
logger.debug(f"Set handler for service: {self.service_name}")
|
|
64
|
-
|
|
65
|
-
async def call(self, request: T, service_name: str, timeout: float = 30.0) -> R:
|
|
66
|
-
"""Call the service"""
|
|
67
|
-
if self.service_name != service_name:
|
|
68
|
-
raise ValueError(
|
|
69
|
-
f"Service name mismatch. Expected {self.service_name}, got {service_name}"
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
# Validate the request type if possible
|
|
73
|
-
request_type = getattr(self.service_type, "Request")
|
|
74
|
-
if not isinstance(request, request_type):
|
|
75
|
-
raise TypeError(
|
|
76
|
-
f"Expected request of type {request_type.__name__}, got {type(request).__name__}"
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
if self._handler is None:
|
|
80
|
-
raise ServiceNotFoundError(
|
|
81
|
-
f"No handler set for service {self.service_name}"
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
try:
|
|
85
|
-
# Run the handler with timeout
|
|
86
|
-
return await asyncio.wait_for(self._run_handler(request), timeout=timeout)
|
|
87
|
-
except asyncio.TimeoutError:
|
|
88
|
-
raise ServiceTimeoutError(
|
|
89
|
-
f"Service call to {self.service_name} timed out after {timeout} seconds"
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
async def _run_handler(self, request: T) -> R:
|
|
93
|
-
"""Run the server handler and handle exceptions"""
|
|
94
|
-
try:
|
|
95
|
-
# If handler is already a coroutine function, await it
|
|
96
|
-
if asyncio.iscoroutinefunction(self._handler):
|
|
97
|
-
result = await self._handler(request)
|
|
98
|
-
else:
|
|
99
|
-
# Run non-async handler in a thread pool
|
|
100
|
-
loop = asyncio.get_event_loop()
|
|
101
|
-
result = await loop.run_in_executor(None, self._handler, request)
|
|
102
|
-
|
|
103
|
-
# Type check the result if possible
|
|
104
|
-
response_type = getattr(self.service_type, "Response", None)
|
|
105
|
-
if response_type and not isinstance(result, response_type):
|
|
106
|
-
raise TypeError(
|
|
107
|
-
f"Service {self.service_name} returned {type(result).__name__}, expected {response_type.__name__}"
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
return result
|
|
111
|
-
except Exception as e:
|
|
112
|
-
logger.error(f"Error in service handler for {self.service_name}: {e}")
|
|
113
|
-
raise ServiceHandlerError(
|
|
114
|
-
f"Service handler for {self.service_name} raised an exception: {e}"
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
@classmethod
|
|
118
|
-
def get_service(cls, service_name: str) -> Optional["ServiceServer"]:
|
|
119
|
-
"""Get a service by name"""
|
|
120
|
-
return cls._services.get(service_name)
|
|
121
|
-
|
|
122
|
-
@classmethod
|
|
123
|
-
def get_all_services(cls) -> List[str]:
|
|
124
|
-
"""Get all services"""
|
|
125
|
-
return list(cls._services.keys())
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def get_service(name: str) -> Optional[ServiceServer]:
|
|
129
|
-
"""External helper function to get a service by name"""
|
|
130
|
-
return ServiceServer.get_service(name)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
def get_all_services() -> List[str]:
|
|
134
|
-
"""External helper function to get all services"""
|
|
135
|
-
return ServiceServer.get_all_services()
|
luckyrobots/message/srv/types.py
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
"""Data models for messaging system.
|
|
2
|
-
|
|
3
|
-
This module defines the data models used for request and response messaging.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from typing import Any, Dict, Optional
|
|
7
|
-
from ...core.models import ObservationModel
|
|
8
|
-
|
|
9
|
-
from pydantic import BaseModel, Field
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class ServiceRequest(BaseModel):
|
|
13
|
-
"""Base class for service requests"""
|
|
14
|
-
|
|
15
|
-
pass
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class ServiceResponse(BaseModel):
|
|
19
|
-
"""Base class for service responses"""
|
|
20
|
-
|
|
21
|
-
success: bool = Field(
|
|
22
|
-
default=True, description="Whether the service call was successful"
|
|
23
|
-
)
|
|
24
|
-
message: str = Field(
|
|
25
|
-
default="", description="A message describing the service call"
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
request_type: str = Field(
|
|
29
|
-
description="Type of response (reset_response or step_response)"
|
|
30
|
-
)
|
|
31
|
-
request_id: str = Field(description="Unique identifier")
|
|
32
|
-
time_stamp: str = Field(alias="timeStamp", description="Timestamp value")
|
|
33
|
-
|
|
34
|
-
observation: ObservationModel = Field(description="Observation data")
|
|
35
|
-
info: Dict[str, str] = Field(description="Additional information")
|
|
36
|
-
|
|
37
|
-
class Config:
|
|
38
|
-
populate_by_name = True
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
class ResetRequest(ServiceRequest):
|
|
42
|
-
"""Request to reset the robot"""
|
|
43
|
-
|
|
44
|
-
seed: Optional[int] = Field(
|
|
45
|
-
default=None, description="The seed to reset the robot with"
|
|
46
|
-
)
|
|
47
|
-
options: Optional[Dict[str, Any]] = Field(
|
|
48
|
-
default=None, description="Options for the reset"
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
class ResetResponse(ServiceResponse):
|
|
53
|
-
"""Response to reset request"""
|
|
54
|
-
|
|
55
|
-
pass
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class Reset:
|
|
59
|
-
"""Reset the robot"""
|
|
60
|
-
|
|
61
|
-
Request = ResetRequest
|
|
62
|
-
Response = ResetResponse
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class StepRequest(ServiceRequest):
|
|
66
|
-
"""Request to step the robot with an action"""
|
|
67
|
-
|
|
68
|
-
actuator_values: list = Field(
|
|
69
|
-
description="The array of actuator values to control the robot with"
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
class StepResponse(ServiceResponse):
|
|
74
|
-
"""Response to step request"""
|
|
75
|
-
|
|
76
|
-
pass
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
class Step:
|
|
80
|
-
"""Step the robot with an action"""
|
|
81
|
-
|
|
82
|
-
Request = StepRequest
|
|
83
|
-
Response = StepResponse
|