Source code for igp2.planlibrary.controller

from collections import deque

import numpy as np
import logging
from typing import Dict

logger = logging.getLogger(__name__)


[docs]class AdaptiveCruiseControl: """ Defines an adaptive cruise controller based on the intelligent driver model (IDM)""" def __init__(self, dt=0.05, a_a=5, b_a=5, delta=4., s_0=2., T_a=1.5): """ Initialise the parameters of the adaptive cruise controller Args: dt: temporal difference a_a: maximum positive acceleration b_a: maximum negative acceleration delta: acceleration exponent s_0: minimum desired gap T_a: following time-gap """ self.dt = dt self.delta = delta self.s_0 = s_0 self.a_a = a_a self.b_a = b_a self.T_a = T_a
[docs] def get_acceleration(self, v_0: float, v_a: float, v_f: float, s_a: float) -> float: """ Get the acceleration output by the controller Args: v_0: maximum velocity v_a: ego vehicle velocity v_f: front vehicle velocity s_a: gap between vehicles Returns: acceleration """ delta_v = v_a - v_f s_star = self.s_0 + self.T_a * v_a + v_a * delta_v / (2 * np.sqrt(self.a_a * self.b_a)) accel = self.a_a * (1 - (v_a / v_0) ** self.delta - (s_star / s_a) ** 2) return accel * self.dt
[docs]class PIDController: """ PID controller based on the CARLA PID controller implementation. """ def __init__(self, dt: float = 0.05, args_lateral: Dict[str, float] = None, args_longitudinal: Dict[str, float] = None, max_steering=1.0): """ Constructor method. Args: dt: Discreet temporal difference args_lateral: dictionary of arguments to set the lateral PID controller using the following semantics: K_P -- Proportional term K_D -- Differential term K_I -- Integral term args_longitudinal: dictionary of arguments to set the longitudinal PID controller using the following semantics: K_P -- Proportional term K_D -- Differential term K_I -- Integral term """ if args_lateral is None: args_lateral = {'K_P': 1.95, 'K_I': 0.2, 'K_D': 0.0} if args_longitudinal is None: args_longitudinal = {'K_P': 1.0, 'K_I': 0.05, 'K_D': 0.0} self.max_steer = max_steering self.past_steering = 0.0 self._lon_controller = PIDLongitudinalController(dt=dt, **args_longitudinal) self._lat_controller = PIDLateralController(dt=dt, **args_lateral)
[docs] def next_action(self, target_acceleration, target_steering) -> (float, float): """Execute one step of control invoking both lateral and longitudinal PID controllers to reach a target waypoint at a given target_speed. Args: target_acceleration: Desired acceleration. target_steering: Target steering Returns: Acceleration and steering to execute """ acceleration = self._lon_controller.next_action(target_acceleration) current_steering = self._lat_controller.next_action(target_steering) # Breaking adjustment: breaking is more sudden than speeding up if acceleration < 0: acceleration *= 2. # Steering regulation: changes cannot happen abruptly, can't steer too much. if current_steering > self.past_steering + 0.33: current_steering = self.past_steering + 0.33 elif current_steering < self.past_steering - 0.33: current_steering = self.past_steering - 0.33 if current_steering >= 0: steering = min(self.max_steer, current_steering) else: steering = max(-self.max_steer, current_steering) self.past_steering = steering return acceleration, steering
[docs]class PIDLongitudinalController: """ PIDLongitudinalController implements longitudinal control using a PID. """ def __init__(self, K_P=1.0, K_I=0.0, K_D=0.0, dt=0.05): """ Constructor method. Args: K_P: Proportional term K_D: Differential term K_I: Integral term dt: time differential in seconds """ self._k_p = K_P self._k_i = K_I self._k_d = K_D self._dt = dt self._error_buffer = deque(maxlen=10)
[docs] def next_action(self, acceleration: float): """ Execute one step of longitudinal control to reach a given target speed. Args: acceleration: Target acceleration Returns: acceleration control """ self._error_buffer.append(acceleration) if len(self._error_buffer) >= 2: _de = (self._error_buffer[-1] - self._error_buffer[-2]) / self._dt _ie = sum(self._error_buffer) * self._dt else: _de = 0.0 _ie = 0.0 return (self._k_p * acceleration) + (self._k_d * _de) + (self._k_i * _ie)
[docs]class PIDLateralController: """ PIDLateralController implements lateral control using a PID. """ def __init__(self, K_P=1.0, K_I=0.0, K_D=0.0, dt=0.05): """ Constructor method. Args: K_P: Proportional term K_D: Differential term K_I: Integral term dt: time differential in seconds """ self._k_p = K_P self._k_i = K_I self._k_d = K_D self._dt = dt self._e_buffer = deque(maxlen=10)
[docs] def next_action(self, steering): """Execute one step of lateral control to steer the vehicle towards a certain waypoint. Args: steering: Target steering Returns: steering control """ self._e_buffer.append(steering) if len(self._e_buffer) >= 2: _de = (self._e_buffer[-1] - self._e_buffer[-2]) / self._dt _ie = sum(self._e_buffer) * self._dt else: _de = 0.0 _ie = 0.0 return (self._k_p * steering) + (self._k_d * _de) + (self._k_i * _ie)