Skip to content

Commit 5b140f0

Browse files
committed
more cleanup
1 parent ec48aaa commit 5b140f0

2 files changed

Lines changed: 43 additions & 33 deletions

File tree

PathPlanning/TimeBasedPathPlanning/ConflictBasedSearch.py

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,7 @@ def plan(grid: Grid, start_and_goals: list[StartAndGoal], single_agent_planner_c
4040
"""
4141
print(f"Using single-agent planner: {single_agent_planner_class}")
4242

43-
initial_solution: dict[AgentId, NodePath] = {}
44-
45-
# Generate initial solution (no constraints)
46-
for start_and_goal in start_and_goals:
47-
path = single_agent_planner_class.plan(grid, start_and_goal.start, start_and_goal.goal, start_and_goal.agent_id, verbose)
48-
initial_solution[start_and_goal.agent_id] = path
49-
50-
if verbose:
51-
print("Initial solution:")
52-
for (agent_idx, path) in initial_solution.items():
53-
print(f"\nAgent {agent_idx} path:\n {path}")
54-
55-
constraint_tree = ConstraintTree(initial_solution)
43+
constraint_tree: ConstraintTree = ConflictBasedSearch.initialize_constraint_tree(grid, start_and_goals, single_agent_planner_class, verbose)
5644
attempted_constraint_combos: set = set()
5745

5846
while constraint_tree.nodes_to_expand:
@@ -100,11 +88,6 @@ def plan(grid: Grid, start_and_goals: list[StartAndGoal], single_agent_planner_c
10088
# Deepcopy to update with applied constraint and new paths
10189
applied_constraint_parent = deepcopy(constraint_tree_node)
10290
applied_constraint_parent.paths[constrained_agent.agent] = new_path
103-
104-
if verbose:
105-
for (agent_idx, path) in applied_constraint_parent.paths.items():
106-
print(f"\nAgent {agent_idx} path:\n {path}")
107-
10891
applied_constraint_parent.constraint = applied_constraint
10992
parent_idx = constraint_tree.add_expanded_node(applied_constraint_parent)
11093

@@ -152,10 +135,10 @@ def plan_for_agent(constrained_agent: ConstrainedAgent,
152135
attempted_constraint_combos.add(constraint_hash)
153136

154137
if verbose:
155-
print(f"\tall constraints: {all_constraints}")
138+
print(f"\tAll constraints: {all_constraints}")
156139

157-
grid.clear_constraint_points()
158-
grid.apply_constraint_points(all_constraints)
140+
grid.clear_constraint_reservations()
141+
grid.apply_constraint_reservations(all_constraints)
159142

160143
# Just plan for agent with new constraint
161144
start_and_goal: StartAndGoal = ConflictBasedSearch.get_agents_start_and_goal(start_and_goals, constrained_agent.agent)
@@ -165,10 +148,31 @@ def plan_for_agent(constrained_agent: ConstrainedAgent,
165148
new_path = single_agent_planner_class.plan(grid, start_and_goal.start, start_and_goal.goal, start_and_goal.agent_id, verbose)
166149
return new_path
167150
except Exception as e:
151+
# Note: single agent planners can fail if constraints make planning for an agent impossible. The upper level search does not
152+
# consider if a constraint will make it impossible for an agent to plan when adding a new constraint.
168153
if verbose:
169154
print(f"Error: {e}")
170155
return None
171156

157+
@staticmethod
158+
def initialize_constraint_tree(grid: Grid, start_and_goals: list[StartAndGoal], single_agent_planner_class: SingleAgentPlanner, verbose: bool) -> ConstraintTree:
159+
"""
160+
Generate an initial solution by planning for each agent with no obstacles
161+
"""
162+
initial_solution: dict[AgentId, NodePath] = {}
163+
164+
# Generate initial solution (no constraints)
165+
for start_and_goal in start_and_goals:
166+
path = single_agent_planner_class.plan(grid, start_and_goal.start, start_and_goal.goal, start_and_goal.agent_id, verbose)
167+
initial_solution[start_and_goal.agent_id] = path
168+
169+
if verbose:
170+
print("Initial solution:")
171+
for (agent_idx, path) in initial_solution.items():
172+
print(f"\nAgent {agent_idx} path:\n {path}")
173+
174+
return ConstraintTree(initial_solution)
175+
172176
class Scenario(Enum):
173177
# Five robots all trying to get through a single cell choke point to reach their goals
174178
NARROW_CORRIDOR = 0

PathPlanning/TimeBasedPathPlanning/GridWithDynamicObstacles.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class Grid:
5959
applied_constraints: list[AppliedConstraint] = []
6060
# Note - this is separate from reservation_matrix because multiple robots can have the same
6161
# constraints at the same (x, y, t) tuple
62-
constraint_points: np.ndarray
62+
constraint_reservations: np.ndarray
6363

6464
# Number of time steps in the simulation
6565
time_limit: int
@@ -80,7 +80,7 @@ def __init__(
8080
self.grid_size = grid_size
8181
self.reservation_matrix = np.zeros((grid_size[0], grid_size[1], self.time_limit))
8282

83-
self.constraint_points = empty_3d_array_of_sets(grid_size[0], grid_size[1], self.time_limit)
83+
self.constraint_reservations = empty_3d_array_of_sets(grid_size[0], grid_size[1], self.time_limit)
8484

8585
if num_obstacles > self.grid_size[0] * self.grid_size[1]:
8686
raise Exception("Number of obstacles is greater than grid size!")
@@ -253,7 +253,7 @@ def generate_hallway_obstacles(self) -> list[list[Position]]:
253253

254254
return obstacle_paths
255255

256-
def generate_temporary_obstacle(self, hallway_length: int = 3) -> list[list[Position]]:
256+
def generate_temporary_obstacle(self) -> list[list[Position]]:
257257
"""
258258
Generates a temporary obstacle at (10, 10) that disappears at t=30
259259
"""
@@ -263,21 +263,27 @@ def generate_temporary_obstacle(self, hallway_length: int = 3) -> list[list[Posi
263263

264264
return [obstacle_path]
265265

266-
def apply_constraint_points(self, constraints: list[AppliedConstraint], verbose = False):
266+
def apply_constraint_reservations(self, constraints: list[AppliedConstraint], verbose = False):
267+
"""
268+
Add new constraints and reserve them in the constraint_reservations map
269+
"""
267270
self.applied_constraints.extend(constraints)
268271
for constraint in constraints:
269272
if verbose:
270273
print(f"Applying {constraint=}")
271-
if constraint not in self.constraint_points[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time]:
272-
self.constraint_points[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time].add(constraint)
274+
if constraint not in self.constraint_reservations[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time]:
275+
self.constraint_reservations[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time].add(constraint)
273276

274277
if verbose:
275-
print(f"\tExisting constraints: {self.constraint_points[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time]}")
278+
print(f"\tExisting constraints: {self.constraint_reservations[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time]}")
276279

277-
def clear_constraint_points(self):
280+
def clear_constraint_reservations(self):
281+
"""
282+
Clear all applied constraints and their associated reservations
283+
"""
278284
for constraint in self.applied_constraints:
279-
if constraint in self.constraint_points[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time]:
280-
self.constraint_points[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time].remove(constraint)
285+
if constraint in self.constraint_reservations[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time]:
286+
self.constraint_reservations[constraint.constraint.position.x, constraint.constraint.position.y, constraint.constraint.time].remove(constraint)
281287
self.applied_constraints.clear()
282288

283289
"""
@@ -295,7 +301,7 @@ def valid_position(self, position: Position, t: int, agent_idx: int) -> bool:
295301
if not self.inside_grid_bounds(position):
296302
return False
297303

298-
constraints = self.constraint_points[position.x, position.y, t]
304+
constraints = self.constraint_reservations[position.x, position.y, t]
299305
for constraint in constraints:
300306
if constraint.constrained_agent == agent_idx:
301307
return False
@@ -366,7 +372,7 @@ def get_safe_intervals_at_cell(self, cell: Position, agent_idx: int) -> list[Int
366372
# Find where the array is zero
367373
zero_mask = (vals == 0)
368374

369-
for constraint_set in self.constraint_points[cell.x, cell.y]:
375+
for constraint_set in self.constraint_reservations[cell.x, cell.y]:
370376
for constraint in constraint_set:
371377
if constraint.constrained_agent != agent_idx:
372378
continue

0 commit comments

Comments
 (0)