Source code for highway_env.envs.two_way_env

from __future__ import annotations

import numpy as np

from highway_env import utils
from highway_env.envs.common.abstract import AbstractEnv
from highway_env.road.lane import LineType, StraightLane
from highway_env.road.road import Road, RoadNetwork


[docs] class TwoWayEnv(AbstractEnv): """ A risk management task: the agent is driving on a two-way lane with icoming traffic. It must balance making progress by overtaking and ensuring safety. These conflicting objectives are implemented by a reward signal and a constraint signal, in the CMDP/BMDP framework. """
[docs] @classmethod def default_config(cls) -> dict: config = super().default_config() config.update( { "observation": {"type": "TimeToCollision", "horizon": 5}, "action": { "type": "DiscreteMetaAction", }, "collision_reward": 0, "left_lane_constraint": 1, "left_lane_reward": 0.2, "high_speed_reward": 0.8, } ) return config
def _reward(self, action: int) -> float: """ The vehicle is rewarded for driving with high speed :param action: the action performed :return: the reward of the state-action transition """ return sum( self.config.get(name, 0) * reward for name, reward in self._rewards(action).items() ) def _rewards(self, action: int) -> dict[str, float]: neighbours = self.road.network.all_side_lanes(self.vehicle.lane_index) return { "high_speed_reward": self.vehicle.speed_index / (self.vehicle.target_speeds.size - 1), "left_lane_reward": ( len(neighbours) - 1 - self.vehicle.target_lane_index[2] ) / (len(neighbours) - 1), } def _is_terminated(self) -> bool: """The episode is over if the ego vehicle crashed or the time is out.""" return self.vehicle.crashed def _is_truncated(self) -> bool: return False def _reset(self) -> np.ndarray: self._make_road() self._make_vehicles() def _make_road(self, length=800): """ Make a road composed of a two-way road. :return: the road """ net = RoadNetwork() # Lanes net.add_lane( "a", "b", StraightLane( [0, 0], [length, 0], line_types=(LineType.CONTINUOUS_LINE, LineType.STRIPED), ), ) net.add_lane( "a", "b", StraightLane( [0, StraightLane.DEFAULT_WIDTH], [length, StraightLane.DEFAULT_WIDTH], line_types=(LineType.NONE, LineType.CONTINUOUS_LINE), ), ) net.add_lane( "b", "a", StraightLane( [length, 0], [0, 0], line_types=(LineType.NONE, LineType.NONE) ), ) road = Road( network=net, np_random=self.np_random, record_history=self.config["show_trajectories"], neighbour_vehicles_connected_lanes=self.config[ "neighbour_vehicles_connected_lanes" ], ) self.road = road def _make_vehicles(self) -> None: """ Populate a road with several vehicles on the road :return: the ego-vehicle """ road = self.road ego_vehicle = self.action_type.vehicle_class( road, road.network.get_lane(("a", "b", 1)).position(30.0, 0.0), speed=30.0 ) road.vehicles.append(ego_vehicle) self.vehicle = ego_vehicle vehicles_type = utils.class_from_path(self.config["other_vehicles_type"]) for i in range(3): self.road.vehicles.append( vehicles_type( road, position=road.network.get_lane(("a", "b", 1)).position( 70.0 + 40.0 * float(i) + 10.0 * self.np_random.normal(), 0.00 ), heading=road.network.get_lane(("a", "b", 1)).heading_at( 70.0 + 40.0 * float(i) ), speed=24.0 + 2.0 * self.np_random.normal(), enable_lane_change=False, ) ) for i in range(2): v = vehicles_type( road, position=road.network.get_lane(("b", "a", 0)).position( 200.0 + 100.0 * float(i) + 10.0 * self.np_random.normal(), 0 ), heading=road.network.get_lane(("b", "a", 0)).heading_at( 200.0 + 100.0 * float(i) ), speed=20.0 + 5.0 * self.np_random.normal(), enable_lane_change=False, ) v.target_lane_index = ("b", "a", 0) self.road.vehicles.append(v)