Changeset 9:3dac12e8914d


Ignore:
Timestamp:
02/05/12 13:42:53 (11 years ago)
Author:
István Váradi <ivaradi@…>
Branch:
default
hg-Phase:
(<MercurialRepository 1 'hg:/home/ivaradi/mlx/hg' '/'>, 'public')
Message:

Flare calculations are handled and added some other printouts

Files:
8 edited

Legend:

Unmodified
Added
Removed
  • TODO

    r7 r9  
    11- Check how piston engines report RPM
     2
     3- Test:
     4   - Mach cruise speed
     5   - ZFW at takeoff
     6   - Speed, heading, pitch at takeoff
  • src/acft.py

    r8 r9  
    2121        self._flight = flight
    2222        self._aircraftState = None
     23       
     24        self._maxVS = -10000.0
     25        self._minVS = 10000.0
    2326
    2427        self._checkers = []
    2528
    2629        self._checkers.append(checks.StageChecker())
     30        self._checkers.append(checks.TakeOffLogger())
    2731
    2832        self._checkers.append(checks.AltimeterLogger())
     
    4145        self._checkers.append(checks.GearsLogger())
    4246
     47        self._checkers.append(checks.CruiseSpeedLogger())
     48
    4349    @property
    4450    def type(self):
     
    6874                          self._aircraftState, aircraftState)
    6975
     76        self._maxVS = max(self._maxVS, aircraftState.vs)
     77        self._minVS = min(self._minVS, aircraftState.vs)
     78
    7079        self._aircraftState = aircraftState
    7180   
     
    7382        """Set the given stage as the new one and do whatever should be
    7483        done."""
    75         self._flight.setStage(aircraftState.timestamp, newStage)
    76 
    77     def flare(self):
    78         """Called when it is detected that we are during flare.
     84        if self._flight.setStage(aircraftState.timestamp, newStage):
     85            if newStage==const.STAGE_PUSHANDTAXI:
     86                self.logger.message(aircraftState.timestamp, "Block time start")
     87                self.logFuel(aircraftState)
     88                self.logger.message(aircraftState.timestamp,
     89                                    "Zero-fuel weight: %.0f kg" % (aircraftState.zfw))
     90            elif newStage==const.STAGE_TAKEOFF:
     91                self.logger.message(aircraftState.timestamp, "Flight time start")
     92                self.logger.message(aircraftState.timestamp,
     93                                    "Takeoff weight: %.0f kg, MTOW: %.0f kg" % \
     94                                    (aircraftState.grossWeight, self.mtow))
     95                self.logger.message(aircraftState.timestamp,
     96                                    "Wind %03.0f degrees at %.0f knots" % \
     97                                    (aircraftState.windDirection,
     98                                     aircraftState.windSpeed))
     99            elif newStage==const.STAGE_TAXIAFTERLAND:
     100                self.logger.message(aircraftState.timestamp, "Flight time end")
     101                self.logFuel(aircraftState)
     102                self.logger.message(aircraftState.timestamp,
     103                                    "Landing weight: %.0f kg, MLW: %.0f" % \
     104                                    (aircraftState.grossWeight, self.mlw))
     105                self.logger.message(aircraftState.timestamp,
     106                                    "Vertical speed range: %.0f..%.0f feet/min" % \
     107                                    (self._maxVS, self._minVS))
     108            elif newStage==const.STAGE_PARKING:
     109                self.logger.message(aircraftState.timestamp, "Block time end")
     110
     111    def prepareFlare(self):
     112        """Called when it is detected that we will soon flare.
    79113
    80114        On the first call, it should start monitoring some parameters more
    81115        closely to determine flare time."""
    82         pass
     116        self.flight.simulator.startFlare()
     117
     118    def flareStarted(self, windSpeed, windDirection, visibility,
     119                     flareStart, flareStartFS):
     120        """Called when the flare has started."""
     121        self.logger.message(self._aircraftState.timestamp, "The flare has begun")
     122        self.logger.message(self._aircraftState.timestamp,
     123                            "Wind %03.0f degrees at %.0f knots" % \
     124                            (windDirection, windSpeed))
     125        self.logger.message(self._aircraftState.timestamp,
     126                            "Visibility: %.0f metres" % (visibility,))
     127        self.logger.message(self._aircraftState.timestamp,
     128                            "Altimeter setting: %.0f hPa" % \
     129                            (self._aircraftState.altimeter,))
     130        self.flight.flareStarted(flareStart, flareStartFS)
     131         
     132    def flareFinished(self, flareEnd, flareEndFS, tdRate, tdRateCalculatedByFS,
     133                      ias, pitch, bank, heading):
     134        """Called when the flare has finished."""
     135        (flareTimeFromFS, flareTime) = self.flight.flareFinished(flareEnd,
     136                                                                 flareEndFS)
     137        self.logger.message(self._aircraftState.timestamp,
     138                            "Flare time: %.1f s (from %s)" % \
     139                            (flareTime,
     140                             "the simulator" if flareTimeFromFS else "real time",))
     141        self.logger.message(self._aircraftState.timestamp,
     142                            "Touchdown rate: %.0f feet/min" % (tdRate,))
     143        self.logger.message(self._aircraftState.timestamp,
     144                            "Touchdown rate was calculated by the %s" % \
     145                            ("simulator" if tdRateCalculatedByFS else "logger",))
     146        self.logger.message(self._aircraftState.timestamp,
     147                            "Touchdown speed: %.0f knots" % (ias,))
     148        self.logger.message(self._aircraftState.timestamp,
     149                            "Touchdown pitch: %.1f degrees" % (pitch,))
     150        self.logger.message(self._aircraftState.timestamp,
     151                            "Touchdown bank: %.1f degrees" % (bank,))
     152        self.logger.message(self._aircraftState.timestamp,
     153                            "Touchdown heading: %03.0f degrees" % (heading,))
    83154
    84155    def cancelFlare(self):
    85156        """Cancel flare, if it has started."""
    86         pass
     157        self.flight.simulator.cancelFlare()
    87158
    88159    def checkFlightEnd(self, aircraftState):
     
    105176    - n1: left, right
    106177    - reverser: left, right"""
    107     pass
    108 
     178    def __init__(self, flight):
     179        super(Boeing737, self).__init__(flight)
     180        self.gearSpeedLimit = 270
     181        self.flapSpeedLimits = { 1 : 260,
     182                                 2 : 260,
     183                                 5 : 250,
     184                                 10 : 210,
     185                                 15 : 200,
     186                                 25 : 190,
     187                                 30 : 175,
     188                                 40 : 162 }
     189
     190    def logFuel(self, aircraftState):
     191        """Log the amount of fuel"""
     192        self.logger.message(aircraftState.timestamp,
     193                            "Fuel: left=%.0f kg - centre=%.0f kg - right=%.0f kg" % \
     194                            (aircraftState.fuel[1], aircraftState.fuel[0],
     195                             aircraftState.fuel[2]))
     196        self.logger.message(aircraftState.timestamp,
     197                            "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
     198                           
    109199#---------------------------------------------------------------------------------------
    110200
     
    113203    def __init__(self, flight):
    114204        super(B736, self).__init__(flight)
     205        self.dow = 38307
     206        self.mtow = 58328
     207        self.mlw = 54657
     208        self.mzfw = 51482
    115209
    116210#---------------------------------------------------------------------------------------
     
    120214    def __init__(self, flight):
    121215        super(B737, self).__init__(flight)
     216        self.dow = 39250
     217        self.mtow = 61410
     218        self.mlw = 58059
     219        self.mzfw = 54657
    122220
    123221#---------------------------------------------------------------------------------------
     
    127225    def __init__(self, flight):
    128226        super(B738, self).__init__(flight)
     227        self.dow = 42690
     228        self.mtow = 71709
     229        self.mlw = 65317
     230        self.mzfw = 61688
     231
     232#---------------------------------------------------------------------------------------
     233
     234class B738Charter(B738):
     235    """Boeing 737-800 aircraft used for charters."""
     236    def __init__(self, flight):
     237        super(B738Charter, self).__init__(flight)
     238        self.mtow = 77791
    129239
    130240#---------------------------------------------------------------------------------------
     
    134244    def __init__(self, flight):
    135245        super(B733, self).__init__(flight)
     246        self.dow = 32700
     247        self.mtow = 62820
     248        self.mlw = 51700
     249        self.mzfw = 48410
    136250
    137251#---------------------------------------------------------------------------------------
     
    141255    def __init__(self, flight):
    142256        super(B734, self).__init__(flight)
     257        self.dow = 33200
     258        self.mtow = 68050
     259        self.mlw = 56200
     260        self.mzfw = 53100
    143261
    144262#---------------------------------------------------------------------------------------
     
    148266    def __init__(self, flight):
    149267        super(B735, self).__init__(flight)
     268        self.dow = 31300
     269        self.mtow = 60550
     270        self.mlw = 50000
     271        self.mzfw = 46700
    150272
    151273#---------------------------------------------------------------------------------------
     
    161283    def __init__(self, flight):
    162284        super(DH8D, self).__init__(flight)
     285        self.dow = 17185
     286        self.mtow = 29257
     287        self.mlw = 28009
     288        self.mzfw = 25855
     289        self.gearSpeedLimit = 215
     290        self.flapSpeedLimits = { 5 : 200,
     291                                 10 : 181,
     292                                 15 : 172,
     293                                 35 : 158 }
     294
     295    def logFuel(self, aircraftState):
     296        """Log the amount of fuel"""
     297        self.logger.message(aircraftState.timestamp,
     298                            "Fuel: left=%.0f kg - centre=%.0f kg - right=%.0f kg" % \
     299                            (aircraftState.fuel[1], aircraftState.fuel[0],
     300                             aircraftState.fuel[2]))
     301        self.logger.message(aircraftState.timestamp,
     302                            "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
    163303
    164304#---------------------------------------------------------------------------------------
     
    172312    - n1: left, right
    173313    - reverser: left, right"""
    174 
     314    def __init__(self, flight):
     315        super(Boeing767, self).__init__(flight)
     316        self.gearSpeedLimit = 270
     317        self.flapSpeedLimits = { 1 : 255,
     318                                 5 : 235,
     319                                 10 : 215,
     320                                 20 : 215,
     321                                 25 : 185,
     322                                 30 : 175 }
     323
     324    def logFuel(self, aircraftState):
     325        """Log the amount of fuel"""
     326        self.logger.message(aircraftState.timestamp,
     327                            "Fuel: left=%.0f kg - centre=%.0f kg - right=%.0f kg" % \
     328                            (aircraftState.fuel[1], aircraftState.fuel[0],
     329                             aircraftState.fuel[2]))
     330        self.logger.message(aircraftState.timestamp,
     331                            "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
     332                           
    175333#---------------------------------------------------------------------------------------
    176334
     
    179337    def __init__(self, flight):
    180338        super(B762, self).__init__(flight)
     339        self.dow = 84507
     340        self.mtow = 175540
     341        self.mlw = 126098
     342        self.mzfw = 114758
    181343
    182344#---------------------------------------------------------------------------------------
     
    186348    def __init__(self, flight):
    187349        super(B763, self).__init__(cflight)
     350        self.dow = 91311
     351        self.mtow = 181436
     352        self.mlw = 137892
     353        self.mzfw = 130635
    188354
    189355#---------------------------------------------------------------------------------------
     
    199365    def __init__(self, flight):
    200366        super(CRJ2, self).__init__(flight)
    201 
     367        self.dow = 14549
     368        self.mtow = 22995
     369        self.mlw = 21319
     370        self.mzfw = 19958
     371        self.gearSpeedLimit = 240
     372        self.flapSpeedLimits = { 8 : 260,
     373                                 20 : 220,
     374                                 30 : 190,
     375                                 45 : 175 }
     376
     377    def logFuel(self, aircraftState):
     378        """Log the amount of fuel"""
     379        self.logger.message(aircraftState.timestamp,
     380                            "Fuel: left=%.0f kg - centre=%.0f kg - right=%.0f kg" % \
     381                            (aircraftState.fuel[1], aircraftState.fuel[0],
     382                             aircraftState.fuel[2]))
     383        self.logger.message(aircraftState.timestamp,
     384                            "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
     385                           
    202386#---------------------------------------------------------------------------------------
    203387
     
    212396    def __init__(self, flight):
    213397        super(F70, self).__init__(flight)
    214 
     398        self.dow = 24283
     399        self.mtow = 38100 # FIXME: differentiate by registration number,
     400                          # MTOW of HA-LMF: 41955
     401        self.mlw = 36740
     402        self.mzfw = 32655
     403        self.gearSpeedLimit = 200
     404        self.flapSpeedLimits = { 8 : 250,
     405                                 15 : 220,
     406                                 25 : 220,
     407                                 42 : 180 }
     408
     409    def logFuel(self, aircraftState):
     410        """Log the amount of fuel"""
     411        self.logger.message(aircraftState.timestamp,
     412                            "Fuel: left=%.0f kg - centre=%.0f kg - right=%.0f kg" % \
     413                            (aircraftState.fuel[1], aircraftState.fuel[0],
     414                             aircraftState.fuel[2]))
     415        self.logger.message(aircraftState.timestamp,
     416                            "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
     417                           
    215418#---------------------------------------------------------------------------------------
    216419
     
    225428    def __init__(self, flight):
    226429        super(DC3, self).__init__(flight)
     430        self.dow = 8627
     431        self.mtow = 11884
     432        self.mlw = 11793
     433        self.mzfw = 11780
     434        self.gearSpeedLimit = 148
     435        self.flapSpeedLimits = { 15 : 135,
     436                                 30 : 99,
     437                                 45 : 97 }
    227438
    228439    def _checkFlightEnd(self, aircraftState):
     
    234445        self._setStage(aircraftState, const.STAGE_END)
    235446
     447    def logFuel(self, aircraftState):
     448        """Log the amount of fuel"""
     449        self.logger.message(aircraftState.timestamp,
     450                            "Fuel: left aux=%.0f kg - left=%.0f kg - right=%.0f kg - right aux=%.0f kg" % \
     451                            (aircraftState.fuel[2], aircraftState.fuel[0],
     452                             aircraftState.fuel[1], aircraftState.fuel[3]))
     453        self.logger.message(aircraftState.timestamp,
     454                            "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
     455                           
    236456#---------------------------------------------------------------------------------------
    237457
     
    247467    def __init__(self, flight):
    248468        super(T134, self).__init__(flight)
    249 
     469        self.dow = 29927
     470        self.mtow = 47600
     471        self.mlw = 43000
     472        self.mzfw = 38500
     473        self.gearSpeedLimit = 216
     474        self.flapSpeedLimits = { 10 : 240,
     475                                 20 : 216,
     476                                 30 : 161 }
     477
     478    def logFuel(self, aircraftState):
     479        """Log the amount of fuel"""
     480        self.logger.message(aircraftState.timestamp,
     481                            "Fuel: left aux=%.0f kg - left tip=%.0f kg - centre= %.0f kg - right tip=%.0f kg - right aux=%.0f kg - external 1=%.0f kg - external 2=%.0f kg" % \
     482                            (aircraftState.fuel[2], aircraftState.fuel[1],
     483                             aircraftState.fuel[0],
     484                             aircraftState.fuel[3], aircraftState.fuel[4],
     485                             aircraftState.fuel[5], aircraftState.fuel[6]))
     486        self.logger.message(aircraftState.timestamp,
     487                            "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
     488                           
    250489#---------------------------------------------------------------------------------------
    251490
     
    260499    def __init__(self, flight):
    261500        super(T154, self).__init__(flight)
    262 
    263 #---------------------------------------------------------------------------------------
     501        self.dow = 53259
     502        self.mtow = 98000
     503        self.mlw = 78000
     504        self.mzfw = 72000
     505        self.gearSpeedLimit = 216
     506        self.flapSpeedLimits = { 15 : 227,
     507                                 28 : 194,
     508                                 45 : 162 }
     509
     510    def logFuel(self, aircraftState):
     511        """Log the amount of fuel"""
     512        self.logger.message(aircraftState.timestamp,
     513                            "Fuel: left aux=%.0f kg - left=%.0f kg - centre=%.0f kg - centre 2=%.0f kg - right=%.0f kg - right aux=%.0f kg" % \
     514                            (aircraftState.fuel[4], aircraftState.fuel[1],
     515                             aircraftState.fuel[0], aircraftState.fuel[3],
     516                             aircraftState.fuel[2], aircraftState.fuel[5]))
     517        self.logger.message(aircraftState.timestamp,
     518                            "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
     519
     520#---------------------------------------------------------------------------------------
     521
    264522
    265523class YK40(Aircraft):
     
    273531    def __init__(self, flight):
    274532        super(YK40, self).__init__(flight)
     533        self.dow = 9400
     534        self.mtow = 17200
     535        self.mlw = 16800
     536        self.mzfw = 12100
     537        self.gearSpeedLimit = 165
     538        self.flapSpeedLimits = { 20 : 165,
     539                                 35 : 135 }
     540
     541    def logFuel(self, aircraftState):
     542        """Log the amount of fuel"""
     543        self.logger.message(aircraftState.timestamp,
     544                            "Fuel: left=%.0f kg - right=%.0f kg" % \
     545                            (aircraftState.fuel[0], aircraftState.fuel[1]))
     546        self.logger.message(aircraftState.timestamp,
     547                            "Total fuel: %.0f kg" % (sum(aircraftState.fuel),))
    275548
    276549#---------------------------------------------------------------------------------------
  • src/checks.py

    r8 r9  
    6666                aircraft.cancelFlare()
    6767            elif state.radioAltitude<150 and not state.onTheGround:
    68                 aircraft.flare()
     68                aircraft.prepareFlare()
    6969        elif stage==const.STAGE_TAXIAFTERLAND:
    7070            if state.parking:
     
    7373            if aircraft.checkFlightEnd(state):
    7474                aircraft.setStage(state, const.STAGE_END)
     75
     76#---------------------------------------------------------------------------------------
     77
     78class TakeOffLogger(StateChecker):
     79    """Logger for the cruise speed."""
     80    def __init__(self):
     81        """Construct the logger."""
     82        self._onTheGround = True
     83   
     84    def check(self, flight, aircraft, logger, oldState, state):
     85        """Log the cruise speed if necessary."""
     86        if flight.stage==const.STAGE_TAKEOFF and \
     87           self._onTheGround and not state.onTheGround:
     88            logger.message(state.timestamp,
     89                           "Takeoff speed: %.0f knots" % (state.ias,))
     90            logger.message(state.timestamp,
     91                           "Takeoff heading: %03.0f degrees" % (state.heading,))
     92            logger.message(state.timestamp,
     93                           "Takeoff pitch: %.1f degrees" % (state.pitch,))
     94            self._onTheGround = False
     95
     96#---------------------------------------------------------------------------------------
     97
     98class CruiseSpeedLogger(StateChecker):
     99    """Logger for the cruise speed."""
     100    def __init__(self):
     101        """Construct the logger."""
     102        self._lastTime = None
     103   
     104    def check(self, flight, aircraft, logger, oldState, state):
     105        """Log the cruise speed if necessary."""
     106        if flight.stage==const.STAGE_CRUISE and \
     107           (self._lastTime is None or \
     108            (self._lastTime+800)<=state.timestamp):
     109                if state.altitude>24500.0:
     110                    logger.message(state.timestamp,
     111                                   "Cruise speed: %.2f mach" % (state.mach,))
     112                else:
     113                    logger.message(state.timestamp,
     114                                   "Cruise speed: %.0f knots" % (state.ias,))
     115                self._lastTime = state.timestamp
    75116
    76117#---------------------------------------------------------------------------------------
     
    301342    def _getMessage(self, state):
    302343        """Get the message to log on a change."""
    303         return "Gears %s at %.0f knots, %f feet" % \
     344        return "Gears %s at %.0f knots, %.0f feet" % \
    304345            ("DOWN" if state.gearsDown else "UP", state.ias, state.altitude)
    305346
  • src/flight.py

    r8 r9  
    1919        self.logger = logger
    2020        self.cruiseAltitude = None
     21        self.flareTimeFromFS = False
    2122        self.aircraftType = None
    2223        self.aircraft = None
     
    2425
    2526        self._endCondition = threading.Condition()
     27
     28        self._flareStart = None
     29        self._flareStartFS = None
    2630
    2731    @property
     
    3135
    3236    def setStage(self, timestamp, stage):
    33         """Set the flight stage."""
     37        """Set the flight stage.
     38
     39        Returns if the stage has really changed."""
    3440        if stage!=self._stage:
    3541            self._stage = stage
     
    3844                with self._endCondition:
    3945                    self._endCondition.notify()
     46            return True
     47        else:
     48            return False
     49
     50    def flareStarted(self, flareStart, flareStartFS):
     51        """Called when the flare time has started."""
     52        self._flareStart = flareStart
     53        self._flareStartFS = flareStartFS
     54
     55    def flareFinished(self, flareEnd, flareEndFS):
     56        """Called when the flare time has ended.
     57       
     58        Return a tuple of the following items:
     59        - a boolean indicating if FS time is used
     60        - the flare time
     61        """
     62        if self.flareTimeFromFS:
     63            return (True, flareEndFS - self._flareStartFS)
     64        else:
     65            return (False, flareEnd - self._flareStart)
    4066
    4167    def wait(self):
  • src/fs.py

    r8 r9  
    5353    - stalled: a boolean indicating if the aircraft is stalled
    5454    - onTheGround: a boolean indicating if the aircraft is on the ground
     55    - zfw: the zero-fuel weight in kilograms (float)
    5556    - grossWeight: the gross weight in kilograms (float)
    5657    - heading: the heading of the aircraft in degrees (float)
     
    6061    negative means bank right (float)
    6162    - ias: the indicated airspeed in knots (float)   
     63    - mach: the airspeed in mach (float)   
    6264    - groundSpeed: the ground speed (float)
    6365    - vs: the vertical speed in feet/minutes (float)
     
    9395    - nav2: the frequency of the NAV1 radio in MHz (string)
    9496    - squawk: the transponder code
     97    - windSpeed: the speed of the wind at the aircraft in knots (float)
     98    - windDirection: the direction of the wind at the aircraft in degrees (float)
    9599
    96100    FIXME: needed when taxiing only:
    97     - zfw: the Zero Fuel Weight in klograms (float)
    98101    - payload weight
    99 
    100     FIXME: needed for touchdown only:
    101     - ambientWindDirection: the ambient wind direction around the aircraft (float)
    102     - ambientWindSpeed: the ambient wind speed around the aircraft in knowns (float)
    103     - tdRate: the touchdown rate calculated by FSUIPC (float)
    104102
    105103    FIXME: needed rarely:
  • src/fsuipc.py

    r8 r9  
    2222class Handler(threading.Thread):
    2323    """The thread to handle the FSUIPC requests."""
     24    @staticmethod
     25    def fsuipc2VS(data):
     26        """Convert the given vertical speed data read from FSUIPC into feet/min."""
     27        return data*60.0/const.FEETTOMETRES/256.0
     28
     29    @staticmethod
     30    def fsuipc2radioAltitude(data):
     31        """Convert the given radio altitude data read from FSUIPC into feet."""
     32        return data/const.FEETTOMETRES/65536.0
     33
     34    @staticmethod
     35    def fsuipc2Degrees(data):
     36        """Convert the given data into degrees."""
     37        return data * 360.0 / 65536.0 / 65536.0
     38
     39    @staticmethod
     40    def fsuipc2PositiveDegrees(data):
     41        """Convert the given data into positive degrees."""
     42        degrees = Handler.fsuipc2Degrees(data)
     43        if degrees<0.0: degrees += 360.0
     44        return degrees
     45
     46    @staticmethod
     47    def fsuipc2IAS(data):
     48        """Convert the given data into indicated airspeed."""
     49        return data / 128.0
     50
    2451    @staticmethod
    2552    def _callSafe(fun):
     
    341368    via FSUIPC."""
    342369    # The basic data that should be queried all the time once we are connected
    343     normalData = [ (0x0240, "H"),
    344                    (0x023e, "H"),
    345                    (0x023b, "b"),
    346                    (0x023c, "b"),
    347                    (0x023a, "b"),
    348                    (0x3d00, -256),
    349                    (0x3c00, -256) ]
    350    
     370    normalData = [ (0x0240, "H"),            # Year
     371                   (0x023e, "H"),            # Number of day in year
     372                   (0x023b, "b"),            # UTC hour
     373                   (0x023c, "b"),            # UTC minute
     374                   (0x023a, "b"),            # seconds
     375                   (0x3d00, -256),           # The name of the current aircraft
     376                   (0x3c00, -256) ]          # The path of the current AIR file
     377
     378    flareData1 = [ (0x023a, "b"),            # Seconds of time
     379                   (0x31e4, "d"),            # Radio altitude
     380                   (0x02c8, "d") ]           # Vertical speed
     381                   
     382    flareStartData = [ (0x0e90, "H"),        # Ambient wind speed
     383                       (0x0e92, "H"),        # Ambient wind direction
     384                       (0x0e8a, "H") ]       # Visibility
     385                       
     386    flareData2 = [ (0x023a, "b"),            # Seconds of time
     387                   (0x0366, "H"),            # On the ground
     388                   (0x02c8, "d"),            # Vertical speed
     389                   (0x030c, "d"),            # Touch-down rate
     390                   (0x02bc, "d"),            # IAS
     391                   (0x0578, "d"),            # Pitch
     392                   (0x057c, "d"),            # Bank
     393                   (0x0580, "d") ]           # Heading
     394
    351395    def __init__(self, connectionListener, aircraft):
    352396        """Construct the simulator.
     
    356400        - modelChanged(aircraftName, modelName): called when the model handling
    357401        the aircraft has changed.
    358         - handleState(aircraftState): handle the given state."""
     402        - handleState(aircraftState): handle the given state.
     403        - flareStarted(windSpeed, windDirection, visibility, flareStart,
     404                       flareStartFS): called when the flare has
     405          started. windSpeed is in knots, windDirection is in degrees and
     406          visibility is in metres. flareStart and flareStartFS are two time
     407          values expressed in seconds that can be used to calculate the flare
     408          time.
     409       - flareFinished(flareEnd, flareEndFS, tdRate, tdRateCalculatedByFS,
     410                       ias, pitch, bank, heading): called when the flare has
     411         finished, i.e. the aircraft is on the ground. flareEnd and flareEndFS
     412         are the two time values corresponding to the touchdown time. tdRate is
     413         the touch-down rate, tdRateCalculatedBySim indicates if the data comes
     414         from the simulator or was calculated by the adapter. The other data
     415         are self-explanatory and expressed in their 'natural' units."""
    359416        self._aircraft = aircraft
    360417
     
    370427        self._aircraftModel = None
    371428
     429        self._flareRequestID = None
     430        self._flareRates = []
     431        self._flareStart = None
     432        self._flareStartFS = None
     433       
    372434    def connect(self):
    373435        """Initiate a connection to the simulator."""
     
    385447        assert self._monitoringRequested
    386448        self._monitoringRequested = False
     449
     450    def startFlare(self):
     451        """Start monitoring the flare time.
     452
     453        At present it is assumed to be called from the FSUIPC thread, hence no
     454        protection."""
     455        #self._aircraft.logger.debug("startFlare")
     456        if self._flareRequestID is None:
     457            self._flareRates = []
     458            self._flareRequestID = self._handler.requestPeriodicRead(0.1,
     459                                                                     Simulator.flareData1,
     460                                                                     self._handleFlare1)
     461
     462    def cancelFlare(self):
     463        """Cancel monitoring the flare time.
     464
     465        At present it is assumed to be called from the FSUIPC thread, hence no
     466        protection."""
     467        if self._flareRequestID is not None:
     468            self._handler.clearPeriodic(self._flareRequestID)
     469            self._flareRequestID = None
    387470
    388471    def disconnect(self):
     
    485568                                              self._handleNormal)
    486569
     570    def _addFlareRate(self, data):
     571        """Append a flare rate to the list of last rates."""
     572        if len(self._flareRates)>=3:
     573            del self._flareRates[0]
     574        self._flareRates.append(Handler.fsuipc2VS(data))
     575
     576    def _handleFlare1(self, data, normal):
     577        """Handle the first stage of flare monitoring."""
     578        #self._aircraft.logger.debug("handleFlare1: " + str(data))
     579        if Handler.fsuipc2radioAltitude(data[1])<=50.0:
     580            self._flareStart = time.time()
     581            self._flareStartFS = data[0]
     582            self._handler.clearPeriodic(self._flareRequestID)
     583            self._flareRequestID = \
     584                self._handler.requestPeriodicRead(0.1,
     585                                                  Simulator.flareData2,
     586                                                  self._handleFlare2)
     587            self._handler.requestRead(Simulator.flareStartData,
     588                                      self._handleFlareStart)
     589               
     590        self._addFlareRate(data[2])
     591
     592    def _handleFlareStart(self, data, extra):
     593        """Handle the data need to notify the aircraft about the starting of
     594        the flare."""
     595        #self._aircraft.logger.debug("handleFlareStart: " + str(data))
     596        if data is not None:
     597            windDirection = data[1]*360.0/65536.0
     598            if windDirection<0.0: windDirection += 360.0
     599            self._aircraft.flareStarted(data[0], windDirection,
     600                                        data[2]*1609.344/100.0,
     601                                        self._flareStart, self._flareStartFS)
     602
     603    def _handleFlare2(self, data, normal):
     604        """Handle the first stage of flare monitoring."""
     605        #self._aircraft.logger.debug("handleFlare2: " + str(data))
     606        if data[1]!=0:
     607            flareEnd = time.time()
     608            self._handler.clearPeriodic(self._flareRequestID)
     609            self._flareRequestID = None
     610
     611            flareEndFS = data[0]
     612            if flareEndFS<self._flareStartFS:
     613                flareEndFS += 60
     614
     615            tdRate = Handler.fsuipc2VS(data[3])
     616            tdRateCalculatedByFS = True
     617            if tdRate==0 or tdRate>1000.0 or tdRate<-1000.0:
     618                tdRate = min(self._flareRates)
     619                tdRateCalculatedByFS = False
     620
     621            self._aircraft.flareFinished(flareEnd, flareEndFS,
     622                                         tdRate, tdRateCalculatedByFS,
     623                                         Handler.fsuipc2IAS(data[4]),
     624                                         Handler.fsuipc2Degrees(data[5]),
     625                                         Handler.fsuipc2Degrees(data[6]),
     626                                         Handler.fsuipc2PositiveDegrees(data[7]))
     627        else:
     628            self._addFlareRate(data[2])
     629                                                 
    487630#------------------------------------------------------------------------------
    488631
     
    499642                      ("stalled", 0x036c, "b"),
    500643                      ("onTheGround", 0x0366, "H"),
     644                      ("zfw", 0x3bfc, "d"),
    501645                      ("grossWeight", 0x30c0, "f"),
    502646                      ("heading", 0x0580, "d"),
     
    504648                      ("bank", 0x057c, "d"),
    505649                      ("ias", 0x02bc, "d"),
     650                      ("mach", 0x11c6, "H"),
    506651                      ("groundSpeed", 0x02b4, "d"),
    507652                      ("vs", 0x02c8, "d"),
     
    521666                      ("nav1", 0x0350, "H"),
    522667                      ("nav2", 0x0352, "H"),
    523                       ("squawk", 0x0354, "H")]
     668                      ("squawk", 0x0354, "H"),
     669                      ("windSpeed", 0x0e90, "H"),
     670                      ("windDirection", 0x0e92, "H")]
     671
    524672
    525673    specialModels = []
     
    624772        state.onTheGround = data[self._monidx_onTheGround]!=0
    625773
     774        state.zfw = data[self._monidx_zfw] * const.LBSTOKG / 256.0
    626775        state.grossWeight = data[self._monidx_grossWeight] * const.LBSTOKG
    627776       
    628         state.heading = data[self._monidx_heading]*360.0/65536.0/65536.0
    629         if state.heading<0.0: state.heading += 360.0
    630 
    631         state.pitch = data[self._monidx_pitch]*360.0/65536.0/65536.0
    632         state.bank = data[self._monidx_bank]*360.0/65536.0/65536.0
    633 
    634         state.ias = data[self._monidx_ias]/128.0
     777        state.heading = Handler.fsuipc2PositiveDegrees(data[self._monidx_heading])
     778
     779        state.pitch = Handler.fsuipc2Degrees(data[self._monidx_pitch])
     780        state.bank = Handler.fsuipc2Degrees(data[self._monidx_bank])
     781
     782        state.ias = Handler.fsuipc2IAS(data[self._monidx_ias])
     783        state.mach = data[self._monidx_mach] / 20480.0
    635784        state.groundSpeed = data[self._monidx_groundSpeed]* 3600.0/65536.0/1852.0
    636         state.vs = data[self._monidx_vs]*60.0/const.FEETTOMETRES/256.0
    637 
    638         state.radioAltitude = data[self._monidx_radioAltitude]/const.FEETTOMETRES/65536.0
     785        state.vs = Handler.fsuipc2VS(data[self._monidx_vs])
     786
     787        state.radioAltitude = \
     788            Handler.fsuipc2radioAltitude(data[self._monidx_radioAltitude])
    639789        state.altitude = data[self._monidx_altitude]/const.FEETTOMETRES/65536.0/65536.0
    640790
     
    687837        state.nav2 = AircraftModel.convertFrequency(data[self._monidx_nav2])
    688838        state.squawk = AircraftModel.convertBCD(data[self._monidx_squawk], 4)
     839
     840        state.windSpeed = data[self._monidx_windSpeed]
     841        state.windDirection = data[self._monidx_windDirection]*360.0/65536.0
     842        if state.windDirection<0.0: state.windDirection += 360.0
    689843       
    690844        return state
  • src/logger.py

    r8 r9  
    4141        print timeStr + ":", msg       
    4242
    43     def debug(self, timestamp, msg):
     43    def debug(self, msg):
    4444        """Log a debug message."""
    45         timeStr = Logger._getTimeStr(timestamp)
    46         print >> self._output, timeStr + ": [DEBUG] ", msg
    47         print timeStr + ": [DEBUG]", msg       
     45        print >> self._output, "[DEBUG] ", msg
     46        print "[DEBUG]", msg
    4847
    4948    def stage(self, timestamp, stage):
  • src/test.py

    r8 r9  
    1919        fl.aircraftType = const.AIRCRAFT_B736
    2020        fl.aircraft = acft.Aircraft.create(fl)
     21        #fl._stage = const.STAGE_LANDING
    2122        simulator = fs.createSimulator(const.SIM_MSFS9, fs.ConnectionListener(),
    2223                                       fl.aircraft)
Note: See TracChangeset for help on using the changeset viewer.