Exemple #1
0
 def setUp(self,
           plane: aircraft.Aircraft = aircraft.cessna172P,
           task_type: Type[
               tasks.HeadingControlTask] = tasks.TurnHeadingControlTask):
     self.env = None
     self.env = JsbSimEnv(aircraft=plane, task_type=task_type)
     self.env.reset()
Exemple #2
0
    def init_and_reset_env(self, env: JsbSimEnv):
        self.assertIsInstance(env.task, HeadingControlTask)

        # we interact at 5 Hz, so we expect the sim to run 12 timesteps per
        #   interaction since it runs at 120 Hz
        self.assertEqual(12, env.sim_steps_per_agent_step)

        # we init a random agent with a seed
        agent = RandomAgent(action_space=env.action_space)
        self.assertEqual(env.action_space, agent.action_space)

        # this task has an action space of three controls: aileron, elevator, rudder
        expected_num_actions = 3
        self.assertEqual(expected_num_actions, len(agent.action_space.low))
        # we see that the action space has the correct low and high range of +-1.0
        expect_low = np.array([-1.0] * expected_num_actions)
        expect_high = np.array([1.0] * expected_num_actions)
        np.testing.assert_array_almost_equal(expect_high,
                                             env.action_space.high)
        np.testing.assert_array_almost_equal(expect_low, env.action_space.low)

        # we reset the env and receive the first state; the env is now ready
        state = env.reset()
        self.assertEqual(len(env.observation_space.low), len(state))

        # we close the env and JSBSim closes with it
        env.close()
        self.assertIsNone(env.sim.jsbsim)
 def setUp(self):
     if self.env:
         self.env.close()
     if self.sim:
         self.sim.close()
     self.task = BasicFlightTask()
     self.env = JsbSimEnv(task_type=BasicFlightTask)
     self.env.reset()
     self.sim = self.env.sim
     self.flightgear = None
Exemple #4
0
 def setUp(self,
           plane: aircraft.Aircraft = aircraft.cessna172P,
           task_type: Type[
               tasks.HeadingControlTask] = tasks.TurnHeadingControlTask,
           shaping: tasks.Shaping = tasks.Shaping.STANDARD):
     self.env = None
     self.env = JsbSimEnv(aircraft=plane,
                          task_type=task_type,
                          shaping=shaping)
     self.env.reset()
Exemple #5
0
class TurnHeadingControlTest(unittest.TestCase):
    def setUp(self,
              plane: aircraft.Aircraft = aircraft.cessna172P,
              task_type: Type[
                  tasks.HeadingControlTask] = tasks.TurnHeadingControlTask,
              shaping: tasks.Shaping = tasks.Shaping.STANDARD):
        self.env = None
        self.env = JsbSimEnv(aircraft=plane,
                             task_type=task_type,
                             shaping=shaping)
        self.env.reset()

    def tearDown(self):
        self.env.close()

    def test_render_heading_control(self):
        self.setUp(plane=aircraft.a320,
                   task_type=tasks.TurnHeadingControlTask,
                   shaping=tasks.Shaping.EXTRA_SEQUENTIAL)
        agent = RandomAgent(self.env.action_space)
        render_every = 5
        report_every = 20
        EPISODES = 50

        for _ in range(EPISODES):
            ep_reward = 0
            done = False
            state = self.env.reset()
            self.env.render(mode='flightgear')
            step_number = 0
            while not done:
                action = agent.act(state)
                state, reward, done, info = self.env.step(action)
                ep_reward += reward
                if step_number % render_every == 0:
                    self.env.render(mode='flightgear')
                if step_number % report_every == 0:
                    heading_target = tasks.HeadingControlTask.target_track_deg
                    print(f'time:\t{self.env.sim.get_sim_time()} s')
                    print(f'last reward:\t{reward}')
                    print(f'episode reward:\t{ep_reward}')
                    print(f'gear status:\t{self.env.sim[prp.gear]}')
                    print(
                        f'thrust eng0:\t{self.env.sim[prp.engine_thrust_lbs]}')
                    print(
                        f'thrust eng1:\t {self.env.sim[prp.Property("propulsion/engine[1]/thrust-lbs", "")]}'
                    )
                    print(f'heading:\t{self.env.sim[prp.heading_deg]}')
                    print(f'target heading:\t{self.env.sim[heading_target]}')
                    print('\n')
                step_number += 1
            print(f'***\n' f'EPISODE REWARD: {ep_reward}\n' f'***\n')
Exemple #6
0
class FlightGearRenderTest(unittest.TestCase):
    def setUp(self,
              plane: aircraft.Aircraft = aircraft.cessna172P,
              task_type: Type[
                  tasks.HeadingControlTask] = tasks.TurnHeadingControlTask):
        self.env = None
        self.env = JsbSimEnv(aircraft=plane, task_type=task_type)
        self.env.reset()

    def tearDown(self):
        self.env.close()

    def test_render_steady_level_flight(self):
        self.setUp(plane=aircraft.cessna172P,
                   task_type=tasks.HeadingControlTask)
        agent = ConstantAgent(self.env.action_space)
        render_every = 5
        report_every = 20
        EPISODES = 999

        for _ in range(EPISODES):
            ep_reward = 0
            done = False
            state = self.env.reset()
            self.env.render(mode='flightgear')
            step_number = 0
            while not done:
                action = agent.act(state)
                state, reward, done, info = self.env.step(action)
                ep_reward += reward
                if step_number % render_every == 0:
                    self.env.render(mode='flightgear')
                if step_number % report_every == 0:
                    print(f'time:\t{self.env.sim.get_sim_time()} s')
                    print(f'last reward:\t{reward}')
                    print(f'episode reward:\t{ep_reward}')
                    print(f'thrust:\t{self.env.sim[prp.engine_thrust_lbs]}')
                    print(
                        f'engine running:\t{self.env.sim[prp.engine_running]}')
                step_number += 1
            print(f'***\n' f'EPISODE REWARD: {ep_reward}\n' f'***')
Exemple #7
0
    def take_step_with_random_agent(self, env: JsbSimEnv):
        agent = RandomAgent(action_space=env.action_space)

        # we set up for a loop through one episode
        first_state = env.reset()

        # we take a single step
        action = agent.act(first_state)
        state, reward, done, info = env.step(action)

        # we see the state has changed
        self.assertEqual(first_state.shape, state.shape)
        self.assertTrue(np.any(np.not_equal(first_state, state)),
                        msg='state should have changed after simulation step')
        expected_time_step_size = env.sim_steps_per_agent_step / env.JSBSIM_DT_HZ
        self.assertAlmostEqual(expected_time_step_size, env.sim.get_sim_time())
        self.assertFalse(done,
                         msg='episode is terminal after only a single step')

        # the aircraft engines are running, as per initial conditions
        self.assertNotAlmostEqual(env.sim[prp.engine_thrust_lbs], 0)

        env.close()
class TestFlightGearVisualiser(unittest.TestCase):
    env = None
    sim = None
    flightgear = None

    def setUp(self):
        if self.env:
            self.env.close()
        if self.sim:
            self.sim.close()
        self.task = BasicFlightTask()
        self.env = JsbSimEnv(task_type=BasicFlightTask)
        self.env.reset()
        self.sim = self.env.sim
        self.flightgear = None
        # individual test methods should init as needed:
        # self.flightgear = FlightGearVisualiser(self.sim)

    def tearDown(self):
        if self.env:
            self.env.close()
        if self.sim:
            self.sim.close()
        if self.flightgear:
            self.flightgear.close()

    def test_init_creates_figure(self):
        self.flightgear = FlightGearVisualiser(self.sim,
                                               self.task.get_props_to_output(),
                                               block_until_loaded=False)
        self.assertIsInstance(self.flightgear.figure, FigureVisualiser)

    def test_launch_flightgear(self):
        self.flightgear = FlightGearVisualiser(self.sim,
                                               self.task.get_props_to_output(),
                                               block_until_loaded=False)
        time.sleep(0.5)

        # check FlightGear has launched by looking at stdout
        self.assertIn(
            'FlightGear',
            self.flightgear.flightgear_process.stdout.readline().decode())
        self.flightgear.close()

    def test_close_closes_flightgear(self):
        self.flightgear = FlightGearVisualiser(self.sim,
                                               self.task.get_props_to_output(),
                                               block_until_loaded=False)
        self.flightgear.close()
        timeout_seconds = 2.0
        return_code = self.flightgear.flightgear_process.wait(
            timeout=timeout_seconds)
        # a non-None return code indicates termination
        self.assertIsNotNone(return_code)

    def test_plot_displays_actions(self):
        self.setUp()
        self.flightgear = FlightGearVisualiser(self.sim,
                                               self.task.get_props_to_output(),
                                               block_until_loaded=False)
        self.flightgear.plot(self.sim)

        # the figure should have plotted a Lines object each axis
        for axis in ['axes_stick', 'axes_rudder', 'axes_throttle']:
            axis_data_plots = getattr(self.flightgear.figure.axes, axis)
            is_empty_plot = len(axis_data_plots.axes.lines) == 0
            self.assertFalse(is_empty_plot,
                             msg=f'no data plotted on axis {axis}')
Exemple #9
0
 def setUp(self, task_type: Type[tasks.HeadingControlTask] = BasicFlightTask):
     self.env = None
     self.env = JsbSimEnv(task_type)
     self.env.reset()
Exemple #10
0
class TestJsbSimInstance(unittest.TestCase):
    def setUp(self, task_type: Type[tasks.HeadingControlTask] = BasicFlightTask):
        self.env = None
        self.env = JsbSimEnv(task_type)
        self.env.reset()

    def tearDown(self):
        self.env.close()

    def test_long_episode_random_actions(self):
        self.setUp()
        tic = time.time()
        self.env.reset()
        for i in range(2000):
            self.env.step(action=self.env.action_space.sample())
            print(f'jsbsim {i / 10} s\n')
        toc = time.time()
        wall_time = (toc - tic)
        sim_time = self.env.sim.get_sim_time()
        print(f'Simulated {sim_time} s of flight in {wall_time} s')

    def test_render_episode(self):
        self.setUp()
        render_every = 5
        self.env.reset()
        for i in range(1000):
            action = self.env.action_space.sample()
            obs, _, _, _ = self.env.step(action=action)
            if i % render_every == 0:
                self.env.render(mode='human')

    def test_render_steady_level_flight_random(self):
        """ Runs steady level flight task with a random agent. """
        self.setUp(task_type=tasks.HeadingControlTask)
        agent = RandomAgent(self.env.action_space)
        render_every = 5
        ep_reward = 0
        done = False
        state = self.env.reset()
        step_number = 0
        while not done:
            action = agent.act(state)
            state, reward, done, info = self.env.step(action)
            ep_reward += reward
            if step_number % render_every == 0:
                self.env.render(mode='human')
            step_number += 1

    def test_run_episode_steady_level_flight_no_render(self):
        self.setUp(task_type=tasks.HeadingControlTask)
        agent = RandomAgent(self.env.action_space)
        report_every = 20
        EPISODES = 10

        for _ in range(EPISODES):
            ep_reward = 0
            done = False
            state = self.env.reset()
            step_number = 0
            while not done:
                action = agent.act(state)
                state, reward, done, info = self.env.step(action)
                ep_reward += reward
                if step_number % report_every == 0:
                    print(f'time:\t{self.env.sim.get_sim_time()} s')
                    print(f'last reward:\t{reward}')
                    print(f'episode reward:\t{ep_reward}')
                step_number += 1
 def init_env(self, agent_interaction_freq):
     self.env = JsbSimEnv(task_type=BasicFlightTask,
                          agent_interaction_freq=agent_interaction_freq)
class TestJsbSimEnv(unittest.TestCase):
    def setUp(self, agent_interaction_freq: int = 10):
        gym.logger.set_level(gym.logger.DEBUG)
        self.env = None
        self.init_env(agent_interaction_freq)
        self.env.reset()

    def init_env(self, agent_interaction_freq):
        self.env = JsbSimEnv(task_type=BasicFlightTask,
                             agent_interaction_freq=agent_interaction_freq)

    def tearDown(self):
        self.env.close()

    def assertValidObservation(self, obs: np.array):
        """ Helper; checks shape and values of an observation. """
        self.assertEqual(self.env.observation_space.shape,
                         obs.shape,
                         msg='observation has wrong size')
        self.assert_in_box_space(obs, self.env.observation_space)

    def assertValidAction(self, action: np.array):
        """ Helper; checks shape and values of an action. """
        self.assertEqual(self.env.action_space.shape,
                         action.shape,
                         msg='action has wrong size')
        self.assert_in_box_space(action, self.env.action_space)

    def assert_in_box_space(self, sample: np.array,
                            space: gym.spaces.Box) -> None:
        if space.contains(sample):
            return
        else:
            is_too_low = sample < space.low
            is_too_high = sample > space.high
            msg = 'Sample is not in space:'
            for i in range(len(sample)):
                if is_too_low[i]:
                    msg += f'\nelement {i} too low: {sample[i]} < {space.low[i]}'
                if is_too_high[i]:
                    msg += f'\nelement {i} too high: {sample[i]} > {space.high[i]}'
            raise AssertionError(msg)

    def validate_action_made(self, action: np.array):
        """ Helper; confirms action was correctly input to simulation. """
        self.assertValidAction(action)
        for prop, command in zip(self.env.task.action_variables, action):
            actual = self.env.sim[prop]
            self.assertAlmostEqual(
                command,
                actual,
                msg='simulation commanded value does not match action')

    def test_init_spaces(self):
        # check correct types for obs and action space
        self.assertIsInstance(self.env.observation_space,
                              gym.Space,
                              msg='observation_space is not a Space object')
        self.assertIsInstance(self.env.action_space,
                              gym.Space,
                              msg='action_space is not a Space object')

        # check low and high values are as expected
        obs_lows = self.env.observation_space.low
        obs_highs = self.env.observation_space.high
        act_lows = self.env.action_space.low
        act_highs = self.env.action_space.high

        places_tol = 3

        for prop, lo, hi in zip(self.env.task.state_variables, obs_lows,
                                obs_highs):
            self.assertAlmostEqual(lo,
                                   prop.min,
                                   msg=f'{prop} min of {prop.min} does not'
                                   f'match space low of {lo}')
            self.assertAlmostEqual(hi,
                                   prop.max,
                                   msg=f'{prop} max of {prop.max} does not'
                                   f'match space high of {hi}')

    def test_reset_env(self):
        self.setUp()
        obs = self.env.reset()

        self.assertValidObservation(obs)

    def test_do_action(self):
        self.setUp()
        action1 = np.array([0.0] * len(self.env.task.action_variables))
        action2 = np.linspace(-0.5,
                              .5,
                              num=len(self.env.task.action_variables))

        # do an action and check results
        obs, _, _, _ = self.env.step(action1)
        self.assertValidObservation(obs)
        self.validate_action_made(action1)

        # repeat action several times
        for _ in range(10):
            obs, _, _, _ = self.env.step(action1)
            self.assertValidObservation(obs)
            self.validate_action_made(action1)

        # repeat new action
        for _ in range(10):
            obs, _, _, _ = self.env.step(action2)
            self.assertValidObservation(obs)
            self.validate_action_made(action2)

    def test_figure_created_closed(self):
        self.env.render(mode='human')
        self.assertIsInstance(self.env.figure_visualiser.figure, plt.Figure)
        self.env.close()
        self.assertIsNone(self.env.figure_visualiser.figure)

    def test_plot_state(self):
        # note: this checks that plot works without throwing exception
        # correctness of plot must be checked in appropriate manual_test
        self.setUp()
        self.env.render(mode='human')

        action = np.array([0.0] * len(self.env.task.action_variables))
        # repeat action several times
        for _ in range(3):
            obs, _, _, _ = self.env.step(action)
            self.env.render(mode='human')

    def test_plot_actions(self):
        # note: this checks that plot works without throwing exception
        # correctness of plot must be checked in appropriate manual_test
        self.env.render(mode='human')

        # repeat action several times
        for _ in range(3):
            action = self.env.action_space.sample()
            _, _, _, _ = self.env.step(action)
            self.env.render(mode='human')

    def test_asl_agl_elevations_equal(self):
        # we want the height above sea level to equal ground elevation at all times
        self.setUp(agent_interaction_freq=1)
        for i in range(25):
            self.env.step(action=self.env.action_space.sample())
            alt_sl = self.env.sim[prp.altitude_sl_ft]
            alt_gl = self.env.sim[prp.BoundedProperty('position/h-agl-ft', '',
                                                      0, 0)]
            self.assertAlmostEqual(alt_sl, alt_gl)

    def test_render_flightgear_mode(self):
        self.setUp()
        self.env.render(mode='flightgear', flightgear_blocking=False)
        self.assertIsInstance(self.env.flightgear_visualiser,
                              FlightGearVisualiser)
        self.env.close()