Skip to content

Commit 06899f2

Browse files
committed
some more debugging, fixed issues with agent id expecting in order + better constraint finding
1 parent bd5db9d commit 06899f2

File tree

3 files changed

+60
-35
lines changed

3 files changed

+60
-35
lines changed

PathPlanning/TimeBasedPathPlanning/BaseClasses.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def plan(grid: Grid, start: Position, goal: Position, agent_idx: int, verbose: b
2626
@dataclass
2727
class StartAndGoal:
2828
# Index of this agent
29+
# TODO: better name and use AgentId type
2930
index: int
3031
# Start position of the robot
3132
start: Position

PathPlanning/TimeBasedPathPlanning/ConflictBasedSearch.py

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ def plan(grid: Grid, start_and_goals: list[StartAndGoal], single_agent_planner_c
3434
initial_solution: dict[AgentId, NodePath] = {}
3535

3636
# Generate initial solution (no reservations for robots)
37-
for agent_idx, start_and_goal in enumerate(start_and_goals):
38-
path = single_agent_planner_class.plan(grid, start_and_goal.start, start_and_goal.goal, agent_idx, verbose)
39-
initial_solution[AgentId(agent_idx)] = path
37+
for start_and_goal in start_and_goals:
38+
path = single_agent_planner_class.plan(grid, start_and_goal.start, start_and_goal.goal, start_and_goal.index, verbose)
39+
initial_solution[AgentId(start_and_goal.index)] = path
4040

41-
# for (agent_idx, path) in initial_solution.items():
42-
# print(f"\nAgent {agent_idx} path:\n {path}")
41+
for (agent_idx, path) in initial_solution.items():
42+
print(f"\nAgent {agent_idx} path:\n {path}")
4343

4444
constraint_tree = ConstraintTree(initial_solution)
4545

@@ -49,17 +49,17 @@ def plan(grid: Grid, start_and_goals: list[StartAndGoal], single_agent_planner_c
4949
constraint_tree_node = constraint_tree.get_next_node_to_expand()
5050
ancestor_constraints = constraint_tree.get_ancestor_constraints(constraint_tree_node.parent_idx)
5151

52-
# print(f"Expanded node: {constraint_tree_node.constraint} with parent: {constraint_tree_node.parent_idx}")
53-
# print(f"\tAncestor constraints: {ancestor_constraints}")
52+
print(f"Expanded node: {constraint_tree_node.constraint} with parent: {constraint_tree_node.parent_idx}")
53+
print(f"\tAncestor constraints: {ancestor_constraints}")
5454

5555
if verbose:
56-
print(f"Expanding node with constraint {constraint_tree_node.constraint} and parent {constraint_tree_node.parent_idx} ")
56+
print(f"Expanding node with constraint {constraint_tree_node.constraint} and parent {constraint_tree_node.parent_idx}")
5757

5858
if constraint_tree_node is None:
5959
raise RuntimeError("No more nodes to expand in the constraint tree.")
6060
if not constraint_tree_node.constraint:
6161
# This means we found a solution!
62-
return (start_and_goals, [constraint_tree_node.paths[AgentId(i)] for i in range(len(start_and_goals))])
62+
return (start_and_goals, [constraint_tree_node.paths[start_and_goal.index] for start_and_goal in start_and_goals])
6363

6464
if not isinstance(constraint_tree_node.constraint, ForkingConstraint):
6565
raise ValueError(f"Expected a ForkingConstraint, but got: {constraint_tree_node.constraint}")
@@ -78,19 +78,22 @@ def plan(grid: Grid, start_and_goals: list[StartAndGoal], single_agent_planner_c
7878
# Skip if we have already tried this set of constraints
7979
constraint_hash = hash(frozenset(all_constraints))
8080
if constraint_hash in attempted_constraint_combos:
81-
break
81+
print(f"\tSkipping already attempted constraint combination: {all_constraints}")
82+
continue
8283
else:
8384
attempted_constraint_combos.add(constraint_hash)
8485

8586
if verbose:
8687
print(f"\tall constraints: {all_constraints}")
88+
print(f"\tall constraints: {all_constraints}")
8789

8890
grid.clear_constraint_points()
8991
grid.apply_constraint_points(all_constraints)
9092

9193
# Just plan for agent with new constraint
92-
start_and_goal = start_and_goals[constrained_agent.agent]
94+
start_and_goal = ConflictBasedSearch.find_by_index(start_and_goals, constrained_agent.agent)
9395
try:
96+
print("\tplanning for: {}", start_and_goal)
9497
new_path = single_agent_planner_class.plan(grid, start_and_goal.start, start_and_goal.goal, start_and_goal.index, verbose)
9598
except Exception as e:
9699
continue
@@ -99,8 +102,8 @@ def plan(grid: Grid, start_and_goals: list[StartAndGoal], single_agent_planner_c
99102
paths: dict[AgentId, NodePath] = deepcopy(applied_constraint_parent.paths) # TODO: not sure if deepcopy is actually needed
100103
paths[constrained_agent.agent] = new_path
101104

102-
# for (agent_idx, path) in paths.items():
103-
# print(f"\nAgent {agent_idx} path:\n {path}")
105+
for (agent_idx, path) in paths.items():
106+
print(f"\nAgent {agent_idx} path:\n {path}")
104107

105108
applied_constraint_parent.constraint = applied_constraint
106109
parent_idx = constraint_tree.add_expanded_node(applied_constraint_parent)
@@ -115,10 +118,18 @@ def plan(grid: Grid, start_and_goals: list[StartAndGoal], single_agent_planner_c
115118
return (start_and_goals, paths.values())
116119

117120
# if verbose:
118-
print(f"Adding new constraint tree node with constraint: {new_constraint_tree_node.constraint}")
121+
# print(f"Adding new constraint tree node with constraint: {new_constraint_tree_node.constraint}")
119122
constraint_tree.add_node_to_tree(new_constraint_tree_node)
120123

121124
raise RuntimeError("No solution found")
125+
126+
# TODO: bad function name
127+
def find_by_index(start_and_goal_list: list[StartAndGoal], target_index: AgentId) -> AgentId:
128+
for item in start_and_goal_list:
129+
if item.index == target_index:
130+
return item
131+
raise RuntimeError(f"Could not find agent with index {target_index} in {start_and_goal_list}")
132+
122133
# TODO
123134
# * get SIPP working w CBS
124135
# * add checks for duplicate expansions
@@ -132,13 +143,13 @@ def main():
132143

133144
# TODO: bug somewhere where it expects agent ids to match indices
134145
# start_and_goals = [StartAndGoal(i, Position(1, i), Position(19, 19-i)) for i in range(1, 12)]
135-
start_and_goals = [StartAndGoal(i, Position(1, 8+i), Position(19, 19-i)) for i in range(6)]
146+
# start_and_goals = [StartAndGoal(i, Position(1, 8+i), Position(19, 19-i)) for i in range(6)]
136147
# start_and_goals = [StartAndGoal(i, Position(1, 2*i), Position(19, 19-i)) for i in range(4)]
137148

138149
# hallway cross
139-
# start_and_goals = [StartAndGoal(0, Position(6, 10), Position(13, 10)),
140-
# StartAndGoal(1, Position(13, 10), Position(7, 10)),
141-
# StartAndGoal(2, Position(11, 10), Position(6, 10))]
150+
start_and_goals = [StartAndGoal(0, Position(6, 10), Position(13, 10)),
151+
StartAndGoal(1, Position(11, 10), Position(6, 10)),
152+
StartAndGoal(2, Position(13, 10), Position(7, 10))]
142153

143154
# temporary obstacle
144155
# start_and_goals = [StartAndGoal(0, Position(15, 14), Position(15, 16))]
@@ -152,15 +163,15 @@ def main():
152163
num_obstacles=250,
153164
obstacle_avoid_points=obstacle_avoid_points,
154165
# obstacle_arrangement=ObstacleArrangement.TEMPORARY_OBSTACLE,
155-
# obstacle_arrangement=ObstacleArrangement.HALLWAY,
156-
obstacle_arrangement=ObstacleArrangement.NARROW_CORRIDOR,
166+
obstacle_arrangement=ObstacleArrangement.HALLWAY,
167+
# obstacle_arrangement=ObstacleArrangement.NARROW_CORRIDOR,
157168
# obstacle_arrangement=ObstacleArrangement.ARRANGEMENT1,
158169
# obstacle_arrangement=ObstacleArrangement.RANDOM,
159170
)
160171

161172
start_time = time.time()
162-
start_and_goals, paths = ConflictBasedSearch.plan(grid, start_and_goals, SafeIntervalPathPlanner, verbose)
163-
# start_and_goals, paths = ConflictBasedSearch.plan(grid, start_and_goals, SpaceTimeAStar, verbose)
173+
# start_and_goals, paths = ConflictBasedSearch.plan(grid, start_and_goals, SafeIntervalPathPlanner, verbose)
174+
start_and_goals, paths = ConflictBasedSearch.plan(grid, start_and_goals, SpaceTimeAStar, verbose)
164175

165176
runtime = time.time() - start_time
166177
print(f"\nPlanning took: {runtime:.5f} seconds")

PathPlanning/TimeBasedPathPlanning/ConstraintTree.py

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def get_constraint_point(self, verbose = False) -> Optional[ForkingConstraint]:
5151
positions_at_time: dict[PositionAtTime, AgentId] = {}
5252
for t in range(final_t + 1):
5353
# TODO: need to be REALLY careful that these agent ids are consitent
54+
possible_constraints: list[ForkingConstraint] = []
5455
for agent_id, path in self.paths.items():
5556
# Check for edge conflicts
5657
last_position = None
@@ -62,19 +63,10 @@ def get_constraint_point(self, verbose = False) -> Optional[ForkingConstraint]:
6263
continue
6364
# print(f"\treserving pos/t for {agent_id}: {position} @ {t}")
6465
position_at_time = PositionAtTime(position, t)
65-
if position_at_time in positions_at_time:
66-
conflicting_agent_id = positions_at_time[position_at_time]
67-
68-
if verbose:
69-
# if True:
70-
print(f"found constraint: {position_at_time} for agents {agent_id} & {conflicting_agent_id}")
71-
constraint = Constraint(position=position, time=t)
72-
return ForkingConstraint((
73-
ConstrainedAgent(agent_id, constraint), ConstrainedAgent(conflicting_agent_id, constraint)
74-
))
75-
else:
66+
if position_at_time not in positions_at_time:
7667
positions_at_time[position_at_time] = AgentId(agent_id)
7768

69+
# edge conflict
7870
if last_position:
7971
new_position_at_last_time = PositionAtTime(position, t-1)
8072
old_position_at_new_time = PositionAtTime(last_position, t)
@@ -89,8 +81,29 @@ def get_constraint_point(self, verbose = False) -> Optional[ForkingConstraint]:
8981
ConstrainedAgent(agent_id, position_at_time),
9082
ConstrainedAgent(conflicting_agent_id1, Constraint(position=last_position, time=t))
9183
))
92-
print(f"new constraint: {new_constraint}")
93-
return new_constraint
84+
possible_constraints.append(new_constraint)
85+
continue
86+
87+
# double reservation at a (cell, time) combination
88+
if positions_at_time[position_at_time] != agent_id:
89+
conflicting_agent_id = positions_at_time[position_at_time]
90+
91+
constraint = Constraint(position=position, time=t)
92+
possible_constraints.append(ForkingConstraint((
93+
ConstrainedAgent(agent_id, constraint), ConstrainedAgent(conflicting_agent_id, constraint)
94+
)))
95+
continue
96+
if possible_constraints:
97+
print(f"choosing best constraint of {possible_constraints}")
98+
# first check for edge constraints
99+
for constraint in possible_constraints:
100+
if constraint.constrained_agents[0].constraint.position != constraint.constrained_agents[1].constraint.position:
101+
print(f"\tfound edge conflict constraint: {constraint}")
102+
return constraint
103+
# if none, then return first normal constraint
104+
print("\treturning normal constraint")
105+
return possible_constraints[0]
106+
94107
return None
95108

96109

0 commit comments

Comments
 (0)