Back to Repositories

Testing Following Distance Control Algorithms in OpenPilot

This test suite validates the following distance functionality in OpenPilot’s longitudinal control system, ensuring proper vehicle spacing during autonomous driving. It verifies both end-to-end and direct control approaches across different driving personalities and speeds.

Test Coverage Overview

The test suite comprehensively evaluates following distance calculations across multiple scenarios.

Key areas covered include:
  • Multiple driving personalities (relaxed, standard, aggressive)
  • Various lead vehicle speeds (0, 10, 35)
  • Both end-to-end and direct control implementations
  • Steady-state following distance validation

Implementation Analysis

The testing approach utilizes parameterized testing to efficiently cover multiple test scenarios. It employs simulation-based verification comparing actual vs expected following distances.

Technical implementation features:
  • Parameterized test class using itertools.product
  • Simulation-based distance calculations
  • Relative error tolerance handling
  • Personality-based following time adjustments

Technical Details

Testing infrastructure includes:
  • pytest framework with parameterized_class decorator
  • Custom Maneuver simulation class
  • Cereal log integration for personality types
  • Longitudinal MPC library integration
  • Configurable error ratio handling (0.1 for direct control, 0.2 for e2e)

Best Practices Demonstrated

The test implementation showcases several testing best practices.

Notable practices include:
  • Comprehensive parameter space coverage
  • Clear separation of test configurations
  • Robust error handling with relative tolerances
  • Efficient test case generation using parameterization
  • Integration with system-level components

commaai/openpilot

selfdrive/controls/tests/test_following_distance.py

            
import pytest
import itertools
from parameterized import parameterized_class

from cereal import log

from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import desired_follow_distance, get_T_FOLLOW
from openpilot.selfdrive.test.longitudinal_maneuvers.maneuver import Maneuver


def run_following_distance_simulation(v_lead, t_end=100.0, e2e=False, personality=0):
  man = Maneuver(
    '',
    duration=t_end,
    initial_speed=float(v_lead),
    lead_relevancy=True,
    initial_distance_lead=100,
    speed_lead_values=[v_lead],
    breakpoints=[0.],
    e2e=e2e,
    personality=personality,
  )
  valid, output = man.evaluate()
  assert valid
  return output[-1,2] - output[-1,1]


@parameterized_class(("e2e", "personality", "speed"), itertools.product(
                      [True, False], # e2e
                      [log.LongitudinalPersonality.relaxed, # personality
                       log.LongitudinalPersonality.standard,
                       log.LongitudinalPersonality.aggressive],
                      [0,10,35])) # speed
class TestFollowingDistance:
  def test_following_distance(self):
    v_lead = float(self.speed)
    simulation_steady_state = run_following_distance_simulation(v_lead, e2e=self.e2e, personality=self.personality)
    correct_steady_state = desired_follow_distance(v_lead, v_lead, get_T_FOLLOW(self.personality))
    err_ratio = 0.2 if self.e2e else 0.1
    assert simulation_steady_state == pytest.approx(correct_steady_state, abs=err_ratio * correct_steady_state + .5)