@@ -72,35 +72,33 @@ def __init__(
7272
7373 @override
7474 def set_world_state (self , world_state : WorldState ):
75- """Send move tactics to robots to the positions in the given world state.
75+ """Send move tactics to drive the friendly robots to the positions in
76+ the given world state.
7677
7778 :param world_state: The WorldState proto with the desired robot states
7879 """
79- self .set_tactics (
80- blue_tactics = self ._create_move_tactics (world_state .blue_robots ),
81- yellow_tactics = self ._create_move_tactics (world_state .yellow_robots ),
80+ friendly_move_tactics = self ._create_move_tactics (
81+ world_state .yellow_robots
82+ if self .is_yellow_friendly
83+ else world_state .blue_robots
8284 )
8385
86+ if self .is_yellow_friendly :
87+ self .set_tactics (blue_tactics = None , yellow_tactics = friendly_move_tactics )
88+ else :
89+ self .set_tactics (blue_tactics = friendly_move_tactics , yellow_tactics = None )
90+
8491 self ._wait_for_robots_at_world_state (world_state )
8592
8693 @override
8794 def set_tactics (self , blue_tactics = {}, yellow_tactics = {}):
88- """Override AI tactics, remapping each team's simulated robot ids to the
89- robot ids that are actually available on the field.
95+ """Override AI tactics, remapping the friendly team's simulated robot ids
96+ to the robot ids that are actually available on the field.
9097 """
9198 if self .is_yellow_friendly :
92- blue_sim_to_field_id = self .enemy_sim_to_field_id
93- yellow_sim_to_field_id = self .friendly_sim_to_field_id
99+ yellow_tactics = self ._map_tactics_to_field_ids (yellow_tactics )
94100 else :
95- blue_sim_to_field_id = self .friendly_sim_to_field_id
96- yellow_sim_to_field_id = self .enemy_sim_to_field_id
97-
98- blue_tactics = self ._map_tactics_to_field_ids (
99- blue_tactics , blue_sim_to_field_id , "blue"
100- )
101- yellow_tactics = self ._map_tactics_to_field_ids (
102- yellow_tactics , yellow_sim_to_field_id , "yellow"
103- )
101+ blue_tactics = self ._map_tactics_to_field_ids (blue_tactics )
104102
105103 super ().set_tactics (blue_tactics = blue_tactics , yellow_tactics = yellow_tactics )
106104
@@ -214,21 +212,16 @@ def _survey_field_robots(self):
214212 # survey field for available robot ids
215213 survey_start_time = time .time ()
216214 self .friendly_robot_ids_field = []
217- self .enemy_robot_ids_field = []
218215 while time .time () - survey_start_time < WORLD_BUFFER_TIMEOUT :
219216 try :
220217 world = self .world_buffer .get (block = True , timeout = 0.1 )
221218 self .initial_world = world
222219 self .friendly_robot_ids_field = [
223220 robot .id for robot in world .friendly_team .team_robots
224221 ]
225- self .enemy_robot_ids_field = [
226- robot .id for robot in world .enemy_team .team_robots
227- ]
228222
229223 if len (self .friendly_robot_ids_field ) > 0 :
230224 logger .info (f"friendly team ids { self .friendly_robot_ids_field } " )
231- logger .info (f"enemy team ids { self .enemy_robot_ids_field } " )
232225 break
233226 except queue .Empty :
234227 continue
@@ -239,41 +232,20 @@ def _survey_field_robots(self):
239232 # Simulated tests create robots with contiguous ids (0, 1, 2, ...), but
240233 # the robots physically on the field may have arbitrary ids and there may
241234 # be fewer of them. Map each simulated id to an available field id, in
242- # ascending order and per team, so tactics and validations written against
243- # simulated ids refer to the robots that are actually present. e.g. field
244- # robots [4, 5] map simulated id 0 -> 4 and 1 -> 5; field robots [0, 1, 5]
245- # map 0 -> 0, 1 -> 1 and 2 -> 5.
246- self .friendly_sim_to_field_id = self ._build_sim_to_field_mapping (
247- self .friendly_robot_ids_field
248- )
249- self .enemy_sim_to_field_id = self ._build_sim_to_field_mapping (
250- self .enemy_robot_ids_field
251- )
252- # Inverse mappings, used to relabel the world's field ids back to the
253- # simulated ids that validations are written against.
254- self .friendly_field_to_sim_id = {
255- field_id : sim_id
256- for sim_id , field_id in self .friendly_sim_to_field_id .items ()
235+ # ascending order, so tactics written against simulated ids are sent to
236+ # the robots that are actually present. e.g. field robots [4, 5] map
237+ # simulated id 0 -> 4 and 1 -> 5; field robots [0, 1, 5] map 0 -> 0,
238+ # 1 -> 1 and 2 -> 5.
239+ self .sim_to_field_robot_id = {
240+ sim_id : field_id
241+ for sim_id , field_id in enumerate (sorted (self .friendly_robot_ids_field ))
257242 }
258- self .enemy_field_to_sim_id = {
259- field_id : sim_id for sim_id , field_id in self .enemy_sim_to_field_id .items ()
243+ # Inverse mapping, used to relabel the world's field ids back to the
244+ # simulated ids that validations are written against.
245+ self .field_to_sim_robot_id = {
246+ field_id : sim_id for sim_id , field_id in self .sim_to_field_robot_id .items ()
260247 }
261- logger .info (
262- f"friendly simulated id to field id mapping { self .friendly_sim_to_field_id } "
263- )
264- logger .info (
265- f"enemy simulated id to field id mapping { self .enemy_sim_to_field_id } "
266- )
267-
268- @staticmethod
269- def _build_sim_to_field_mapping (field_ids ):
270- """Map contiguous simulated robot ids (0, 1, 2, ...) onto the available
271- field ids for a team, in ascending order.
272-
273- :param field_ids: the robot ids present on the field for a team
274- :return: dict of simulated_robot_id -> field_robot_id
275- """
276- return {sim_id : field_id for sim_id , field_id in enumerate (sorted (field_ids ))}
248+ logger .info (f"simulated id to field id mapping { self .sim_to_field_robot_id } " )
277249
278250 def _create_move_tactics (self , robot_states ):
279251 """Create a MoveTactic for each robot to drive it to its world state.
@@ -294,109 +266,74 @@ def _create_move_tactics(self, robot_states):
294266 for robot_id , robot_state in robot_states .items ()
295267 }
296268
297- def _map_tactics_to_field_ids (self , tactics , sim_to_field_id , team_name ):
269+ def _map_tactics_to_field_ids (self , tactics ):
298270 """Remap a tactics dict keyed by simulated robot ids to the robot ids
299271 available on the field. Tactics for simulated ids with no available
300272 field robot are dropped with a warning.
301273
302274 :param tactics: None or dict of simulated_robot_id -> tactic
303- :param sim_to_field_id: the team's simulated-id -> field-id mapping
304- :param team_name: the team colour, used in warnings
305275 :return: None if tactics is None, else dict of field_robot_id -> tactic
306276 """
307277 if tactics is None :
308278 return None
309279
310280 mapped_tactics = {}
311281 for sim_id , tactic in tactics .items ():
312- if sim_id not in sim_to_field_id :
282+ if sim_id not in self . sim_to_field_robot_id :
313283 logger .warning (
314- f"no { team_name } field robot available for simulated robot id "
315- f" { sim_id } ; skipping its tactic"
284+ f"no field robot available for simulated robot id { sim_id } ; "
285+ " skipping its tactic"
316286 )
317287 continue
318- mapped_tactics [sim_to_field_id [sim_id ]] = tactic
288+ mapped_tactics [self . sim_to_field_robot_id [sim_id ]] = tactic
319289
320290 return mapped_tactics
321291
322- @staticmethod
323- def _remap_robot_state_ids (robot_states , sim_to_field_id ):
324- """Remap a world-state robot map keyed by simulated ids to field ids,
325- dropping any simulated id with no available field robot.
326-
327- :param robot_states: map of simulated_robot_id -> RobotState
328- :param sim_to_field_id: the team's simulated-id -> field-id mapping
329- :return: dict of field_robot_id -> RobotState
330- """
331- return {
332- sim_to_field_id [sim_id ]: robot_state
333- for sim_id , robot_state in robot_states .items ()
334- if sim_id in sim_to_field_id
335- }
336-
337292 def _relabel_world_to_sim_ids (self , world : World ) -> World :
338- """Return a copy of the world with both teams' robot ids translated from
293+ """Return a copy of the world with friendly robot ids translated from
339294 field ids back to the simulated ids the test uses.
340295
341296 Validations match robots by the contiguous simulated ids (0, 1, 2, ...),
342297 but the world reports the robots' actual field ids. Relabeling the world
343298 here lets every id-based validation find the correct robot without each
344- validation needing to know about the mapping. Robots with no mapping
345- (e.g. extras not part of the test) keep their field id.
299+ validation needing to know about the mapping. Friendly robots with no
300+ mapping (e.g. extras not part of the test) keep their field id.
346301
347302 :param world: The World proto reported by the field full system
348- :return: a copy of the world with robot ids in simulated-id space
303+ :return: a copy of the world with friendly robot ids in simulated-id space
349304 """
350305 relabeled_world = World ()
351306 relabeled_world .CopyFrom (world )
352- self ._relabel_team_to_sim_ids (
353- relabeled_world .friendly_team , self .friendly_field_to_sim_id
354- )
355- self ._relabel_team_to_sim_ids (
356- relabeled_world .enemy_team , self .enemy_field_to_sim_id
357- )
307+ for robot in relabeled_world .friendly_team .team_robots :
308+ if robot .id in self .field_to_sim_robot_id :
309+ robot .id = self .field_to_sim_robot_id [robot .id ]
358310 return relabeled_world
359311
360- @staticmethod
361- def _relabel_team_to_sim_ids (team , field_to_sim_id ):
362- """Relabel a team's robot ids in place from field ids to simulated ids.
363-
364- :param team: a Team proto whose robots' ids to relabel
365- :param field_to_sim_id: the team's field-id -> simulated-id mapping
366- """
367- for robot in team .team_robots :
368- if robot .id in field_to_sim_id :
369- robot .id = field_to_sim_id [robot .id ]
370-
371312 def _wait_for_robots_at_world_state (self , world_state : WorldState ):
372313 """Block until every robot in the world state is within
373314 ROBOT_SETUP_TOLERANCE_M of its target position.
374315
375316 Robot positions are read from the friendly full system's World in the
376- same fashion as _survey_field_robots. The friendly team maps to the
377- friendly-coloured robots in the world state, and the enemy team to the
378- other colour. Each team's targets are remapped from simulated ids to the
379- field ids they were assigned to in set_tactics.
317+ same fashion as _survey_field_robots. The friendly targets are remapped
318+ from simulated ids to the field ids they were assigned to in set_tactics.
380319
381320 :param world_state: The WorldState proto with the desired robot states
382321 :raises Exception: if the robots do not reach their targets within
383322 ROBOT_SETUP_TIMEOUT_S
384323 """
385- if self .is_yellow_friendly :
386- friendly_targets = world_state .yellow_robots
387- enemy_targets = world_state .blue_robots
388- else :
389- friendly_targets = world_state .blue_robots
390- enemy_targets = world_state .yellow_robots
324+ friendly_targets = (
325+ world_state .yellow_robots
326+ if self .is_yellow_friendly
327+ else world_state .blue_robots
328+ )
391329
392- # Remap each team's targets onto the field ids they were commanded to,
330+ # Remap the friendly targets onto the field ids they were commanded to,
393331 # dropping any simulated id that has no available field robot
394- friendly_targets = self ._remap_robot_state_ids (
395- friendly_targets , self .friendly_sim_to_field_id
396- )
397- enemy_targets = self ._remap_robot_state_ids (
398- enemy_targets , self .enemy_sim_to_field_id
399- )
332+ friendly_targets = {
333+ self .sim_to_field_robot_id [sim_id ]: robot_state
334+ for sim_id , robot_state in friendly_targets .items ()
335+ if sim_id in self .sim_to_field_robot_id
336+ }
400337
401338 logger .info ("waiting for robots to reach their target positions" )
402339 wait_start_time = time .time ()
@@ -410,14 +347,8 @@ def _wait_for_robots_at_world_state(self, world_state: WorldState):
410347 robot .id : robot .current_state .global_position
411348 for robot in world .friendly_team .team_robots
412349 }
413- enemy_positions = {
414- robot .id : robot .current_state .global_position
415- for robot in world .enemy_team .team_robots
416- }
417350
418- if self ._all_robots_at_targets (
419- friendly_targets , friendly_positions
420- ) and self ._all_robots_at_targets (enemy_targets , enemy_positions ):
351+ if self ._all_robots_at_targets (friendly_targets , friendly_positions ):
421352 logger .info ("all robots reached their target positions" )
422353 return
423354
0 commit comments