def steering_control(self, target_lane_index):
        """
            Steer the vehicle to follow the center of an given lane.

        1. Lateral position is controlled by a proportional controller yielding a lateral velocity command
        2. Lateral velocity command is converted to a heading reference
        3. Heading is controlled by a proportional controller yielding a heading rate command
        4. Heading rate command is converted to a steering angle

        :param target_lane_index: index of the lane to follow
        :return: a steering wheel angle command [rad]
        """

        target_lane = self.road.network.get_lane(target_lane_index)
        lane_coords = target_lane.local_coordinates(self.position)
        lane_next_coords = lane_coords[0] + self.velocity * self.PURSUIT_TAU
        lane_future_heading = target_lane.heading_at(lane_next_coords)

        # Lateral position control
        lateral_velocity_command = -self.KP_LATERAL * lane_coords[1]
        # Lateral velocity to heading
        heading_command = np.arcsin(
            np.clip(lateral_velocity_command / utils.not_zero(self.velocity),
                    -1, 1))
        heading_ref = lane_future_heading + np.clip(heading_command,
                                                    -np.pi / 4, np.pi / 4)
        # Heading control
        heading_rate_command = self.KP_HEADING * utils.wrap_to_pi(heading_ref -
                                                                  self.heading)
        # Heading rate to steering angle
        steering_angle = np.arctan(
            self.LENGTH / utils.not_zero(self.velocity) * heading_rate_command)
        steering_angle = np.clip(steering_angle, -self.MAX_STEERING_ANGLE,
                                 self.MAX_STEERING_ANGLE)
        return steering_angle
Example #2
0
 def local_coordinates(self, position: np.ndarray) -> Tuple[float, float]:
     delta = position - self.center
     phi = np.arctan2(delta[1], delta[0])
     phi = self.start_phase + utils.wrap_to_pi(phi - self.start_phase)
     r = np.linalg.norm(delta)
     longitudinal = self.direction * (phi - self.start_phase) * self.radius
     lateral = self.direction * (self.radius - r)
     return longitudinal, lateral
Example #3
0
 def distance_with_heading(self,
                           position: np.ndarray,
                           heading: Optional[float],
                           heading_weight: float = 1.0):
     """Compute a weighted distance in position and heading to the lane."""
     if heading is None:
         return self.distance(position)
     s, r = self.local_coordinates(position)
     angle = np.abs(wrap_to_pi(heading - self.heading_at(s)))
     return abs(r) + max(s - self.length, 0) + max(
         0 - s, 0) + heading_weight * angle
 def steering_features(self, target_lane_index):
     """
         A collection of features used to follow a lane
     :param target_lane_index: index of the lane to follow
     :return: a array of features
     """
     lane = self.road.network.get_lane(target_lane_index)
     lane_coords = lane.local_coordinates(self.position)
     lane_next_coords = lane_coords[0] + self.velocity * self.PURSUIT_TAU
     lane_future_heading = lane.heading_at(lane_next_coords)
     features = np.array([utils.wrap_to_pi(lane_future_heading - self.heading) *
                          self.LENGTH / utils.not_zero(self.velocity),
                          -lane_coords[1] * self.LENGTH / (utils.not_zero(self.velocity) ** 2)])
     return features