def __init__(self, name, namespace, model_name):
     if not name or not isinstance(name, str):
         raise GenericRolloutException("Camera name cannot be None or empty string")
     self._name = name
     self._model_name = model_name or self._name
     self._namespace = namespace or "default"
     self.lock = threading.Lock()
     self.is_reset_called = False
     self.spawn_sdf_model = ServiceProxyWrapper(SPAWN_SDF_MODEL, SpawnModel)
     CameraManager.get_instance().add(self, namespace)
Esempio n. 2
0
    def _spawn_cameras(self):
        '''helper method for initializing cameras
        '''
        # virtual event configure camera does not need to wait for car to spawm because
        # follow car camera is not tracking any car initially
        camera_manager = CameraManager.get_instance()

        # pop all camera under virtual event namespace
        camera_manager.pop(namespace=VIRTUAL_EVENT)

        # Spawn the follow car camera
        LOG.info(
            "[virtual event manager] Spawning virtual event follow car camera model"
        )
        initial_pose = self._track_data.get_racecar_start_pose(
            racecar_idx=0,
            racer_num=1,
            start_position=get_start_positions(1)[0])
        self._main_cameras[VIRTUAL_EVENT].spawn_model(
            initial_pose,
            os.path.join(self._deepracer_path, "models", "camera",
                         "model.sdf"))

        LOG.info("[virtual event manager] Spawning sub camera model")
        # Spawn the top camera model
        self._sub_camera.spawn_model(
            None,
            os.path.join(self._deepracer_path, "models", "top_camera",
                         "model.sdf"))
Esempio n. 3
0
 def __init__(self, config_dict, run_phase_sink, metrics):
     '''agent_name - String containing the name of the agent
        config_dict - Dictionary containing all the keys in ConfigParams
        run_phase_sink - Sink to recieve notification of a change in run phase
     '''
     # reset rules manager
     self._metrics = metrics
     self._is_continuous = config_dict[const.ConfigParams.IS_CONTINUOUS.value]
     self._is_reset = False
     self._pause_count = 0
     self._reset_rules_manager = construct_reset_rules_manager(config_dict)
     self._ctrl_status = dict()
     self._ctrl_status[AgentCtrlStatus.AGENT_PHASE.value] = AgentPhase.RUN.value
     self._config_dict = config_dict
     self._number_of_resets = config_dict[const.ConfigParams.NUMBER_OF_RESETS.value]
     self._off_track_penalty = config_dict[const.ConfigParams.OFF_TRACK_PENALTY.value]
     self._collision_penalty = config_dict[const.ConfigParams.COLLISION_PENALTY.value]
     self._pause_end_time = 0.0
     self._reset_count = 0
     # simapp_version speed scale
     self._speed_scale_factor_ = get_speed_factor(config_dict[const.ConfigParams.VERSION.value])
     # Store the name of the agent used to set agents position on the track
     self._agent_name_ = config_dict[const.ConfigParams.AGENT_NAME.value]
     # Store the name of the links in the agent, this should be const
     self._agent_link_name_list_ = config_dict[const.ConfigParams.LINK_NAME_LIST.value]
     # Store the reward function
     self._reward_ = config_dict[const.ConfigParams.REWARD.value]
     self._track_data_ = TrackData.get_instance()
     # Create publishers for controlling the car
     self._velocity_pub_dict_ = OrderedDict()
     self._steering_pub_dict_ = OrderedDict()
     for topic in config_dict[const.ConfigParams.VELOCITY_LIST.value]:
         self._velocity_pub_dict_[topic] = rospy.Publisher(topic, Float64, queue_size=1)
     for topic in config_dict[const.ConfigParams.STEERING_LIST.value]:
         self._steering_pub_dict_[topic] = rospy.Publisher(topic, Float64, queue_size=1)
     #Create default reward parameters
     self._reward_params_ = const.RewardParam.make_default_param()
     #Creat the default metrics dictionary
     self._step_metrics_ = StepMetrics.make_default_metric()
     # State variable to track if the car direction has been reversed
     self._reverse_dir_ = False
     # Dictionary of bools indicating starting position behavior
     self._start_pos_behavior_ = \
         {'change_start' : config_dict[const.ConfigParams.CHANGE_START.value],
          'alternate_dir' : config_dict[const.ConfigParams.ALT_DIR.value]}
     # Dictionary to track the previous way points
     self._prev_waypoints_ = {'prev_point' : Point(0, 0), 'prev_point_2' : Point(0, 0)}
     # Dictionary containing some of the data for the agent
     self._data_dict_ = {'max_progress': 0.0,
                         'current_progress': 0.0,
                         'prev_progress': 0.0,
                         'steps': 0.0,
                         'start_ndist': 0.0}
     #Load the action space
     self._action_space_, self._json_actions_ = \
         load_action_space(config_dict[const.ConfigParams.ACTION_SPACE_PATH.value])
     #! TODO evaluate if this is the best way to reset the car
     rospy.wait_for_service(SET_MODEL_STATE)
     rospy.wait_for_service(GET_MODEL_STATE)
     self.set_model_state = ServiceProxyWrapper(SET_MODEL_STATE, SetModelState)
     self.get_model_client = ServiceProxyWrapper(GET_MODEL_STATE, GetModelState)
     # Adding the reward data publisher
     self.reward_data_pub = RewardDataPublisher(self._agent_name_, self._json_actions_)
     # init time
     self.last_time = 0.0
     self.curr_time = 0.0
     # subscriber to time to update camera position
     self.camera_manager = CameraManager.get_instance()
     # True if the agent is in the training phase
     self._is_training_ = False
     rospy.Subscriber('/clock', Clock, self._update_sim_time)
     # Register to the phase sink
     run_phase_sink.register(self)
     # Make sure velicty and angle are set to 0
     send_action(self._velocity_pub_dict_, self._steering_pub_dict_, 0.0, 0.0)
     start_pose = self._track_data_._center_line_.interpolate_pose(self._data_dict_['start_ndist'] * self._track_data_.get_track_length(),
                                                                   reverse_dir=self._reverse_dir_,
                                                                   finite_difference=FiniteDifference.FORWARD_DIFFERENCE)
     self._track_data_.initialize_object(self._agent_name_, start_pose, ObstacleDimensions.BOT_CAR_DIMENSION)
     self.car_model_state = self.get_model_client(self._agent_name_, '')
     self._reset_agent(reset_pos=const.ResetPos.START_POS.value)
    def __init__(self, config_dict, run_phase_sink, metrics):
        '''config_dict (dict): containing all the keys in ConfigParams
           run_phase_sink (RunPhaseSubject): Sink to receive notification of a change in run phase
           metrics (EvalMetrics/TrainingMetrics): Training or evaluation metrics
        '''
        # reset rules manager
        self._metrics = metrics
        self._is_continuous = config_dict[
            const.ConfigParams.IS_CONTINUOUS.value]
        self._reset_rules_manager = construct_reset_rules_manager(config_dict)
        self._ctrl_status = dict()
        self._ctrl_status[
            AgentCtrlStatus.AGENT_PHASE.value] = AgentPhase.RUN.value
        self._config_dict = config_dict
        self._done_condition = config_dict.get(
            const.ConfigParams.DONE_CONDITION.value, any)
        self._number_of_resets = config_dict[
            const.ConfigParams.NUMBER_OF_RESETS.value]
        self._off_track_penalty = config_dict[
            const.ConfigParams.OFF_TRACK_PENALTY.value]
        self._collision_penalty = config_dict[
            const.ConfigParams.COLLISION_PENALTY.value]
        self._pause_duration = 0.0
        self._reset_count = 0
        self._curr_crashed_object_name = ''
        # simapp_version speed scale
        self._speed_scale_factor_ = get_speed_factor(
            config_dict[const.ConfigParams.VERSION.value])
        # Store the name of the agent used to set agents position on the track
        self._agent_name_ = config_dict[const.ConfigParams.AGENT_NAME.value]
        # Set start lane. This only support for two agents H2H race
        self._agent_idx_ = get_racecar_idx(self._agent_name_)
        # Get track data
        self._track_data_ = TrackData.get_instance()
        if self._agent_idx_ is not None:
            self._start_lane_ = self._track_data_.inner_lane \
                if self._agent_idx_ % 2 else self._track_data_.outer_lane
        else:
            self._start_lane_ = self._track_data_.center_line
        # Store the name of the links in the agent, this should be const
        self._agent_link_name_list_ = config_dict[
            const.ConfigParams.LINK_NAME_LIST.value]
        # Store the reward function
        self._reward_ = config_dict[const.ConfigParams.REWARD.value]
        # Create publishers for controlling the car
        self._velocity_pub_dict_ = OrderedDict()
        self._steering_pub_dict_ = OrderedDict()
        for topic in config_dict[const.ConfigParams.VELOCITY_LIST.value]:
            self._velocity_pub_dict_[topic] = rospy.Publisher(topic,
                                                              Float64,
                                                              queue_size=1)
        for topic in config_dict[const.ConfigParams.STEERING_LIST.value]:
            self._steering_pub_dict_[topic] = rospy.Publisher(topic,
                                                              Float64,
                                                              queue_size=1)
        #Create default reward parameters
        self._reward_params_ = const.RewardParam.make_default_param()
        #Create the default metrics dictionary
        self._step_metrics_ = StepMetrics.make_default_metric()
        # Dictionary of bools indicating starting position behavior
        self._start_pos_behavior_ = \
            {'change_start' : config_dict[const.ConfigParams.CHANGE_START.value],
             'alternate_dir' : config_dict[const.ConfigParams.ALT_DIR.value]}
        # Dictionary to track the previous way points
        self._prev_waypoints_ = {
            'prev_point': Point(0, 0),
            'prev_point_2': Point(0, 0)
        }

        # Normalized distance of new start line from the original start line of the track.
        start_ndist = 0.0

        # Normalized start position offset w.r.t to start_ndist, which is the start line of the track.
        start_pos_offset = config_dict.get(
            const.ConfigParams.START_POSITION.value, 0.0)
        self._start_line_ndist_offset = start_pos_offset / self._track_data_.get_track_length(
        )

        # Dictionary containing some of the data for the agent
        # - During the reset call, every value except start_ndist will get wiped out by self._clear_data
        #   (reset happens prior to every episodes begin)
        # - If self._start_line_ndist_offset is not 0 (usually some minus value),
        #   then initial current_progress suppose to be non-zero (usually some minus value) as progress
        #   suppose to be based on start_ndist.
        # - This will be correctly calculated by first call of utils.compute_current_prog function.
        #   As prev_progress will be initially 0.0 and physical position is not at start_ndist,
        #   utils.compute_current_prog will return negative progress if self._start_line_ndist_offset is negative value
        #   (meaning behind start line) and will return positive progress if self._start_line_ndist_offset is
        #   positive value (meaning ahead of start line).
        self._data_dict_ = {
            'max_progress': 0.0,
            'current_progress': 0.0,
            'prev_progress': 0.0,
            'steps': 0.0,
            'start_ndist': start_ndist,
            'prev_car_pose': 0.0
        }

        #Load the action space
        self._action_space_, self._json_actions_ = \
            load_action_space(config_dict[const.ConfigParams.ACTION_SPACE_PATH.value])
        #! TODO evaluate if this is the best way to reset the car
        # Adding the reward data publisher
        self.reward_data_pub = RewardDataPublisher(self._agent_name_,
                                                   self._json_actions_)
        # subscriber to time to update camera position
        self.camera_manager = CameraManager.get_instance()
        # True if the agent is in the training phase
        self._is_training_ = False
        # Register to the phase sink
        run_phase_sink.register(self)
        # Make sure velocity and angle are set to 0
        send_action(self._velocity_pub_dict_, self._steering_pub_dict_, 0.0,
                    0.0)

        # start_dist should be hypothetical start line (start_ndist) plus
        # start position offset (start_line_ndist_offset).
        start_pose = self._start_lane_.interpolate_pose(
            (self._data_dict_['start_ndist'] + self._start_line_ndist_offset) *
            self._track_data_.get_track_length(),
            finite_difference=FiniteDifference.FORWARD_DIFFERENCE)
        self._track_data_.initialize_object(self._agent_name_, start_pose, \
                                            ObstacleDimensions.BOT_CAR_DIMENSION)

        self.make_link_points = lambda link_state: Point(
            link_state.pose.position.x, link_state.pose.position.y)
        self.reference_frames = ['' for _ in self._agent_link_name_list_]

        self._pause_car_model_pose = None
        self._park_position = DEFAULT_PARK_POSITION
        AbstractTracker.__init__(self, TrackerPriority.HIGH)
Esempio n. 5
0
    def __init__(self,
                 queue_url,
                 aws_region='us-east-1',
                 race_duration=180,
                 number_of_trials=3,
                 number_of_resets=10000,
                 penalty_seconds=2.0,
                 off_track_penalty=2.0,
                 collision_penalty=5.0,
                 is_continuous=False,
                 race_type="TIME_TRIAL"):
        # constructor arguments
        self._model_updater = ModelUpdater.get_instance()
        self._deepracer_path = rospkg.RosPack().get_path(
            DeepRacerPackages.DEEPRACER_SIMULATION_ENVIRONMENT)
        body_shell_path = os.path.join(self._deepracer_path, "meshes", "f1")
        self._valid_body_shells = \
            set(".".join(f.split(".")[:-1]) for f in os.listdir(body_shell_path) if os.path.isfile(
                os.path.join(body_shell_path, f)))
        self._valid_body_shells.add(const.BodyShellType.DEFAULT.value)
        self._valid_car_colors = set(e.value for e in const.CarColorType
                                     if "f1" not in e.value)
        self._num_sectors = int(rospy.get_param("NUM_SECTORS", "3"))
        self._queue_url = queue_url
        self._region = aws_region
        self._number_of_trials = number_of_trials
        self._number_of_resets = number_of_resets
        self._penalty_seconds = penalty_seconds
        self._off_track_penalty = off_track_penalty
        self._collision_penalty = collision_penalty
        self._is_continuous = is_continuous
        self._race_type = race_type
        self._is_save_simtrace_enabled = False
        self._is_save_mp4_enabled = False
        self._is_event_end = False
        self._done_condition = any
        self._race_duration = race_duration
        self._enable_domain_randomization = False

        # sqs client
        # The boto client errors out after polling for 1 hour.
        self._sqs_client = SQSClient(queue_url=self._queue_url,
                                     region_name=self._region,
                                     max_num_of_msg=MAX_NUM_OF_SQS_MESSAGE,
                                     wait_time_sec=SQS_WAIT_TIME_SEC,
                                     session=refreshed_session(self._region))
        self._s3_client = S3Client(region_name=self._region)
        # tracking current state information
        self._track_data = TrackData.get_instance()
        self._start_lane = self._track_data.center_line
        # keep track of the racer specific info, e.g. s3 locations, alias, car color etc.
        self._current_racer = None
        # keep track of the current race car we are using. It is always "racecar".
        car_model_state = ModelState()
        car_model_state.model_name = "racecar"
        self._current_car_model_state = car_model_state
        self._last_body_shell_type = None
        self._last_sensors = None
        self._racecar_model = AgentModel()
        # keep track of the current control agent we are using
        self._current_agent = None
        # keep track of the current control graph manager
        self._current_graph_manager = None
        # Keep track of previous model's name
        self._prev_model_name = None
        self._hide_position_idx = 0
        self._hide_positions = get_hide_positions(race_car_num=1)
        self._run_phase_subject = RunPhaseSubject()
        self._simtrace_video_s3_writers = []

        self._local_model_directory = './checkpoint'

        # virtual event only have single agent, so set agent_name to "agent"
        self._agent_name = "agent"

        # camera manager
        self._camera_manager = CameraManager.get_instance()

        # setting up virtual event top and follow camera in CameraManager
        # virtual event configure camera does not need to wait for car to spawm because
        # follow car camera is not tracking any car initially
        self._main_cameras, self._sub_camera = configure_camera(
            namespaces=[VIRTUAL_EVENT], is_wait_for_model=False)
        self._spawn_cameras()

        # pop out all cameras after configuration to prevent camera from moving
        self._camera_manager.pop(namespace=VIRTUAL_EVENT)

        dummy_metrics_s3_config = {
            MetricsS3Keys.METRICS_BUCKET.value: "dummy-bucket",
            MetricsS3Keys.METRICS_KEY.value: "dummy-key",
            MetricsS3Keys.REGION.value: self._region
        }

        self._eval_metrics = EvalMetrics(
            agent_name=self._agent_name,
            s3_dict_metrics=dummy_metrics_s3_config,
            is_continuous=self._is_continuous,
            pause_time_before_start=PAUSE_TIME_BEFORE_START)

        # upload a default best sector time for all sectors with time inf for each sector
        # if there is not best sector time existed in s3

        # use the s3 bucket and prefix for yaml file stored as environment variable because
        # here is SimApp use only. For virtual event there is no s3 bucket and prefix past
        # through yaml file. All are past through sqs. For simplicity, reuse the yaml s3 bucket
        # and prefix environment variable.
        virtual_event_best_sector_time = VirtualEventBestSectorTime(
            bucket=os.environ.get("YAML_S3_BUCKET", ''),
            s3_key=get_s3_key(os.environ.get("YAML_S3_PREFIX", ''),
                              SECTOR_TIME_S3_POSTFIX),
            region_name=os.environ.get("APP_REGION", "us-east-1"),
            local_path=SECTOR_TIME_LOCAL_PATH)
        response = virtual_event_best_sector_time.list()
        # this is used to handle situation such as robomaker job crash, so the next robomaker job
        # can catch the best sector time left over from crashed job
        if "Contents" not in response:
            virtual_event_best_sector_time.persist(
                body=json.dumps({
                    SECTOR_X_FORMAT.format(idx + 1): float("inf")
                    for idx in range(self._num_sectors)
                }),
                s3_kms_extra_args=utils.get_s3_kms_extra_args())

        # ROS service to indicate all the robomaker markov packages are ready for consumption
        signal_robomaker_markov_package_ready()

        PhaseObserver('/agent/training_phase', self._run_phase_subject)

        # setup mp4 services
        self._setup_mp4_services()
 def detach(self):
     """Detach camera from manager"""
     CameraManager.get_instance().remove(self, self.namespace)
Esempio n. 7
0
    def __init__(self, config_dict, run_phase_sink, metrics):
        '''agent_name - String containing the name of the agent
           config_dict - Dictionary containing all the keys in ConfigParams
           run_phase_sink - Sink to recieve notification of a change in run phase
        '''
        # reset rules manager
        self._metrics = metrics
        self._is_continuous = config_dict[
            const.ConfigParams.IS_CONTINUOUS.value]
        self._is_reset = False
        self._reset_rules_manager = construct_reset_rules_manager(config_dict)
        self._ctrl_status = dict()
        self._ctrl_status[
            AgentCtrlStatus.AGENT_PHASE.value] = AgentPhase.RUN.value
        self._config_dict = config_dict
        self._done_condition = config_dict.get(
            const.ConfigParams.DONE_CONDITION.value, any)
        self._number_of_resets = config_dict[
            const.ConfigParams.NUMBER_OF_RESETS.value]
        self._off_track_penalty = config_dict[
            const.ConfigParams.OFF_TRACK_PENALTY.value]
        self._collision_penalty = config_dict[
            const.ConfigParams.COLLISION_PENALTY.value]
        self._pause_duration = 0.0
        self._reset_count = 0
        self._curr_crashed_object_name = None
        self._last_crashed_object_name = None
        # simapp_version speed scale
        self._speed_scale_factor_ = get_speed_factor(
            config_dict[const.ConfigParams.VERSION.value])
        # Store the name of the agent used to set agents position on the track
        self._agent_name_ = config_dict[const.ConfigParams.AGENT_NAME.value]
        # Set start lane. This only support for two agents H2H race
        self._agent_idx_ = get_racecar_idx(self._agent_name_)
        # Get track data
        self._track_data_ = TrackData.get_instance()
        if self._agent_idx_ is not None:
            self._start_lane_ = self._track_data_.inner_lane \
                if self._agent_idx_ % 2 else self._track_data_.outer_lane
        else:
            self._start_lane_ = self._track_data_.center_line
        # Store the name of the links in the agent, this should be const
        self._agent_link_name_list_ = config_dict[
            const.ConfigParams.LINK_NAME_LIST.value]
        # Store the reward function
        self._reward_ = config_dict[const.ConfigParams.REWARD.value]
        # Create publishers for controlling the car
        self._velocity_pub_dict_ = OrderedDict()
        self._steering_pub_dict_ = OrderedDict()
        for topic in config_dict[const.ConfigParams.VELOCITY_LIST.value]:
            self._velocity_pub_dict_[topic] = rospy.Publisher(topic,
                                                              Float64,
                                                              queue_size=1)
        for topic in config_dict[const.ConfigParams.STEERING_LIST.value]:
            self._steering_pub_dict_[topic] = rospy.Publisher(topic,
                                                              Float64,
                                                              queue_size=1)
        #Create default reward parameters
        self._reward_params_ = const.RewardParam.make_default_param()
        #Creat the default metrics dictionary
        self._step_metrics_ = StepMetrics.make_default_metric()
        # Dictionary of bools indicating starting position behavior
        self._start_pos_behavior_ = \
            {'change_start' : config_dict[const.ConfigParams.CHANGE_START.value],
             'alternate_dir' : config_dict[const.ConfigParams.ALT_DIR.value]}
        # Dictionary to track the previous way points
        self._prev_waypoints_ = {
            'prev_point': Point(0, 0),
            'prev_point_2': Point(0, 0)
        }
        # Normalize start position in meter to normalized start_ndist in percentage
        start_ndist = config_dict.get(const.ConfigParams.START_POSITION.value, 0.0) / \
            self._track_data_.get_track_length()
        # Dictionary containing some of the data for the agent
        self._data_dict_ = {
            'max_progress': 0.0,
            'current_progress': 0.0,
            'prev_progress': 0.0,
            'steps': 0.0,
            'start_ndist': start_ndist
        }
        #Load the action space
        self._action_space_, self._json_actions_ = \
            load_action_space(config_dict[const.ConfigParams.ACTION_SPACE_PATH.value])
        #! TODO evaluate if this is the best way to reset the car
        # Adding the reward data publisher
        self.reward_data_pub = RewardDataPublisher(self._agent_name_,
                                                   self._json_actions_)
        # subscriber to time to update camera position
        self.camera_manager = CameraManager.get_instance()
        # True if the agent is in the training phase
        self._is_training_ = False
        # Register to the phase sink
        run_phase_sink.register(self)
        # Make sure velicty and angle are set to 0
        send_action(self._velocity_pub_dict_, self._steering_pub_dict_, 0.0,
                    0.0)
        start_pose = self._track_data_.center_line.interpolate_pose(
            self._data_dict_['start_ndist'] *
            self._track_data_.get_track_length(),
            finite_difference=FiniteDifference.FORWARD_DIFFERENCE)
        self._track_data_.initialize_object(self._agent_name_, start_pose, \
                                            ObstacleDimensions.BOT_CAR_DIMENSION)

        self.make_link_points = lambda link_state: Point(
            link_state.pose.position.x, link_state.pose.position.y)
        self.reference_frames = ['' for _ in self._agent_link_name_list_]

        self._pause_car_model_pose = None
        self._park_position = DEFAULT_PARK_POSITION
        AbstractTracker.__init__(self, TrackerPriority.HIGH)
 def __init__(self, config_dict):
     '''agent_name - String containing the name of the agent
        config_dict - Dictionary containing all the keys in ConfigParams
     '''
     # simapp_version speed scale
     self._speed_scale_factor_ = get_speed_factor(
         config_dict[const.ConfigParams.VERSION.value])
     # Store the name of the agent used to set agents position on the track
     self._agent_name_ = config_dict[const.ConfigParams.AGENT_NAME.value]
     # Store the name of the links in the agent, this should be const
     self._agent_link_name_list_ = config_dict[
         const.ConfigParams.LINK_NAME_LIST.value]
     # Store the reward function
     self._reward_ = config_dict[const.ConfigParams.REWARD.value]
     self._track_data_ = TrackData.get_instance()
     # Create publishers for controlling the car
     self._velocity_pub_dict_ = OrderedDict()
     self._steering_pub_dict_ = OrderedDict()
     for topic in config_dict[const.ConfigParams.VELOCITY_LIST.value]:
         self._velocity_pub_dict_[topic] = rospy.Publisher(topic,
                                                           Float64,
                                                           queue_size=1)
     for topic in config_dict[const.ConfigParams.STEERING_LIST.value]:
         self._steering_pub_dict_[topic] = rospy.Publisher(topic,
                                                           Float64,
                                                           queue_size=1)
     #Create default reward parameters
     self._reward_params_ = const.RewardParam.make_default_param()
     #Creat the default metrics dictionary
     self._step_metrics_ = StepMetrics.make_default_metric()
     # State variable to track if the car direction has been reversed
     self._reverse_dir_ = False
     # Dictionary of bools indicating starting position behavior
     self._start_pos_behavior_ = \
         {'change_start' : config_dict[const.ConfigParams.CHANGE_START.value],
          'alternate_dir' : config_dict[const.ConfigParams.ALT_DIR.value]}
     # Dictionary to track the previous way points
     self._prev_waypoints_ = {
         'prev_point': Point(0, 0),
         'prev_point_2': Point(0, 0)
     }
     # Dictionary containing some of the data for the agent
     self._data_dict_ = {
         'prev_progress': 0.0,
         'steps': 0.0,
         'start_ndist': 0.0
     }
     #Load the action space
     self._action_space_, self._json_actions_ = \
         load_action_space(config_dict[const.ConfigParams.ACTION_SPACE_PATH.value])
     #! TODO evaluate if this is the best way to reset the car
     rospy.wait_for_service(SET_MODEL_STATE)
     rospy.wait_for_service(GET_MODEL_STATE)
     self.set_model_state = ServiceProxyWrapper(SET_MODEL_STATE,
                                                SetModelState)
     self.get_model_client = ServiceProxyWrapper(GET_MODEL_STATE,
                                                 GetModelState)
     # Adding the reward data publisher
     self.reward_data_pub = RewardDataPublisher(self._agent_name_,
                                                self._json_actions_)
     # init time
     self.last_time = 0.0
     self.curr_time = 0.0
     # subscriber to time to update camera position
     camera_types = [camera for camera in CameraType]
     self.camera_manager = CameraManager(camera_types=camera_types)
     rospy.Subscriber('/clock', Clock, self.update_camera)
     # Make sure velicty and angle are set to 0
     send_action(self._velocity_pub_dict_, self._steering_pub_dict_, 0.0,
                 0.0)
class RolloutCtrl(AgentCtrlInterface):
    '''Concrete class for an agent that drives forward'''
    def __init__(self, config_dict):
        '''agent_name - String containing the name of the agent
           config_dict - Dictionary containing all the keys in ConfigParams
        '''
        # simapp_version speed scale
        self._speed_scale_factor_ = get_speed_factor(
            config_dict[const.ConfigParams.VERSION.value])
        # Store the name of the agent used to set agents position on the track
        self._agent_name_ = config_dict[const.ConfigParams.AGENT_NAME.value]
        # Store the name of the links in the agent, this should be const
        self._agent_link_name_list_ = config_dict[
            const.ConfigParams.LINK_NAME_LIST.value]
        # Store the reward function
        self._reward_ = config_dict[const.ConfigParams.REWARD.value]
        self._track_data_ = TrackData.get_instance()
        # Create publishers for controlling the car
        self._velocity_pub_dict_ = OrderedDict()
        self._steering_pub_dict_ = OrderedDict()
        for topic in config_dict[const.ConfigParams.VELOCITY_LIST.value]:
            self._velocity_pub_dict_[topic] = rospy.Publisher(topic,
                                                              Float64,
                                                              queue_size=1)
        for topic in config_dict[const.ConfigParams.STEERING_LIST.value]:
            self._steering_pub_dict_[topic] = rospy.Publisher(topic,
                                                              Float64,
                                                              queue_size=1)
        #Create default reward parameters
        self._reward_params_ = const.RewardParam.make_default_param()
        #Creat the default metrics dictionary
        self._step_metrics_ = StepMetrics.make_default_metric()
        # State variable to track if the car direction has been reversed
        self._reverse_dir_ = False
        # Dictionary of bools indicating starting position behavior
        self._start_pos_behavior_ = \
            {'change_start' : config_dict[const.ConfigParams.CHANGE_START.value],
             'alternate_dir' : config_dict[const.ConfigParams.ALT_DIR.value]}
        # Dictionary to track the previous way points
        self._prev_waypoints_ = {
            'prev_point': Point(0, 0),
            'prev_point_2': Point(0, 0)
        }
        # Dictionary containing some of the data for the agent
        self._data_dict_ = {
            'prev_progress': 0.0,
            'steps': 0.0,
            'start_ndist': 0.0
        }
        #Load the action space
        self._action_space_, self._json_actions_ = \
            load_action_space(config_dict[const.ConfigParams.ACTION_SPACE_PATH.value])
        #! TODO evaluate if this is the best way to reset the car
        rospy.wait_for_service(SET_MODEL_STATE)
        rospy.wait_for_service(GET_MODEL_STATE)
        self.set_model_state = ServiceProxyWrapper(SET_MODEL_STATE,
                                                   SetModelState)
        self.get_model_client = ServiceProxyWrapper(GET_MODEL_STATE,
                                                    GetModelState)
        # Adding the reward data publisher
        self.reward_data_pub = RewardDataPublisher(self._agent_name_,
                                                   self._json_actions_)
        # init time
        self.last_time = 0.0
        self.curr_time = 0.0
        # subscriber to time to update camera position
        camera_types = [camera for camera in CameraType]
        self.camera_manager = CameraManager(camera_types=camera_types)
        rospy.Subscriber('/clock', Clock, self.update_camera)
        # Make sure velicty and angle are set to 0
        send_action(self._velocity_pub_dict_, self._steering_pub_dict_, 0.0,
                    0.0)

    def update_camera(self, sim_time):
        # get car state
        car_model_state = self.get_model_client('racecar', '')
        # update timer
        self.curr_time = sim_time.clock.secs + 1.e-9 * sim_time.clock.nsecs
        time_delta = self.curr_time - self.last_time
        self.last_time = self.curr_time
        # update camera pose
        self.camera_manager.update(car_model_state, time_delta)

    @property
    def action_space(self):
        return self._action_space_

    def reset_agent(self):
        send_action(self._velocity_pub_dict_, self._steering_pub_dict_, 0.0,
                    0.0)
        self._track_data_.car_ndist = self._data_dict_[
            'start_ndist']  # TODO -- REMOVE THIS

        # Compute the start pose
        start_dist = self._data_dict_[
            'start_ndist'] * self._track_data_.get_track_length()
        start_pose = self._track_data_._center_line_.interpolate_pose(
            start_dist,
            reverse_dir=self._reverse_dir_,
            finite_difference=FiniteDifference.FORWARD_DIFFERENCE)

        # If we have obstacles, don't start near one
        for object_pose in self._track_data_.object_poses.values():
            object_point = Point(
                [object_pose.position.x, object_pose.position.y])
            object_dist = self._track_data_._center_line_.project(object_point)
            object_dist_ahead = (object_dist - start_dist
                                 ) % self._track_data_.get_track_length()
            object_dist_behind = (start_dist - object_dist
                                  ) % self._track_data_.get_track_length()
            if self._reverse_dir_:
                object_dist_ahead, object_dist_behind = object_dist_behind, object_dist_ahead
            if object_dist_ahead < 1.0 or object_dist_behind < 0.5:  # TODO: don't hard-code these numbers
                object_nearest_pnts_dict = self._track_data_.get_nearest_points(
                    object_point)
                object_nearest_dist_dict = self._track_data_.get_nearest_dist(
                    object_nearest_pnts_dict, object_point)
                object_is_inner = object_nearest_dist_dict[TrackNearDist.NEAR_DIST_IN.value] < \
                                    object_nearest_dist_dict[TrackNearDist.NEAR_DIST_OUT.value]
                if object_is_inner:
                    start_pose = self._track_data_._outer_lane_.interpolate_pose(
                        self._track_data_._outer_lane_.project(
                            Point(start_pose.position.x,
                                  start_pose.position.y)),
                        reverse_dir=self._reverse_dir_,
                        finite_difference=FiniteDifference.FORWARD_DIFFERENCE)
                else:
                    start_pose = self._track_data_._inner_lane_.interpolate_pose(
                        self._track_data_._inner_lane_.project(
                            Point(start_pose.position.x,
                                  start_pose.position.y)),
                        reverse_dir=self._reverse_dir_,
                        finite_difference=FiniteDifference.FORWARD_DIFFERENCE)
                break

        start_state = ModelState()
        start_state.model_name = self._agent_name_
        start_state.pose = start_pose
        start_state.twist.linear.x = 0
        start_state.twist.linear.y = 0
        start_state.twist.linear.z = 0
        start_state.twist.angular.x = 0
        start_state.twist.angular.y = 0
        start_state.twist.angular.z = 0
        self.set_model_state(start_state)
        # reset view cameras
        self.camera_manager.reset(start_state)

    def send_action(self, action):
        steering_angle = float(
            self._json_actions_[action]['steering_angle']) * math.pi / 180.0
        speed = float(self._json_actions_[action]['speed']/const.WHEEL_RADIUS)\
                *self._speed_scale_factor_
        send_action(self._velocity_pub_dict_, self._steering_pub_dict_,
                    steering_angle, speed)

    def judge_action(self, action):
        try:
            # Get the position of the agent
            pos_dict = self._track_data_.get_agent_pos(
                self._agent_name_, self._agent_link_name_list_,
                const.RELATIVE_POSITION_OF_FRONT_OF_CAR)
            model_point = pos_dict[AgentPos.POINT.value]
            # Compute the next index
            current_ndist = self._track_data_.get_norm_dist(model_point)
            prev_index, next_index = self._track_data_.find_prev_next_waypoints(
                current_ndist, normalized=True, reverse_dir=self._reverse_dir_)
            # Set the basic reward and training metrics
            set_reward_and_metrics(self._reward_params_, self._step_metrics_,
                                   pos_dict, self._track_data_, next_index,
                                   prev_index, action, self._json_actions_)
            # Convert current progress to be [0,100] starting at the initial waypoint
            if self._reverse_dir_:
                self._reward_params_[const.RewardParam.LEFT_CENT.value[0]] = \
                    not self._reward_params_[const.RewardParam.LEFT_CENT.value[0]]
                current_progress = self._data_dict_[
                    'start_ndist'] - current_ndist
            else:
                current_progress = current_ndist - self._data_dict_[
                    'start_ndist']

            current_progress = compute_current_prog(
                current_progress, self._data_dict_['prev_progress'])
            self._data_dict_['steps'] += 1
            # Add the agen specific metrics
            self._step_metrics_[StepMetrics.STEPS.value] = \
            self._reward_params_[const.RewardParam.STEPS.value[0]] = self._data_dict_['steps']
            self._reward_params_[
                const.RewardParam.REVERSE.value[0]] = self._reverse_dir_
            self._step_metrics_[StepMetrics.PROG.value] = \
            self._reward_params_[const.RewardParam.PROG.value[0]] = current_progress
        except Exception as ex:
            raise GenericRolloutException(
                'Cannot find position: {}'.format(ex))

        # This code should be replaced with the contact sensor code
        is_crashed = False
        model_heading = self._reward_params_[
            const.RewardParam.HEADING.value[0]]

        obstacle_reward_params = self._track_data_.get_object_reward_params(
            model_point, model_heading, current_progress, self._reverse_dir_)
        if obstacle_reward_params:
            self._reward_params_.update(obstacle_reward_params)
            is_crashed = self._track_data_.is_racecar_collided(
                pos_dict[AgentPos.LINK_POINTS.value])

        prev_pnt_dist = min(
            model_point.distance(self._prev_waypoints_['prev_point']),
            model_point.distance(self._prev_waypoints_['prev_point_2']))

        is_off_track = not any(
            self._track_data_.points_on_track(
                pos_dict[AgentPos.LINK_POINTS.value]))
        is_immobilized = (prev_pnt_dist <= 0.0001
                          and self._data_dict_['steps'] %
                          const.NUM_STEPS_TO_CHECK_STUCK == 0)
        is_lap_complete = current_progress >= 100.0

        self._reward_params_[const.RewardParam.CRASHED.value[0]] = is_crashed
        self._reward_params_[
            const.RewardParam.OFFTRACK.value[0]] = is_off_track

        done = is_crashed or is_immobilized or is_off_track or is_lap_complete
        episode_status = EpisodeStatus.get_episode_status(
            is_crashed=is_crashed,
            is_immobilized=is_immobilized,
            is_off_track=is_off_track,
            is_lap_complete=is_lap_complete)
        try:
            reward = float(self._reward_(copy.deepcopy(self._reward_params_)))
        except Exception as ex:
            raise RewardFunctionError(
                'Reward function exception {}'.format(ex))
        if math.isnan(reward) or math.isinf(reward):
            raise RewardFunctionError('{} returned as reward'.format(reward))

        self._prev_waypoints_['prev_point_2'] = self._prev_waypoints_[
            'prev_point']
        self._prev_waypoints_['prev_point'] = model_point
        self._data_dict_['prev_progress'] = current_progress
        #Get the last of the step metrics
        self._step_metrics_[StepMetrics.REWARD.value] = reward
        self._step_metrics_[StepMetrics.DONE.value] = done
        self._step_metrics_[StepMetrics.TIME.value] = time.time()
        self._step_metrics_[
            StepMetrics.EPISODE_STATUS.value] = episode_status.value

        return reward, done, self._step_metrics_

    def finish_episode(self):
        if self._start_pos_behavior_['change_start']:
            self._data_dict_['start_ndist'] = (
                self._data_dict_['start_ndist'] +
                const.ROUND_ROBIN_ADVANCE_DIST) % 1.0
        if self._start_pos_behavior_['alternate_dir']:
            self._reverse_dir_ = not self._reverse_dir_

    def clear_data(self):
        for key in self._prev_waypoints_:
            self._prev_waypoints_[key] = Point(0, 0)
        for key in self._data_dict_:
            if key != 'start_ndist':
                self._data_dict_[key] = 0.0