18
18
import subprocess
19
19
import time
20
20
from pathlib import Path
21
- from typing import Any , Dict , Optional
21
+ from typing import Any , Dict , List , Optional
22
22
23
- from geometry_msgs .msg import PoseStamped
23
+ import yaml
24
+ from geometry_msgs .msg import Point , Pose , PoseStamped , Quaternion
24
25
from std_msgs .msg import Header
26
+ from tf2_geometry_msgs import do_transform_pose
25
27
26
- import yaml
27
- from geometry_msgs .msg import Point , Pose , Quaternion
28
28
from rai .communication .ros2 .connectors import ROS2ARIConnector , ROS2ARIMessage
29
- from tf2_geometry_msgs import do_transform_pose
30
29
from rai .utils .ros_async import get_future_result
31
30
from rai_interfaces .srv import ManipulatorMoveTo
32
31
from rai_sim .simulation_bridge import (
44
43
class O3DExROS2SimulationConfig (SimulationConfig ):
45
44
binary_path : Path
46
45
robotic_stack_command : str
46
+ required_services : List [str ]
47
+ required_topics : List [str ]
48
+ required_actions : List [str ]
47
49
48
50
@classmethod
49
51
def load_config (
@@ -203,6 +205,35 @@ def get_scene_state(self) -> SceneState:
203
205
)
204
206
return SceneState (entities = entities )
205
207
208
+ def _is_robotic_stack_ready (
209
+ self , simulation_config : O3DExROS2SimulationConfig
210
+ ) -> bool :
211
+ retries = 0
212
+ while retries < 30 :
213
+ topics = self .connector .get_topics_names_and_types ()
214
+ services = self .connector .node .get_service_names_and_types ()
215
+ topics_names = [tp [0 ] for tp in topics ]
216
+ service_names = [srv [0 ] for srv in services ]
217
+ self .logger .debug (
218
+ f"required services: { simulation_config .required_services } "
219
+ )
220
+ self .logger .debug (f"required topics: { simulation_config .required_topics } " )
221
+ self .logger .debug (f"required actions: { simulation_config .required_actions } " )
222
+ # NOTE actions will be listed in services and topics
223
+ if (
224
+ all (srv in service_names for srv in simulation_config .required_services )
225
+ and all (tp in topics_names for tp in simulation_config .required_topics )
226
+ and all (
227
+ ac in service_names for ac in simulation_config .required_actions
228
+ )
229
+ ):
230
+ self .logger .debug ("All required services are available." )
231
+ return True
232
+
233
+ time .sleep (5 )
234
+ retries += 1
235
+ return False
236
+
206
237
def setup_scene (self , simulation_config : O3DExROS2SimulationConfig ):
207
238
if self .current_binary_path != simulation_config .binary_path :
208
239
if self .current_sim_process :
@@ -215,6 +246,11 @@ def setup_scene(self, simulation_config: O3DExROS2SimulationConfig):
215
246
while self .spawned_entities :
216
247
self ._despawn_entity (self .spawned_entities [0 ])
217
248
249
+ if not self ._is_robotic_stack_ready (simulation_config = simulation_config ):
250
+ raise RuntimeError (
251
+ "Not all required services, topics and actions are available"
252
+ )
253
+
218
254
for entity in simulation_config .entities :
219
255
self ._spawn_entity (entity )
220
256
0 commit comments