예제 #1
0
파일: element.py 프로젝트: Edwardhk/pgdrive
    def __init__(self, random_seed=None, name=None):
        """
        Config is a static conception, which specified the parameters of one element.
        There parameters doesn't change, such as length of straight road, max speed of one vehicle, etc.
        """
        self.name = random_string() if name is None else name
        assert isinstance(
            self.PARAMETER_SPACE, PGSpace
        ) or random_seed is None, "Using PGSpace to define parameter spaces of " + self.class_name
        self._config = PGConfig(
            {k: None
             for k in self.PARAMETER_SPACE.parameters})
        self.random_seed = 0 if random_seed is None else random_seed
        if self.PARAMETER_SPACE is not None:
            self.PARAMETER_SPACE.seed(self.random_seed)
        self.render = False if AssetLoader.loader is None else True

        # each element has its node_path to render, physics node are child nodes of it
        self.node_path = None

        # Temporally store bullet nodes that have to place in bullet world (not NodePath)
        self.dynamic_nodes = PhysicsNodeList()

        # Nodes in this tuple didn't interact with other nodes! they only used to do rayTest or sweepTest
        self.static_nodes = PhysicsNodeList()

        if self.render:
            self.loader = AssetLoader.get_loader()

            if not hasattr(self.loader, "loader"):
                # It is closed before!
                self.loader.__init__()
예제 #2
0
def test_base_vehicle():
    env = PGDriveEnv()
    try:
        env.reset()
        pg_world = env.pg_world
        map = env.current_map

        # v_config = BaseVehicle.get_vehicle_config(dict())
        v_config = PGConfig(BASE_DEFAULT_CONFIG["vehicle_config"]).update(
            PGDriveEnvV1_DEFAULT_CONFIG["vehicle_config"])
        v_config.update({"use_render": False, "use_image": False})
        v = BaseVehicle(pg_world, vehicle_config=v_config)
        v.add_lidar()
        v.add_routing_localization(True)
        v.add_routing_localization(False)
        v.routing_localization.set_force_calculate_lane_index(True)
        v.update_map_info(map)

        for heading in [-1.0, 0.0, 1.0]:
            for pos in [[0., 0.], [-100., -100.], [100., 100.]]:
                v.reset(map, pos=pos, heading=heading)
                np.testing.assert_almost_equal(_get_heading_deg(
                    v.heading_theta),
                                               heading,
                                               decimal=3)

                v_pos = v.position
                # v_pos[1] = -v_pos[1], this position is converted to pg_position in reset() now
                np.testing.assert_almost_equal(v_pos, pos)

                v.set_position(pos)
                v_pos = v.position
                np.testing.assert_almost_equal(v_pos, pos)

                v.update_state(detector_mask=None)
        v.reset(map, pos=np.array([10, 0]))
        for a_x in [-1, 0, 0.5, 1]:
            for a_y in [-1, 0, 0.5, 1]:
                v.prepare_step([a_x, a_y])
                v.set_act([a_x, a_y])
                _assert_vehicle(v)
                v.set_incremental_action([a_x, a_y])
                _assert_vehicle(v)
                state = v.get_state()
                v.set_state(state)
                assert _get_heading_deg(v.heading_theta) == _get_heading_deg(
                    state["heading"])
                np.testing.assert_almost_equal(v.position, state["position"])
                v.projection([a_x, a_y])

        _nan_speed(env)

        v.destroy()
        del v
    finally:
        env.close()
예제 #3
0
def test_config_unchangeable():
    c = PGConfig({"aaa": 100}, unchangeable=True)
    try:
        c['aaa'] = 1000
    except ValueError as e:
        print('Great! ', e)
    assert c['aaa'] == 100
예제 #4
0
 def _get_single_vehicle_config(self, extra_config: dict):
     """
     Newly introduce method
     """
     vehicle_config = merge_dicts(self.config["vehicle_config"],
                                  extra_config,
                                  allow_new_keys=False)
     return PGConfig(vehicle_config)
예제 #5
0
def merge_config(old_dict, new_dict, new_keys_allowed=False):
    from pgdrive.utils import PGConfig
    if isinstance(old_dict, PGConfig):
        old_dict = old_dict.get_dict()
    if isinstance(new_dict, PGConfig):
        new_dict = new_dict.get_dict()
    merged = merge_dicts(old_dict, new_dict, allow_new_keys=new_keys_allowed)
    return PGConfig(merged)
예제 #6
0
 def _update_dict_item(self, k, v, allow_overwrite):
     if not isinstance(v, (dict, PGConfig)):
         if allow_overwrite:
             return False
         else:
             raise TypeError(
                 "Type error! The item {} has original type {} and updating type {}.".format(
                     k, type(self[k]), type(v)
                 )
             )
     if not isinstance(self[k], PGConfig):
         self._set_item(k, PGConfig(self[k]), allow_overwrite)
     self[k].update(v, allow_overwrite=allow_overwrite)
     return True
예제 #7
0
    def __init__(self, config: dict = None):
        self.default_config_copy = PGConfig(self.default_config(),
                                            unchangeable=True)
        merged_config = self._process_extra_config(config)
        self.config = self._post_process_config(merged_config)

        self.num_agents = self.config["num_agents"]
        self.is_multi_agent = self.config["is_multi_agent"]
        if not self.is_multi_agent:
            assert self.num_agents == 1
        assert isinstance(self.num_agents, int) and (self.num_agents > 0
                                                     or self.num_agents == -1)

        # observation and action space
        self.agent_manager = AgentManager(
            init_observations=self._get_observations(),
            never_allow_respawn=not self.config["allow_respawn"],
            debug=self.config["debug"],
            delay_done=self.config["delay_done"],
            infinite_agents=self.num_agents == -1)
        self.agent_manager.init_space(
            init_observation_space=self._get_observation_space(),
            init_action_space=self._get_action_space())

        # map setting
        self.start_seed = self.config["start_seed"]
        self.env_num = self.config["environment_num"]

        # lazy initialization, create the main vehicle in the lazy_init() func
        self.pg_world: Optional[PGWorld] = None
        self.scene_manager: Optional[SceneManager] = None
        self.main_camera = None
        self.controller = None
        self.restored_maps = dict()
        self.episode_steps = 0

        self.maps = {
            _seed: None
            for _seed in range(self.start_seed, self.start_seed + self.env_num)
        }
        self.current_seed = self.start_seed
        self.current_map = None

        self.dones = None
        self.episode_rewards = defaultdict(float)
        # In MARL envs with respawn mechanism, varying episode lengths might happen.
        self.episode_lengths = defaultdict(int)
        self._pending_force_seed = None
예제 #8
0
 def _update_spawn_roads_with_configs(self, spawn_roads=None):
     assert self.num_agents <= len(self.target_vehicle_configs), (
         "Too many agents! We only accept {} agents, which is specified by the number of configs in "
         "target_vehicle_configs, but you have {} agents! "
         "You should require less agent or not to specify the target_vehicle_configs!"
         .format(len(self.target_vehicle_configs), self.num_agents))
     target_vehicle_configs = []
     safe_spawn_places = []
     for v_id, v_config in self.target_vehicle_configs.items():
         lane_tuple = v_config["spawn_lane_index"]
         target_vehicle_configs.append(
             PGConfig(dict(identifier="|".join(
                 (str(s) for s in lane_tuple)),
                           config=v_config,
                           force_agent_name=v_id),
                      unchangeable=True))
         safe_spawn_places.append(target_vehicle_configs[-1].copy())
     return target_vehicle_configs, safe_spawn_places
예제 #9
0
    def _update_spawn_roads_randomly(self, spawn_roads):
        assert not self.custom_target_vehicle_config, "This will overwrite your custom target vehicle config"
        assert len(spawn_roads) > 0
        interval = self.RESPAWN_REGION_LONGITUDE
        num_slots = int(floor(self.exit_length / interval))
        assert num_slots > 0, "The exist length {} should greater than minimal longitude interval {}.".format(
            self.exit_length, interval)
        interval = self.exit_length / num_slots
        self._longitude_spawn_interval = interval
        if self.num_agents is not None:
            assert self.num_agents > 0 or self.num_agents == -1
            assert self.num_agents <= self.lane_num * len(
                spawn_roads
            ) * num_slots, (
                "Too many agents! We only accepet {} agents, but you have {} agents!"
                .format(self.lane_num * len(spawn_roads) * num_slots,
                        self.num_agents))

        # We can spawn agents in the middle of road at the initial time, but when some vehicles need to be respawn,
        # then we have to set it to the farthest places to ensure safety (otherwise the new vehicles may suddenly
        # appear at the middle of the road!)
        target_vehicle_configs = []
        safe_spawn_places = []
        for i, road in enumerate(spawn_roads):
            for lane_idx in range(self.lane_num):
                for j in range(num_slots):
                    long = 1 / 2 * self.RESPAWN_REGION_LONGITUDE + j * self.RESPAWN_REGION_LONGITUDE
                    lane_tuple = road.lane_index(
                        lane_idx)  # like (>>>, 1C0_0_, 1) and so on.
                    target_vehicle_configs.append(
                        PGConfig(
                            dict(identifier="|".join(
                                (str(s) for s in lane_tuple + (j, ))),
                                 config={
                                     "spawn_lane_index": lane_tuple,
                                     "spawn_longitude": long,
                                     "spawn_lateral": 0
                                 },
                                 force_agent_name=None),
                            unchangeable=True))  # lock the spawn positions
                    if j == 0:
                        safe_spawn_places.append(
                            target_vehicle_configs[-1].copy())
        return target_vehicle_configs, safe_spawn_places
예제 #10
0
파일: map.py 프로젝트: Edwardhk/pgdrive
    def __init__(self, pg_world: PGWorld, map_config: dict = None):
        """
        Map can be stored and recover to save time when we access the map encountered before
        """
        self.config = PGConfig(map_config)
        self.film_size = (self.config["draw_map_resolution"],
                          self.config["draw_map_resolution"])
        self.random_seed = self.config[self.SEED]
        self.road_network = RoadNetwork()

        # A flatten representation of blocks, might cause chaos in city-level generation.
        self.blocks = []

        # Generate map and insert blocks
        self._generate(pg_world)
        assert self.blocks, "The generate methods does not fill blocks!"

        #  a trick to optimize performance
        self.road_network.after_init()
예제 #11
0
 def update(self, new_dict: Union[dict, "PGConfig"], allow_overwrite=True, stop_recursive_update=None):
     """
     Update this dict with extra configs
     :param new_dict: extra configs
     :param allow_overwrite: whether allowing to add new keys to existing configs or not
     :param stop_recursive_update: Deep update and recursive-check will NOT be applied to keys in stop_recursive_update
     :return: None
     """
     stop_recursive_update = stop_recursive_update or []
     new_dict = new_dict or dict()
     new_dict = copy.deepcopy(new_dict)
     if not allow_overwrite:
         old_keys = set(self._config)
         new_keys = set(new_dict)
         diff = new_keys.difference(old_keys)
         if len(diff) > 0:
             raise KeyError(
                 "'{}' does not exist in existing config. "
                 "Please use config.update(...) to update the config. Existing keys: {}.".format(
                     diff, self._config.keys()
                 )
             )
     for k, v in new_dict.items():
         if k not in self:
             if isinstance(v, dict):
                 v = PGConfig(v)
             self._config[k] = v  # Placeholder
         success = False
         if isinstance(self._config[k], (dict, PGConfig)):
             if k not in stop_recursive_update:
                 success = self._update_dict_item(k, v, allow_overwrite)
             else:
                 self._set_item(k, v, allow_overwrite)
                 success = True
         if not success:
             self._update_single_item(k, v, allow_overwrite)
         if k in self._config and not hasattr(self, k):
             self.__setattr__(k, self._config[k])
     return self
예제 #12
0
파일: element.py 프로젝트: Edwardhk/pgdrive
class Element:
    """
    Element class are base class of all static objects, whose properties are fixed after calling init().
    They have no any desire to change its state, e.g. moving, bouncing, changing color.
    Instead, only other Elements or DynamicElements can affect them and change their states.
    """

    PARAMETER_SPACE = PGSpace({})

    def __init__(self, random_seed=None, name=None):
        """
        Config is a static conception, which specified the parameters of one element.
        There parameters doesn't change, such as length of straight road, max speed of one vehicle, etc.
        """
        self.name = random_string() if name is None else name
        assert isinstance(
            self.PARAMETER_SPACE, PGSpace
        ) or random_seed is None, "Using PGSpace to define parameter spaces of " + self.class_name
        self._config = PGConfig(
            {k: None
             for k in self.PARAMETER_SPACE.parameters})
        self.random_seed = 0 if random_seed is None else random_seed
        if self.PARAMETER_SPACE is not None:
            self.PARAMETER_SPACE.seed(self.random_seed)
        self.render = False if AssetLoader.loader is None else True

        # each element has its node_path to render, physics node are child nodes of it
        self.node_path = None

        # Temporally store bullet nodes that have to place in bullet world (not NodePath)
        self.dynamic_nodes = PhysicsNodeList()

        # Nodes in this tuple didn't interact with other nodes! they only used to do rayTest or sweepTest
        self.static_nodes = PhysicsNodeList()

        if self.render:
            self.loader = AssetLoader.get_loader()

            if not hasattr(self.loader, "loader"):
                # It is closed before!
                self.loader.__init__()

    @property
    def class_name(self):
        return self.__class__.__name__

    def get_config(self, copy=True):
        if copy:
            return self._config.copy()
        return self._config

    def set_config(self, config: dict):
        # logging.debug("Read config to " + self.class_name)
        self._config.update(config)

    def attach_to_pg_world(self, parent_node_path: NodePath,
                           pg_physics_world: PGPhysicsWorld):
        if self.render:
            # double check :-)
            assert isinstance(
                self.node_path,
                NodePath), "No render model on node_path in this Element"
            self.node_path.reparentTo(parent_node_path)
        self.dynamic_nodes.attach_to_physics_world(
            pg_physics_world.dynamic_world)
        self.static_nodes.attach_to_physics_world(
            pg_physics_world.static_world)

    def detach_from_pg_world(self, pg_physics_world: PGPhysicsWorld):
        """
        It is not fully remove, if this element is useless in the future, call Func delete()
        """
        self.node_path.detachNode()
        self.dynamic_nodes.detach_from_physics_world(
            pg_physics_world.dynamic_world)
        self.static_nodes.detach_from_physics_world(
            pg_physics_world.static_world)

    def destroy(self, pg_world):
        """
        Fully delete this element and release the memory
        """
        self.detach_from_pg_world(pg_world.physics_world)
        self.node_path.removeNode()
        self.dynamic_nodes.clear()
        self.static_nodes.clear()
        self._config.clear()

    def __del__(self):
        logging.debug("{} is destroyed".format(self.class_name))

    @property
    def heading_theta(self):
        return 0.0  # Not used!
예제 #13
0
    def __init__(
        self,
        pg_world: PGWorld,
        vehicle_config: Union[dict, PGConfig] = None,
        physics_config: dict = None,
        random_seed: int = 0,
        name: str = None,
    ):
        """
        This Vehicle Config is different from self.get_config(), and it is used to define which modules to use, and
        module parameters. And self.physics_config defines the physics feature of vehicles, such as length/width
        :param pg_world: PGWorld
        :param vehicle_config: mostly, vehicle module config
        :param physics_config: vehicle height/width/length, find more physics para in VehicleParameterSpace
        :param random_seed: int
        """
        self.vehicle_config = PGConfig(vehicle_config)

        # self.vehicle_config = self.get_vehicle_config(vehicle_config) \
        #     if vehicle_config is not None else self._default_vehicle_config()

        # observation, action
        self.action_space = self.get_action_space_before_init(
            extra_action_dim=self.vehicle_config["extra_action_dim"])

        super(BaseVehicle, self).__init__(random_seed, name=name)
        # config info
        self.set_config(self.PARAMETER_SPACE.sample())
        if physics_config is not None:
            self.set_config(physics_config)
        self.increment_steering = self.vehicle_config["increment_steering"]
        self.enable_reverse = self.vehicle_config["enable_reverse"]
        self.max_speed = self.vehicle_config["max_speed"]
        self.max_steering = self.vehicle_config["max_steering"]

        self.pg_world = pg_world
        self.node_path = NodePath("vehicle")

        # create
        self.spawn_place = (0, 0)
        self._add_chassis(pg_world.physics_world)
        self.wheels = self._create_wheel()

        # modules
        self.image_sensors = {}
        self.lidar: Optional[Lidar] = None
        self.side_detector: Optional[SideDetector] = None
        self.lane_line_detector: Optional[LaneLineDetector] = None
        self.routing_localization: Optional[RoutingLocalizationModule] = None
        self.lane: Optional[AbstractLane] = None
        self.lane_index = None
        self.vehicle_panel = VehiclePanel(self.pg_world) if (
            self.pg_world.mode == RENDER_MODE_ONSCREEN) else None

        # state info
        self.throttle_brake = 0.0
        self.steering = 0
        self.last_current_action = deque([(0.0, 0.0), (0.0, 0.0)], maxlen=2)
        self.last_position = self.spawn_place
        self.last_heading_dir = self.heading
        self.dist_to_left_side = None
        self.dist_to_right_side = None

        # collision info render
        self.collision_info_np = self._init_collision_info_render(pg_world)
        self.collision_banners = {}  # to save time
        self.current_banner = None
        self.attach_to_pg_world(self.pg_world.pbr_render,
                                self.pg_world.physics_world)

        # step info
        self.out_of_route = None
        self.on_lane = None
        # self.step_info = None
        self._init_step_info()

        # others
        self._add_modules_for_vehicle(self.vehicle_config["use_render"])
        self.takeover = False
        self._expert_takeover = False
        self.energy_consumption = 0

        # overtake_stat
        self.front_vehicles = set()
        self.back_vehicles = set()
예제 #14
0
 def default_config(cls) -> "PGConfig":
     return PGConfig(BASE_DEFAULT_CONFIG)
예제 #15
0
 def copy(self, unchangeable=None):
     """If unchangeable is None, then just following the original config's setting."""
     if unchangeable is None:
         unchangeable = self._unchangeable
     return PGConfig(self, unchangeable)