def __init__(self, fdmexec): """Constructor for the Simulator object Arguments: fdmexec: A flight dynamics model """ self.aircraft = Aircraft(fdmexec) self.fdmexec = fdmexec self.fdm = FDM(fdmexec) self.trim_mode = TRIM_MODE_FULL self._crashed = False self.start_paused = False
def test_fill_gps_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdm_builder.aircraft = "Rascal" fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) factory = SensorDataFactory(aircraft) protocol = factory.buildProtocol(("127.0.0.1", 12345)) sensor_data_response = fdm_pb2.SensorDataResponse() protocol.fill_gps_data(sensor_data_response) self.assertAlmostEqual(sensor_data_response.gps.latitude, aircraft.instruments.gps.latitude) self.assertAlmostEqual(sensor_data_response.gps.longitude, aircraft.instruments.gps.longitude) self.assertAlmostEqual(sensor_data_response.gps.altitude, aircraft.instruments.gps.altitude) self.assertAlmostEqual(sensor_data_response.gps.airspeed, aircraft.instruments.gps.airspeed) self.assertAlmostEqual(sensor_data_response.gps.heading, aircraft.instruments.gps.heading) self.assertEqual(sensor_data_response.type, fdm_pb2.GPS_REQUEST)
def test_datagram_received(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdm_builder.aircraft = "Rascal" fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) controls_protocol = ControlsProtocol(fdmexec) aileron = 0.1 elevator = 0.2 rudder = 0.3 throttle = 0.4 controls = fdm_pb2.Controls() controls.aileron = aileron controls.elevator = elevator controls.rudder = rudder controls.throttle = throttle controls_datagram = controls.SerializeToString() host = "127.0.0.1" port = 12345 controls_protocol.datagramReceived(controls_datagram, (host, port)) self.assertAlmostEqual(aircraft.controls.aileron, aileron, 3) self.assertAlmostEqual(aircraft.controls.elevator, elevator, 3) self.assertAlmostEqual(aircraft.controls.rudder, rudder, 3) self.assertAlmostEqual(aircraft.controls.throttle, throttle, 3)
def test_fill_ins_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdm_builder.aircraft = "Rascal" fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) factory = SensorDataFactory(aircraft) protocol = factory.buildProtocol(("127.0.0.1", 12345)) sensor_data_response = fdm_pb2.SensorDataResponse() protocol.fill_ins_data(sensor_data_response) self.assertAlmostEqual( sensor_data_response.ins.roll, aircraft.sensors.inertial_navigation_system.roll) self.assertAlmostEqual( sensor_data_response.ins.pitch, aircraft.sensors.inertial_navigation_system.pitch) self.assertEqual(sensor_data_response.type, fdm_pb2.INS_REQUEST)
def test_fill_gyroscope_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdm_builder.aircraft = "Rascal" fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) factory = SensorDataFactory(aircraft) protocol = factory.buildProtocol(("127.0.0.1", 12345)) sensor_data_response = fdm_pb2.SensorDataResponse() protocol.fill_gyroscope_data(sensor_data_response) self.assertAlmostEqual(sensor_data_response.gyroscope.roll_rate, aircraft.sensors.gyroscope.roll_rate) self.assertAlmostEqual(sensor_data_response.gyroscope.pitch_rate, aircraft.sensors.gyroscope.pitch_rate) self.assertAlmostEqual(sensor_data_response.gyroscope.yaw_rate, aircraft.sensors.gyroscope.yaw_rate) self.assertEqual(sensor_data_response.type, fdm_pb2.GYROSCOPE_REQUEST)
def test_handle_sensor_data_request(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdm_builder.aircraft = "Rascal" fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) factory = SensorDataFactory(aircraft) protocol = factory.buildProtocol(("127.0.0.1", 12345)) protocol.send_response_string = MagicMock() sensor_data_request = fdm_pb2.SensorDataRequest() sensor_data_request.type = fdm_pb2.GPS_REQUEST protocol.handle_sensor_data_request(sensor_data_request) expected_sensor_data_response = fdm_pb2.SensorDataResponse() expected_sensor_data_response.type = fdm_pb2.GPS_REQUEST expected_sensor_data_response.gps.latitude = aircraft.instruments.gps.latitude expected_sensor_data_response.gps.longitude = aircraft.instruments.gps.longitude expected_sensor_data_response.gps.altitude = aircraft.instruments.gps.altitude expected_sensor_data_response.gps.airspeed = aircraft.instruments.gps.airspeed expected_sensor_data_response.gps.heading = aircraft.instruments.gps.heading protocol.send_response_string.assert_called_once_with( expected_sensor_data_response.SerializeToString())
def test_get_fdm_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) fdm = FDM(fdmexec) resource = FDMResource(fdm, aircraft) fdm_data = resource.get() self.assertAlmostEqual(fdm.fdmexec.GetSimTime(), fdm_data["time"], 3) self.assertAlmostEqual(fdm.fdmexec.GetDeltaT(), fdm_data["dt"], 3) self.assertAlmostEqual(fdm.position.latitude, fdm_data["latitude"], 3) self.assertAlmostEqual(fdm.position.longitude, fdm_data["longitude"], 3) self.assertAlmostEqual(fdm.position.altitude, fdm_data["altitude"], 3) self.assertAlmostEqual(fdm.velocities.true_airspeed, fdm_data["airspeed"], 3) self.assertAlmostEqual(fdm.position.heading, fdm_data["heading"], 3) self.assertAlmostEqual(fdm.accelerations.x, fdm_data["x_acceleration"], 3) self.assertAlmostEqual(fdm.accelerations.y, fdm_data["y_acceleration"], 3) self.assertAlmostEqual(fdm.accelerations.z, fdm_data["z_acceleration"], 3) self.assertAlmostEqual(fdm.velocities.p, fdm_data["roll_rate"], 3) self.assertAlmostEqual(fdm.velocities.q, fdm_data["pitch_rate"], 3) self.assertAlmostEqual(fdm.velocities.r, fdm_data["yaw_rate"], 3) self.assertAlmostEqual(fdm.atmosphere.temperature, fdm_data["temperature"], 3) self.assertAlmostEqual(fdm.atmosphere.pressure, fdm_data["static_pressure"], 3) self.assertAlmostEqual(aircraft.sensors.pitot_tube.true_pressure, fdm_data["total_pressure"], 3) self.assertAlmostEqual(fdm.orientation.phi, fdm_data["roll"], 3) self.assertAlmostEqual(fdm.orientation.theta, fdm_data["pitch"], 3) climb_rate = convert_jsbsim_velocity(-fdmexec.GetPropagate().GetVel(3)) self.assertAlmostEqual(climb_rate, fdm_data["climb_rate"], 3)
def test_fill_accelerometer_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdm_builder.aircraft = "Rascal" fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) factory = SensorDataFactory(aircraft) protocol = factory.buildProtocol(("127.0.0.1", 12345)) sensor_data_response = fdm_pb2.SensorDataResponse() protocol.fill_accelerometer_data(sensor_data_response) self.assertAlmostEqual(sensor_data_response.accelerometer.x, aircraft.sensors.accelerometer.x) self.assertAlmostEqual(sensor_data_response.accelerometer.y, aircraft.sensors.accelerometer.y) self.assertAlmostEqual(sensor_data_response.accelerometer.z, aircraft.sensors.accelerometer.z) self.assertEqual(sensor_data_response.type, fdm_pb2.ACCELEROMETER_REQUEST)
def test_fill_controls_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdm_builder.aircraft = "Rascal" fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) factory = SensorDataFactory(aircraft) protocol = factory.buildProtocol(("127.0.0.1", 12345)) sensor_data_response = fdm_pb2.SensorDataResponse() protocol.fill_controls_data(sensor_data_response) self.assertAlmostEqual(sensor_data_response.controls.aileron, aircraft.controls.aileron) self.assertAlmostEqual(sensor_data_response.controls.elevator, aircraft.controls.elevator) self.assertAlmostEqual(sensor_data_response.controls.rudder, aircraft.controls.rudder) self.assertAlmostEqual(sensor_data_response.controls.throttle, aircraft.controls.throttle) self.assertEqual(sensor_data_response.type, fdm_pb2.CONTROLS_REQUEST)
def create_simulator(self): """Create the Simulator object""" fdm_builder = FDMBuilder(self.data_path) fdm_builder.dt = self.dt fdm_builder.latitude = self.latitude fdm_builder.longitude = self.longitude fdm_builder.altitude = self.altitude fdm_builder.airspeed = self.airspeed fdm_builder.heading = self.heading fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) aircraft.start_engines() logger.debug("trimming the aircraft at mode %d", self.trim_mode) trim_result = aircraft.trim(self.trim_mode) if not trim_result: logger.warning("Failed to trim the aircraft") # reset the aircraft control because the trim operation might # have messed them up aircraft.controls.aileron = 0.0 aircraft.controls.elevator = 0.0 aircraft.controls.rudder = 0.0 aircraft.controls.throttle = 0.0 simulator = Simulator(fdmexec) simulator.trim_mode = self.trim_mode simulator.start_paused = self.start_paused result = simulator.step() if not result: logger.error("Failed to execute simulator run") return None if self.start_paused: simulator.pause() return simulator
def test_set_rudder(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdm_builder.aircraft = "Rascal" fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) fdmexec.GetFCS().SetDrCmd(0.178) self.assertAlmostEqual(aircraft.controls.rudder, 0.178, 0.0)
def test_set_throttle(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdm_builder.aircraft = "Rascal" fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) fdmexec.GetFCS().SetThrottleCmd(0, 0.198) self.assertAlmostEqual(aircraft.controls.throttle, 0.198)
def test_get_thermometer_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) resource = ThermometerResource(aircraft.sensors.thermometer) thermometer_data = resource.get() self.assertAlmostEqual(aircraft.sensors.thermometer.temperature, thermometer_data["temperature"], 3)
def test_get_engine_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) resource = EngineResource(aircraft.engine) engine_data = resource.get() self.assertAlmostEqual(aircraft.engine.thrust, engine_data["thrust"], 3)
def test_get_aircraft_information(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) resource = AircraftResource(aircraft) aircraft_data = resource.get() self.assertDictEqual(aircraft_data, {"type": "Rascal"})
def test_get_pitot_tube_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) resource = PitotTubeResource(aircraft.sensors.pitot_tube) pitot_tube_data = resource.get() self.assertAlmostEqual(aircraft.sensors.pitot_tube.pressure, pitot_tube_data["total_pressure"], 3)
def test_get_pressure_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) resource = PressureSensorResource(aircraft.sensors.pressure_sensor) pressure_sensor_data = resource.get() self.assertAlmostEqual(aircraft.sensors.pressure_sensor.pressure, pressure_sensor_data["static_pressure"], 3)
def test_get_gyroscope_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) resource = GyroscopeResource(aircraft.sensors.gyroscope) gyroscope_data = resource.get() self.assertAlmostEqual(aircraft.sensors.gyroscope.roll_rate, gyroscope_data["roll_rate"], 3) self.assertAlmostEqual(aircraft.sensors.gyroscope.pitch_rate, gyroscope_data["pitch_rate"], 3) self.assertAlmostEqual(aircraft.sensors.gyroscope.yaw_rate, gyroscope_data["yaw_rate"], 3)
def test_get_accelerometer_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) resource = AccelerometerResource(aircraft.sensors.accelerometer) accelerometer_data = resource.get() self.assertAlmostEqual(aircraft.sensors.accelerometer.x, accelerometer_data["x"], 3) self.assertAlmostEqual(aircraft.sensors.accelerometer.y, accelerometer_data["y"], 3) self.assertAlmostEqual(aircraft.sensors.accelerometer.z, accelerometer_data["z"], 3)
def test_get_flight_controls(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) resource = FlightControlsResource(aircraft.controls) flight_controls_data = resource.get() self.assertAlmostEqual(aircraft.controls.aileron, flight_controls_data["aileron"], 3) self.assertAlmostEqual(aircraft.controls.elevator, flight_controls_data["elevator"], 3) self.assertAlmostEqual(aircraft.controls.rudder, flight_controls_data["rudder"], 3) self.assertAlmostEqual(aircraft.engine.throttle, flight_controls_data["throttle"], 3)
def test_get_gps_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) resource = GPSResource(aircraft.instruments.gps) gps_data = resource.get() self.assertAlmostEqual(aircraft.instruments.gps.latitude, gps_data["latitude"], 3) self.assertAlmostEqual(aircraft.instruments.gps.longitude, gps_data["longitude"], 3) self.assertAlmostEqual(aircraft.instruments.gps.altitude, gps_data["altitude"], 3) self.assertAlmostEqual(aircraft.instruments.gps.airspeed, gps_data["airspeed"], 3) self.assertAlmostEqual(aircraft.instruments.gps.heading, gps_data["heading"], 3)
def test_get_ins_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) resource = InertialNavigationSystemResource(aircraft.sensors.inertial_navigation_system) inertial_navigation_system_data = resource.get() self.assertAlmostEqual(aircraft.sensors.inertial_navigation_system.latitude, inertial_navigation_system_data["latitude"], 3) self.assertAlmostEqual(aircraft.sensors.inertial_navigation_system.longitude, inertial_navigation_system_data["longitude"], 3) self.assertAlmostEqual(aircraft.sensors.inertial_navigation_system.altitude, inertial_navigation_system_data["altitude"], 3) self.assertAlmostEqual(aircraft.sensors.inertial_navigation_system.airspeed, inertial_navigation_system_data["airspeed"], 3) self.assertAlmostEqual(aircraft.sensors.inertial_navigation_system.heading, inertial_navigation_system_data["heading"], 3) self.assertAlmostEqual(aircraft.sensors.inertial_navigation_system.roll, inertial_navigation_system_data["roll"], 3) self.assertAlmostEqual(aircraft.sensors.inertial_navigation_system.pitch, inertial_navigation_system_data["pitch"], 3)
def test_fill_pitot_tube_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdm_builder.aircraft = "Rascal" fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) factory = SensorDataFactory(aircraft) protocol = factory.buildProtocol(("127.0.0.1", 12345)) sensor_data_response = fdm_pb2.SensorDataResponse() protocol.fill_pitot_tube_data(sensor_data_response) self.assertAlmostEqual(sensor_data_response.pitot_tube.pressure, aircraft.sensors.pitot_tube.pressure) self.assertEqual(sensor_data_response.type, fdm_pb2.PITOT_TUBE_REQUEST)
def test_fill_engine_data(self): huginn_data_path = configuration.get_data_path() fdm_builder = FDMBuilder(huginn_data_path) fdm_builder.aircraft fdmexec = fdm_builder.create_fdm() aircraft = Aircraft(fdmexec) factory = SensorDataFactory(aircraft) protocol = factory.buildProtocol(("127.0.0.1", 12345)) sensor_data_response = fdm_pb2.SensorDataResponse() protocol.fill_engine_data(sensor_data_response) self.assertAlmostEqual(sensor_data_response.engine.thrust, aircraft.engine.thrust) self.assertAlmostEqual(sensor_data_response.engine.throttle, aircraft.engine.throttle) self.assertEqual(sensor_data_response.type, fdm_pb2.ENGINE_REQUEST)
class Simulator(object): """The Simulator class is used to perform the simulation of an aircraft""" def __init__(self, fdmexec): """Constructor for the Simulator object Arguments: fdmexec: A flight dynamics model """ self.aircraft = Aircraft(fdmexec) self.fdmexec = fdmexec self.fdm = FDM(fdmexec) self.trim_mode = TRIM_MODE_FULL self._crashed = False self.start_paused = False @property def crashed(self): """Returns True if the aircraft has crashed""" return self._crashed @property def dt(self): """The simulation time step""" return self.fdmexec.GetDeltaT() @property def simulation_time(self): """The current simulation time""" return self.fdmexec.GetSimTime() def pause(self): """Pause the simulator""" self.fdmexec.Hold() def resume(self): """Resume the simulation""" if self.crashed: logger.debug("Not resuming simulation because the aircraft has " "crashed") return if self.fdmexec.IntegrationSuspended(): self.fdmexec.ResumeIntegration() self.fdmexec.Resume() def is_paused(self): """Check if the simulator is paused""" return self.fdmexec.Holding() def reset(self): """Reset the simulation""" logger.debug("Reseting the aircraft") self._crashed = False self.pause() self.aircraft.controls.aileron = 0.0 self.aircraft.controls.elevator = 0.0 self.aircraft.controls.rudder = 0.0 self.aircraft.controls.throttle = 0.0 self.fdmexec.ResetToInitialConditions(0) if not self.fdmexec.RunIC(): logger.error("Failed to run initial condition") return False logger.debug("starting the aircraft's engines") self.aircraft.start_engines() trim_result = self.aircraft.trim(self.trim_mode) if not trim_result: logger.warning("Failed to trim the aircraft") # reset the controls because the trim operation might have messed # them up self.aircraft.controls.aileron = 0.0 self.aircraft.controls.elevator = 0.0 self.aircraft.controls.rudder = 0.0 self.aircraft.controls.throttle = 0.0 if not self.step(): logger.error("Failed to execute initial run") return False logger.debug("Engine thrust after simulation reset %f", self.aircraft.engine.thrust) if not self.start_paused: self.resume() return True def step(self): """Run the simulation one time""" if not self.crashed and self.fdm.position.altitude < 0.0: logger.debug("Aircraft has crashed. Pausing simulator") self.pause() self._crashed = True return True if self.crashed: logger.debug("Not executing simulation step because aircraft has " "crashed") return True was_paused = self.is_paused() if was_paused: self.resume() try: self.fdmexec.ProcessMessage() self.fdmexec.CheckIncrementalHold() run_result = self.fdmexec.Run() except: raise SimulationError() if run_result: if was_paused: self.pause() return True else: if was_paused: self.pause() logger.error("The simulator has failed to run") return False def run_for(self, time_to_run): """Run the simulation for the given time in seconds Arguments: time_to_run: the time in seconds that the simulator will run """ if time_to_run < 0.0: logger.error("Invalid simulator run time length %f", time_to_run) return False start_time = self.fdmexec.GetSimTime() end_time = start_time + time_to_run while self.fdmexec.GetSimTime() <= end_time: result = self.step() if not result: return False return True def run(self): """Run the simulation""" if not self.fdmexec.Holding(): result = self.step() return result return True def set_aircraft_controls(self, aileron, elevator, rudder, throttle): """Update the aircraft controls""" self.aircraft.controls.aileron = aileron self.aircraft.controls.elevator = elevator self.aircraft.controls.rudder = rudder self.aircraft.controls.throttle = throttle def print_simulator_state(self): """Show the current state of the simulation""" print("Simulation state") print("================") print("Time: %f seconds" % self.simulation_time) print("DT: %f seconds" % self.dt) print("Running: %s" % (not self.is_paused())) print("")