11"""Dora node that test waypoint mission completions using the robot pose."""
22
3- import time
4-
53import msgs
64import pytest
75
6+ from tester .stuck_detector import StuckDetector
87from tester .transforms import Transforms
98
109
@@ -20,22 +19,28 @@ def test_receives_scene_info_on_startup(node):
2019
2120@pytest .mark .parametrize ("difficulty" , [0.1 , 0.7 , 1.1 ])
2221@pytest .mark .clock_timeout (30 )
23- def test_completes_waypoint_mission_with_variable_height_steps (node , difficulty : float ):
22+ def test_completes_waypoint_mission_with_variable_height_steps (
23+ node , difficulty : float , metrics : dict
24+ ):
2425 """Test that the waypoint mission completes successfully.
2526
2627 The pyramid steps height is configured via difficulty.
2728 """
28- run_waypoint_mission_test (node , scene = "generated_pyramid" , difficulty = difficulty )
29+ run_waypoint_mission_test (
30+ node , scene = "generated_pyramid" , difficulty = difficulty , metrics = metrics
31+ )
2932
3033
3134@pytest .mark .parametrize ("scene" , ["rail_blocks" , "stone_stairs" , "excavator" ])
3235@pytest .mark .clock_timeout (30 )
33- def test_completes_waypoint_mission_in_photo_realistic_env (node , scene : str ):
36+ def test_completes_waypoint_mission_in_photo_realistic_env (
37+ node , scene : str , metrics : dict
38+ ):
3439 """Test that the waypoint mission completes successfully."""
35- run_waypoint_mission_test (node , scene , difficulty = 1.0 )
40+ run_waypoint_mission_test (node , scene , difficulty = 1.0 , metrics = metrics )
3641
3742
38- def run_waypoint_mission_test (node , scene : str , difficulty : float ):
43+ def run_waypoint_mission_test (node , scene : str , difficulty : float , metrics : dict ):
3944 """Run the waypoint mission test."""
4045 transforms = Transforms ()
4146 node .send_output (
@@ -45,7 +50,22 @@ def run_waypoint_mission_test(node, scene: str, difficulty: float):
4550 waypoint_list : list [str ] = []
4651 next_waypoint_index = 0
4752
53+ metrics_key = f"completion_time.{ scene } _{ difficulty } "
54+ start_time_ms = None
55+ current_time_ms = None
56+ stuck_detector = StuckDetector (max_no_progress_time = 5000 ) # 5 seconds
57+
4858 for event in node :
59+ if event ["type" ] == "INPUT" and event ["id" ] == "clock" :
60+ now = msgs .Timestamp .from_arrow (event ["value" ]).float_milliseconds
61+ if start_time_ms is None or now < start_time_ms :
62+ start_time_ms = now
63+ current_time_ms = now
64+
65+ # Bail if we haven't started yet
66+ if current_time_ms is None :
67+ continue
68+
4969 if event ["type" ] == "INPUT" and event ["id" ] == "waypoints" :
5070 waypoint_list_msg = msgs .WaypointList .from_arrow (event ["value" ])
5171 waypoints = waypoint_list_msg .waypoints
@@ -60,7 +80,7 @@ def run_waypoint_mission_test(node, scene: str, difficulty: float):
6080
6181 transforms .add_transform (
6282 wp .transform ,
63- int (time . time () ),
83+ int (current_time_ms ),
6484 parent_frame = "world" ,
6585 child_frame = waypoint_frame ,
6686 )
@@ -71,7 +91,7 @@ def run_waypoint_mission_test(node, scene: str, difficulty: float):
7191 continue
7292
7393 transform = msgs .Transform .from_arrow (event ["value" ])
74- timestamp = int (time . time () )
94+ timestamp = int (current_time_ms )
7595 transforms .add_transform (
7696 transform ,
7797 timestamp ,
@@ -95,3 +115,13 @@ def run_waypoint_mission_test(node, scene: str, difficulty: float):
95115 else :
96116 print ("All waypoints completed!" )
97117 break
118+
119+ if stuck_detector .step_is_stuck (transform , timestamp ):
120+ raise AssertionError (
121+ "Robot is stuck and cannot complete the waypoint mission."
122+ )
123+
124+ if start_time_ms is not None and current_time_ms is not None :
125+ elapsed_time_ms = current_time_ms - start_time_ms
126+ # Convert to seconds
127+ metrics [metrics_key ] = elapsed_time_ms / 1000.0
0 commit comments