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 | 250.000000 | 250.000000 | 250.000000 | 250.000000 | 250.000000 |
mean | 124.500000 | 0.122522 | 2.236000 | 3.100000 | 1.570796 | 0.715538 | 0.856000 | 0.796000 | 0.656000 |
std | 72.312977 | 0.072869 | 4.926396 | 12.651095 | 0.000000 | 0.125498 | 0.351794 | 0.403777 | 0.475994 |
min | 0.000000 | 0.002141 | 0.000000 | 0.000000 | 1.570796 | 0.222478 | 0.000000 | 0.000000 | 0.000000 |
25% | 62.250000 | 0.055579 | 0.000000 | 0.000000 | 1.570796 | 0.700834 | 1.000000 | 1.000000 | 0.000000 |
50% | 124.500000 | 0.125724 | 0.000000 | 0.000000 | 1.570796 | 0.758876 | 1.000000 | 1.000000 | 1.000000 |
75% | 186.750000 | 0.187246 | 0.000000 | 0.000000 | 1.570796 | 0.792167 | 1.000000 | 1.000000 | 1.000000 |
max | 249.000000 | 0.247253 | 19.000000 | 114.000000 | 1.570796 | 0.825777 | 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.00000 | 5000.000000 | 5000.000000 |
mean | 2499.500000 | 0.125604 | 0.501800 | 20.636600 | 1.171667 | 0.745573 | 0.59880 | 0.952000 | 0.550800 |
std | 1443.520003 | 0.072464 | 2.484438 | 48.535728 | 0.229486 | 0.071828 | 0.49019 | 0.213788 | 0.497462 |
min | 0.000000 | 0.000054 | 0.000000 | 0.000000 | 0.785811 | 0.208325 | 0.00000 | 0.000000 | 0.000000 |
25% | 1249.750000 | 0.062673 | 0.000000 | 0.000000 | 0.972600 | 0.720328 | 0.00000 | 1.000000 | 0.000000 |
50% | 2499.500000 | 0.127100 | 0.000000 | 0.000000 | 1.165859 | 0.760185 | 1.00000 | 1.000000 | 1.000000 |
75% | 3749.250000 | 0.187673 | 0.000000 | 14.000000 | 1.374103 | 0.792539 | 1.00000 | 1.000000 | 1.000000 |
max | 4999.000000 | 0.249940 | 19.000000 | 490.000000 | 1.570597 | 0.832498 | 1.00000 | 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");

[ ]: