# AP_FLAKE8_CLEAN from LogAnalyzer import Test, TestResult from VehicleType import VehicleType # from ArduCopter/defines.h AUTOTUNE_INITIALISED = 30 AUTOTUNE_OFF = 31 AUTOTUNE_RESTART = 32 AUTOTUNE_SUCCESS = 33 AUTOTUNE_FAILED = 34 AUTOTUNE_REACHED_LIMIT = 35 AUTOTUNE_PILOT_TESTING = 36 AUTOTUNE_SAVEDGAINS = 37 AUTOTUNE_EVENTS = frozenset( [ AUTOTUNE_INITIALISED, AUTOTUNE_OFF, AUTOTUNE_RESTART, AUTOTUNE_SUCCESS, AUTOTUNE_FAILED, AUTOTUNE_REACHED_LIMIT, AUTOTUNE_PILOT_TESTING, AUTOTUNE_SAVEDGAINS, ] ) class TestAutotune(Test): '''test for autotune success (copter only)''' class AutotuneSession(object): def __init__(self, events): self.events = events @property def linestart(self): return self.events[0][0] @property def linestop(self): return self.events[-1][0] @property def success(self): return AUTOTUNE_SUCCESS in [i for _, i in self.events] @property def failure(self): return AUTOTUNE_FAILED in [i for _, i in self.events] @property def limit(self): return AUTOTUNE_REACHED_LIMIT in [i for _, i in self.events] def __repr__(self): return "".format(self.linestart, self.linestop) def __init__(self): Test.__init__(self) self.name = "Autotune" def run(self, logdata, verbose): self.result = TestResult() self.result.status = TestResult.StatusType.GOOD if logdata.vehicleType != VehicleType.Copter: self.result.status = TestResult.StatusType.NA return for i in ['EV', 'ATDE', 'ATUN']: r = False if i not in logdata.channels: self.result.status = TestResult.StatusType.UNKNOWN self.result.statusMessage = "No {} log data".format(i) r = True if r: return events = list(filter(lambda x: x[1] in AUTOTUNE_EVENTS, logdata.channels["EV"]["Id"].listData)) attempts = [] j = None for i in range(0, len(events)): line, ev = events[i] if ev == AUTOTUNE_INITIALISED: if j is not None: attempts.append(TestAutotune.AutotuneSession(events[j:i])) j = i # last attempt if j is not None: attempts.append(TestAutotune.AutotuneSession(events[j:])) for a in attempts: # this should not be necessary! def class_from_channel(c): members = dict({'__init__': lambda x: setattr(x, i, None) for i in logdata.channels[c]}) cls = type('Channel__{:s}'.format(c), (object,), members) return cls # last wins if a.success: self.result.status = TestResult.StatusType.GOOD s = "[+]" elif a.failure: self.result.status = TestResult.StatusType.FAIL s = "[-]" else: self.result.status = TestResult.StatusType.UNKNOWN s = "[?]" s += " Autotune {}-{}\n".format(a.linestart, a.linestop) self.result.statusMessage += s if verbose: linenext = a.linestart + 1 while linenext < a.linestop: try: line = logdata.channels['ATUN']['RateMax'].getNearestValueFwd(linenext)[1] if line > a.linestop: break except ValueError: break atun = class_from_channel('ATUN')() for key in logdata.channels['ATUN']: setattr(atun, key, logdata.channels['ATUN'][key].getNearestValueFwd(linenext)[0]) linenext = logdata.channels['ATUN'][key].getNearestValueFwd(linenext)[1] + 1 self.result.statusMessage += ( "ATUN Axis:{atun.Axis} TuneStep:{atun.TuneStep} RateMin:{atun.RateMin:5.0f}" " RateMax:{atun.RateMax:5.0f} RPGain:{atun.RPGain:1.4f} RDGain:{atun.RDGain:1.4f}" " SPGain:{atun.SPGain:1.1f} (@line:{l})\n" ).format(l=linenext, atun=atun) self.result.statusMessage += '\n'