Deadlocks and Collisions#
In this notebook, we will look at two negative events that may happen while navigating: collisions and deadlocks. We will first learn own to visualize them during a simulation, then how to perform many simulations to assess the impact of two parameters: the safety radius and barrier angle.
We are going to color colliding agents in red and deadlocked agents in blue
[1]:
from navground.sim.ui.video import display_video, display_video_from_run
def decorate(agent):
if agent.has_been_in_collision_since(world.time - 1.0):
return {'fill': 'red'}
if agent.has_been_stuck_since(world.time - 1.0):
return {'fill': 'blue'}
return {}
We start by specifying an experiment with safety_margin=0
, which is an unsafe setup that will lead to collisions.
[2]:
from navground import sim
yaml = """
type: Cross
agent_margin: 0.1
side: 4
target_margin: 0.1
tolerance: 0.5
groups:
-
type: thymio
number: 20
radius: 0.08
control_period: 0.1
speed_tolerance: 0.02
kinematics:
type: 2WDiff
wheel_axis: 0.094
max_speed: 0.166
behavior:
type: HL
optimal_speed: 0.12
horizon: 5.0
tau: 0.5
eta: 0.25
safety_margin: 0.0
state_estimation:
type: Bounded
range: 5.0
"""
[3]:
scenario = sim.load_scenario(yaml)
world = sim.World()
scenario.init_world(world, 0)
We run the simulation for some time with some agents colliding shoulder-to-shoulder.
[4]:
display_video(world, time_step=0.1, duration=120, factor=10, decorate=decorate, display_width=300)
[4]:
Try now to increase the safety margin to 0.5, which is so large that it will rapidly lead to deadlocked agents, which are colored in blue.
[5]:
yaml = """
type: Cross
agent_margin: 0.1
side: 4
target_margin: 0.1
tolerance: 0.5
groups:
-
type: thymio
number: 20
radius: 0.08
control_period: 0.1
speed_tolerance: 0.02
kinematics:
type: 2WDiff
wheel_axis: 0.094
max_speed: 0.166
behavior:
type: HL
optimal_speed: 0.12
horizon: 5.0
tau: 0.5
eta: 0.25
safety_margin: 0.5
state_estimation:
type: Bounded
range: 5.0
"""
[6]:
scenario = sim.load_scenario(yaml)
world = sim.World()
scenario.init_world(world, 0)
display_video(world, time_step=0.1, duration=120, factor=10, decorate=decorate, display_width=300)
[6]:
In between these two extrema, there should be good trade-off with no collisions and no deadlocks. We invistigate it with an experiment where we vary the safety margin.
[7]:
from navground import sim
yaml = """
steps: 3000
time_step: 0.1
record_collisions: true
record_deadlocks: true
record_safety_violation: true
record_efficacy: true
terminated_when_idle_or_stuck: true
runs: 250
run_index: 0
scenario:
type: Cross
agent_margin: 0.1
side: 4
target_margin: 0.1
tolerance: 0.5
groups:
-
type: thymio
number: 20
radius: 0.08
control_period: 0.1
speed_tolerance: 0.02
kinematics:
type: 2WDiff
wheel_axis: 0.094
max_speed: 0.166
behavior:
type: HL
optimal_speed: 0.12
horizon: 5.0
tau: 0.5
eta: 0.5
safety_margin:
sampler: uniform
from: 0.0
to: 0.25
once: true
state_estimation:
type: Bounded
range: 5.0
"""
[8]:
from tqdm.notebook import tqdm
experiment = sim.load_experiment(yaml)
experiment.save_directory = ""
with tqdm() as bar:
experiment.setup_tqdm(bar)
experiment.run(keep=True, number_of_threads=8)
We import all relevant data into a pandas frame where we also define
“safe”: no collisions
“fluid”: no deadlocks
“ok”: when safe and fluid
[9]:
import numpy as np
import pandas as pd
def count_deadlocks(deadlock_time, final_time):
is_deadlocked = np.logical_and(deadlock_time > 0, deadlock_time < (final_time - 5.0))
return sum(is_deadlocked)
def extract_data(experiment):
collisions = []
deadlocks = []
efficacy = []
sms = []
bas = []
seeds = []
for i, run in experiment.runs.items():
world = run.world
sm = np.unique([agent.behavior.safety_margin for agent in world.agents])
ba = np.unique([agent.behavior.barrier_angle for agent in world.agents])
sms += list(sm)
bas += list(ba)
seeds.append(run.seed)
final_time = run.world.time
deadlocks.append(count_deadlocks(run.deadlocks, final_time))
collisions.append(len(run.collisions))
efficacy.append(run.efficacy.mean())
df = pd.DataFrame({
'seeds': seeds,
'safety_margin': sms,
'deadlocks': deadlocks,
'collisions': collisions,
'barrier_angle': bas,
'efficacy': efficacy})
df['safe'] = (df.collisions == 0).astype(int)
df['fluid'] = (df.deadlocks == 0).astype(int)
df['ok'] = ((df.deadlocks == 0) & (df.collisions == 0)).astype(int)
return df
[10]:
data = extract_data(experiment)
data.describe()
[10]:
seeds | safety_margin | deadlocks | collisions | barrier_angle | efficacy | safe | fluid | ok | |
---|---|---|---|---|---|---|---|---|---|
count | 250.000000 | 250.000000 | 250.000000 | 250.000000 | 2.500000e+02 | 250.000000 | 250.000000 | 250.000000 | 250.000000 |
mean | 124.500000 | 0.127183 | 2.568000 | 4.424000 | 1.570796e+00 | 0.745850 | 0.788000 | 0.764000 | 0.556000 |
std | 72.312977 | 0.073709 | 5.243219 | 16.482077 | 2.224900e-16 | 0.132497 | 0.409545 | 0.425474 | 0.497851 |
min | 0.000000 | 0.001417 | 0.000000 | 0.000000 | 1.570796e+00 | 0.205297 | 0.000000 | 0.000000 | 0.000000 |
25% | 62.250000 | 0.054341 | 0.000000 | 0.000000 | 1.570796e+00 | 0.737490 | 1.000000 | 1.000000 | 0.000000 |
50% | 124.500000 | 0.126612 | 0.000000 | 0.000000 | 1.570796e+00 | 0.792123 | 1.000000 | 1.000000 | 1.000000 |
75% | 186.750000 | 0.193269 | 0.000000 | 0.000000 | 1.570796e+00 | 0.829279 | 1.000000 | 1.000000 | 1.000000 |
max | 249.000000 | 0.249757 | 19.000000 | 157.000000 | 1.570796e+00 | 0.859686 | 1.000000 | 1.000000 | 1.000000 |
We plot the consequences of the safety margin on deadlocks and collisions. We see that
for low safety margins, there are collisions
for high safety margins, there are deadlocks
[11]:
ax = data.plot.scatter(x='safety_margin', y='collisions', color='r')
data.plot.scatter(ax=ax.twinx(), x='safety_margin', y='deadlocks', color='b');
Efficacy measures how much agents are progressing towards their target (1 = ideal, 0 = stuck). Looking at efficacy gives a more fine-grained picture than deadlocks, which are still visible on the right (points lower than the slowing degrading line).
[12]:
data.plot.scatter(x='safety_margin', y='efficacy', color='k');
Deadlocks can be mitigated by reducing the barrier angle but this may cause collisions. We investigate the effect of safety margin and barrier angle with a larger experiment where we vary both parameters.
[13]:
from navground import sim
yaml = """
steps: 3000
time_step: 0.1
record_collisions: true
record_deadlocks: true
record_safety_violation: false
record_efficacy: true
terminated_when_idle_or_stuck: true
runs: 5000
scenario:
type: Cross
agent_margin: 0.1
side: 4
target_margin: 0.1
tolerance: 0.5
groups:
-
type: thymio
number: 20
radius: 0.08
control_period: 0.1
speed_tolerance: 0.02
kinematics:
type: 2WDiff
wheel_axis: 0.094
max_speed: 0.166
behavior:
type: HL
optimal_speed: 0.12
horizon: 5.0
tau: 0.5
eta: 0.5
safety_margin:
sampler: uniform
from: 0.0
to: 0.25
once: true
barrier_angle:
sampler: uniform
from: 0.7854
to: 1.5708
once: true
state_estimation:
type: Bounded
range: 5.0
"""
[14]:
experiment = sim.load_experiment(yaml)
with tqdm() as bar:
experiment.setup_tqdm(bar)
experiment.run(keep=True, number_of_threads=8)
[15]:
data = extract_data(experiment)
data.describe()
[15]:
seeds | safety_margin | deadlocks | collisions | barrier_angle | efficacy | safe | fluid | ok | |
---|---|---|---|---|---|---|---|---|---|
count | 5000.000000 | 5000.000000 | 5000.000000 | 5000.000000 | 5000.000000 | 5000.000000 | 5000.000000 | 5000.000000 | 5000.000000 |
mean | 2499.500000 | 0.123464 | 0.594600 | 23.151800 | 1.179999 | 0.783691 | 0.598000 | 0.945000 | 0.543000 |
std | 1443.520003 | 0.072286 | 2.705201 | 53.899475 | 0.227654 | 0.075513 | 0.490351 | 0.228003 | 0.498197 |
min | 0.000000 | 0.000033 | 0.000000 | 0.000000 | 0.785570 | 0.182359 | 0.000000 | 0.000000 | 0.000000 |
25% | 1249.750000 | 0.061341 | 0.000000 | 0.000000 | 0.982294 | 0.762972 | 0.000000 | 1.000000 | 0.000000 |
50% | 2499.500000 | 0.122854 | 0.000000 | 0.000000 | 1.184699 | 0.801590 | 1.000000 | 1.000000 | 1.000000 |
75% | 3749.250000 | 0.185237 | 0.000000 | 15.000000 | 1.374994 | 0.828694 | 1.000000 | 1.000000 | 1.000000 |
max | 4999.000000 | 0.249975 | 19.000000 | 580.000000 | 1.570611 | 0.865469 | 1.000000 | 1.000000 | 1.000000 |
Lower barrier angles reduce safety:
[16]:
data.plot.hexbin(x="safety_margin", y="barrier_angle", C="safe",
reduce_C_function=np.mean, gridsize=15,
title="Probability of safe run");
Higher barrier angles increase the probability of deadlocks:
[17]:
data.plot.hexbin(x="safety_margin", y="barrier_angle", C="fluid",
reduce_C_function=np.mean, gridsize=15,
title="Probability of deadlock-free run");
For parameters in the dark green region below, agents are behaving well:
[18]:
data.plot.hexbin(x="safety_margin", y="barrier_angle", C="ok",
reduce_C_function=np.mean, gridsize=15,
title="Probability of ok run");
Finally, we also plot the efficacy:
[19]:
data.plot.hexbin(x="safety_margin", y="barrier_angle", C="efficacy",
reduce_C_function=np.mean, gridsize=15,
title="Average efficacy");
[ ]: