Exemple #1
0
 def testManualPrefix(self):
   # The type name of the test enum is completely artifical. Here, we claim it
   # has a type name that disagrees with the prefix in order to test the prefix
   # argument.
   helper = c_helpers.EnumHelper('FakeTypeName', FakeModule(FULL_ENUM),
                                 prefix='kTestEnum')
   for name, value in ENUM_VALUES.iteritems():
     self.assertEqual(value, helper.Value(name))
Exemple #2
0
 def testNameCollision(self):
   bad_enum = {'kCollisionAValue1': 1,
               'kCollisionBValue1': 1}
   module = FakeModule(bad_enum)
   with self.assertRaises(AssertionError) as e:
     c_helpers.EnumHelper('Collision', module)
   self.assertIn('kCollisionAValue1', e.exception.message)
   self.assertIn('kCollisionBValue1', e.exception.message)
Exemple #3
0
class JoystickAioUpdateIndicator(indicator.BaseIndicator):

    _MASK = c_helpers.EnumHelper('JoystickWarning',
                                 pack_avionics_messages).Value('NotPresent')

    def __init__(self):
        super(JoystickAioUpdateIndicator, self).__init__('Joystick')

    def Filter(self, messages):

        if not messages:
            return '--', stoplights.STOPLIGHT_UNAVAILABLE

        status = messages['JoystickStatus.JoystickA.status']
        if status is None:
            return 'No Update', stoplights.STOPLIGHT_ERROR
        elif avionics_util.CheckWarning(status, self._MASK):
            return 'Not Present', stoplights.STOPLIGHT_ERROR
        else:
            return 'Up', stoplights.STOPLIGHT_NORMAL
Exemple #4
0
This module looks for an 'ltc6804_config' tuple in the configuration file
(specified on command line). The ltc6804_config tuple should contain the
hardware revision EnumHelper and a dictionary that maps the board's hardware
revision to a list of dictionaries. Each dictionary in this list specifies
the configuration for each LTC6804 chip.
"""

import sys
import textwrap

from makani.avionics.firmware.drivers import ltc6804_types
from makani.avionics.firmware.monitors import generate_monitor_base
from makani.lib.python import c_helpers

rate_helper = c_helpers.EnumHelper('Ltc6804Rate', ltc6804_types)
cell_ch_helper = c_helpers.EnumHelper('Ltc6804CellCh', ltc6804_types)
aux_ch_helper = c_helpers.EnumHelper('Ltc6804AuxCh', ltc6804_types)
stat_ch_helper = c_helpers.EnumHelper('Ltc6804StatCh', ltc6804_types)
dcto_helper = c_helpers.EnumHelper('Ltc6804Dcto', ltc6804_types)
self_test_helper = c_helpers.EnumHelper('Ltc6804SelfTest', ltc6804_types)


class Ltc6804DeviceConfig(generate_monitor_base.DeviceConfigBase):
    """Generate LTC6804 voltage/current monitor configuration."""

    # TODO: Add unit tests.

    def __init__(self, config):
        expected_parameters = {
            'name', 'address', 'input_mask', 'balance_min_cutoff',
Exemple #5
0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Classes to perform checks on flight computers."""

from makani.analysis.checks import base_check
from makani.analysis.checks.collection import avionics_checks
from makani.avionics.firmware.monitors import fc_types
from makani.avionics.network import aio_node
from makani.lib.python import c_helpers

_FC_LABELS_HELPER = c_helpers.EnumHelper('FcLabel',
                                         aio_node,
                                         prefix='kAioNodeFc')
_FC_ANALOG_VOLTAGE_HELPER = c_helpers.EnumHelper('FcAnalogVoltage', fc_types)
_FC_INA219_MONITOR_HELPER = c_helpers.EnumHelper('FcIna219Monitor', fc_types)


class FcMonAnalogChecker(avionics_checks.BaseVoltageChecker):
    """The monitor to check flight computer voltage."""
    @base_check.RegisterSpecs
    def __init__(self, for_log, fc_short_name, **base_kwargs):
        """Initialize the voltage checker for a given flight computer.

    Args:
      for_log: True if this check is performed over a log. False if it is for
          realtime AIO messages.
      fc_short_name: Short name of a Flight Computer.
Exemple #6
0
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Dump routes from a TMS570 AIO node."""

import socket
import sys
import textwrap

from makani.avionics.common import aio
from makani.avionics.common import pack_avionics_messages
from makani.avionics.network import aio_node
from makani.avionics.network import message_type
from makani.lib.python import c_helpers

aio_node_helper = c_helpers.EnumHelper('AioNode', aio_node)
message_type_helper = c_helpers.EnumHelper('MessageType', message_type)


def _MacToString(mac):
    return '%02X:%02X:%02X:%02X:%02X:%02X' % (mac.a, mac.b, mac.c, mac.d,
                                              mac.e, mac.f)


def _FormatResponse(source, msg):
    source_name = aio_node_helper.ShortName(source)
    mac = _MacToString(msg.entry.ethernet_address)
    mcast = (msg.entry.ethernet_address.a & 1) == 1
    mcast_str = 'Multicast' if mcast else 'Unicast'
    port_str = ('mask 0x%02X' if mcast else 'port %d') % msg.entry.port_map
    print(
Exemple #7
0
    def __init__(self, for_log, message_type, node, **base_kwargs):

        super(AioMonAnalogChecker, self).__init__(
            for_log, message_type, node, 'aio_mon.analog_data',
            'aio_mon.analog_populated',
            c_helpers.EnumHelper('AioAnalogVoltage', aio_types), **base_kwargs)
Exemple #8
0
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Scoring functions relating to the hover controller."""

from makani.analysis.control import geometry
from makani.avionics.common import plc_messages
from makani.lib.python import c_helpers
from makani.lib.python.batch_sim import scoring_functions
from makani.lib.python.h5_utils import numpy_utils
import numpy as np
import pandas as pd
import scoring_functions_util as scoring_util

_GROUND_STATION_MODE_HELPER = c_helpers.EnumHelper(
    'GroundStationMode', plc_messages)


class TetherElevationScoringFunction(
    scoring_functions.DoubleSidedLimitScoringFunction):
  """Tests the tether elevation."""

  def __init__(self, bad_lower_limit, good_lower_limit, good_upper_limit,
               bad_upper_limit, severity, transform_stages=None,
               sustained_duration=0.0, extra_system_labels=None):
    super(TetherElevationScoringFunction, self).__init__(
        ('Tether Elevation %s' % transform_stages if transform_stages
         else 'Tether Elevation'),
        'deg', bad_lower_limit, good_lower_limit,
        good_upper_limit, bad_upper_limit, severity)
    self._sustained_duration = sustained_duration
import os
import sys
import textwrap

import gflags
import makani
from makani.avionics.network import message_type
from makani.lib.python import c_helpers

gflags.DEFINE_string('h2py_dir', '.',
                     'Full path to H2PY_DIR containing pack modules.')
gflags.DEFINE_string('autogen_root', makani.HOME,
                     'Root of the source tree for the output files.')
FLAGS = gflags.FLAGS

message_type_helper = c_helpers.EnumHelper('MessageType', message_type)


def _GenStructName(message_type_name):
    short_name = message_type_helper.ShortName(message_type_name)
    if short_name in [
            'ControlTelemetry', 'ControlSlowTelemetry', 'SimTelemetry',
            'GroundTelemetry'
    ]:
        return short_name
    else:
        return short_name + 'Message'


def _GenPackFunctionName(message_type_name):
    return 'Pack' + _GenStructName(message_type_name)
Exemple #10
0
    def __init__(self, for_log, message_type, node, **base_kwargs):

        super(AioMonHumidityChecker, self).__init__(
            for_log, message_type, node, 'aio_mon.si7021_data[:].rel_humidity',
            'aio_mon.si7021_populated',
            c_helpers.EnumHelper('AioSi7021Monitor', aio_types), **base_kwargs)
Exemple #11
0
""""Monitor indicators from the ground station."""

from makani.avionics.firmware.monitors import mvlv_types
from makani.control import control_types
from makani.control import system_params
from makani.control import system_types
from makani.gs.monitor2.apps.layout import indicator
from makani.gs.monitor2.apps.layout import stoplights
from makani.gs.monitor2.apps.plugins import common
from makani.gs.monitor2.apps.plugins.indicators import avionics
from makani.gs.monitor2.apps.plugins.indicators import batt
from makani.lib.python import c_helpers
from makani.lib.python import struct_tree

FLIGHT_MODE_HELPER = c_helpers.EnumHelper('FlightMode', control_types)

MVLV_ANALOG_VOLTAGE_HELPER = c_helpers.EnumHelper('MvlvAnalogVoltage',
                                                  mvlv_types)

MVLV_MCP342X_MONITOR_HELPER = c_helpers.EnumHelper('MvlvMcp342xMonitor',
                                                   mvlv_types)

MVLV_MON_WARNING_HELPER = c_helpers.EnumHelper('MvlvMonitorWarning',
                                               mvlv_types)

MVLV_MON_ERROR_HELPER = c_helpers.EnumHelper('MvlvMonitorError', mvlv_types)

MVLV_MON_STATUS_HELPER = c_helpers.EnumHelper('MvlvMonitorStatus', mvlv_types)

_SYSTEM_PARAMS = system_params.GetSystemParams().contents
Exemple #12
0
    1.0 if flap_idx in [system_types.kFlapA4, system_types.kFlapA5] else 0.0
    for flap_idx in range(system_types.kNumFlaps)
]

_ELE_FLAP_BASIS = [
    1.0 if flap_idx == system_types.kFlapEle else 0.0
    for flap_idx in range(system_types.kNumFlaps)
]

_RUD_FLAP_BASIS = [
    1.0 if flap_idx == system_types.kFlapRud else 0.0
    for flap_idx in range(system_types.kNumFlaps)
]

_FLAP_LABEL_LIST = c_helpers.EnumHelper('FlapLabel',
                                        system_labels,
                                        prefix='kFlap').ShortNames()
_FLAP_LABELS = {i: _FLAP_LABEL_LIST[i] for i in range(len(_FLAP_LABEL_LIST))}


def GetFlapOffsetParameterRanges():
    return [
        # Assuming maximum 1 deg (0.02 rad) error in control surface angles for
        # Monte Carlo sweeps, ~3 deg (0.05 rad) variation in crosswind sweeps.
        parameter_tables.AeroSimFlapOffsetParameterRange(
            'Center Flap Offset [rad]',
            _CENTER_FLAP_BASIS, [-0.05, 0.05],
            distribution={
                'mean': 0.0,
                'sigma': 0.01,
                'bound': 2.0,
Exemple #13
0
This module looks for an 'mcp9800_config' tuple in the configuration file
(specified on command line). The mcp9800_config tuple should contain the
hardware revision EnumHelper and a dictionary that maps the board's hardware
revision to a list of dictionaries. Each dictionary in this list specifies
the configuration for each MCP9800 chip.
"""

import sys
import textwrap

from makani.avionics.firmware.drivers import mcp9800_types
from makani.avionics.firmware.monitors import generate_monitor_base
from makani.lib.python import c_helpers

resolution_helper = c_helpers.EnumHelper('Mcp9800Resolution', mcp9800_types)


class Mcp9800DeviceConfig(generate_monitor_base.DeviceConfigBase):
    """Generate MCP9800 monitor configuration."""

    # TODO: Add unit tests.

    def __init__(self, config):
        expected_parameters = {'name', 'address', 'resolution'}

        super(Mcp9800DeviceConfig, self).__init__(config, expected_parameters)

    def CheckParameterValues(self, config):
        """Verify the MCP9800 configuration."""
        name = config['name']
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import sys
import unittest

from makani.avionics.bootloader import bootloader_client
from makani.avionics.common import aio
from makani.avionics.firmware.identity import identity_types
from makani.avionics.network import aio_labels
from makani.avionics.network import aio_node
from makani.lib.python import c_helpers
import mock

hardware_type_helper = c_helpers.EnumHelper('HardwareType', identity_types)


class ParseArgumentsTest(unittest.TestCase):
    def RunParse(self, arg_string):
        argv = ['bootloader_client.py'] + arg_string.split()
        with mock.patch.object(sys, 'argv', argv):
            return bootloader_client.ParseArguments()

    def testBatt(self):
        parsed_args = self.RunParse('--target batt_a batt_application.elf')
        args = parsed_args['args']

        self.assertEqual(parsed_args['file'], 'batt_application.elf')
        self.assertEqual(args.force_hardware, None)
Exemple #15
0
from makani.analysis.aero import aero_ssam
from makani.analysis.aero import apparent_wind_util
from makani.analysis.log_analysis import loop_averager
from makani.control import system_types
from makani.lib.python import c_helpers
from makani.lib.python.batch_sim import scoring_functions
from makani.lib.python.h5_utils import numpy_utils
from makani.system import labels as system_labels

import numpy as np
from scipy import interpolate
import scoring_functions_util as scoring_util

_FLAP_LABEL_HELPER = c_helpers.EnumHelper('FlapLabel',
                                          system_labels,
                                          prefix='kFlap')
_WING_MODEL_HELPER = c_helpers.EnumHelper('WingModel', system_types)
_WING_SERIAL_HELPER = c_helpers.EnumHelper('WingSerial', system_types)


class AirspeedMaxScoringFunction(
        scoring_functions.SingleSidedLimitScoringFunction):
    """Tests if the airspeed falls outside of acceptable limits."""
    def __init__(self, good_limit, bad_limit, severity):
        super(AirspeedMaxScoringFunction,
              self).__init__('Max Airspeed', 'm/s', good_limit, bad_limit,
                             severity)

    def GetSystemLabels(self):
        return ['controls']
Exemple #16
0
    def _ReduceWorkerOutput(self, outputs):
        matplotlib.use('Agg')
        pylab = importlib.import_module('pylab')

        # Create directory to place output files.
        if not os.path.exists(FLAGS.output_dir):
            os.makedirs(FLAGS.output_dir)

        # Write a text report of extreme values experienced during flight.
        self._WriteReport(outputs)

        # pylint: disable=g-long-lambda
        outputs.sort(cmp=lambda x, y: cmp(x['parameters']['wind_speed'], y[
            'parameters']['wind_speed']))
        data_all = batch_sim_util.CollateOutputs(outputs)
        data = batch_sim_util.CollateOutputs([
            o for o in outputs if (o['parameters']['joystick_throttle'] ==
                                   FLAGS.joystick_throttles[0])
        ])
        stats_all = data_all['statistics']
        stats = data['statistics']
        wind_speeds_all = data_all['parameters']['wind_speed']
        wind_speeds = data['parameters']['wind_speed']

        # Save power curve to HDF5 file.
        #
        # TODO: Make a Python dictionary to HDF5 conversion
        # function.
        data_file = h5py.File(os.path.join(FLAGS.output_dir, 'data.h5'), 'w')
        data_file.create_dataset('wind_speed', data=wind_speeds)
        data_file.create_dataset('crosswind_power',
                                 data=stats['crosswind_power']['mean'][:])
        data_file.create_dataset('sim_success', data=data['sim_success'])

        flap_labels = [
            'Port aileron (outer)', 'Port aileron (inner)',
            'Center flap (port)', 'Center flap (starboard)',
            'Starboard aileron (inner)', 'Starboard aileron (outer)',
            'Elevator', 'Rudder'
        ]

        subsystem_helper = c_helpers.EnumHelper('SubsystemLabel',
                                                control_types,
                                                prefix='kSubsys')

        # Plot mean flap deflections.
        pylab.figure().patch.set_alpha(0.0)
        for flap_num in [0, 2, 4, 6, 7]:
            pylab.plot(wind_speeds,
                       stats['flaps'][flap_num]['mean'],
                       label=flap_labels[flap_num])
        pylab.axhline(0, color='black')
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        pylab.ylim([-0.6, 0.1])
        pylab.title('Mean flap deflections')
        pylab.xlabel('Wind speed [m/s]')
        pylab.ylabel('Deflection [rad]')
        pylab.legend(framealpha=0.5)
        pylab.grid()
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.savefig(FLAGS.output_dir + '/mean_flap_deflections.svg')
        pylab.close()

        # Plot standard deviation flap deflections.
        pylab.figure().patch.set_alpha(0.0)
        for flap_num in [0, 2, 4, 6, 7]:
            pylab.plot(wind_speeds,
                       stats['flaps'][flap_num]['std'],
                       label=flap_labels[flap_num])
        pylab.axhline(0, color='black')
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        pylab.ylim([-0.0, 0.2])
        pylab.title('Standard deviation flap deflections')
        pylab.xlabel('Wind speed [m/s]')
        pylab.ylabel('Deflection [rad]')
        pylab.legend(framealpha=0.5)
        pylab.grid()
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.savefig(FLAGS.output_dir +
                      '/standard_deviation_flap_deflections.svg')
        pylab.close()

        # Plot controller faults.
        pylab.figure().patch.set_alpha(0.0)
        num_subsystems = numpy.shape(data['faults'])[0]
        # The values in data['faults'] are bitfields (see the FaultType
        # enum).  Here we want just a faults / no faults indication.
        pylab.imshow(numpy.array(data['faults']) != 0,
                     extent=[
                         numpy.min(wind_speeds),
                         numpy.max(wind_speeds), 0, num_subsystems
                     ],
                     origin='lower',
                     interpolation='none',
                     cmap=pylab.get_cmap('RdYlGn_r'),
                     aspect=0.3)
        pylab.title('Controller faults')
        pylab.xlabel('Wind speed [m/s]')
        pylab.gca().set_yticks(
            numpy.linspace(0.5, num_subsystems - 0.5, num_subsystems))
        pylab.gca().set_yticklabels(
            [subsystem_helper.ShortName(i) for i in range(num_subsystems)],
            fontsize=8)
        pylab.savefig(FLAGS.output_dir + '/faults_vs_wind_speed.png')
        pylab.close()

        # Plot power curves by throttle position.
        pylab.figure().patch.set_alpha(0.0)
        throttles_all = data_all['parameters']['joystick_throttle']
        throttle_list = sorted(set(throttles_all))
        for throttle in throttle_list:
            pylab.plot(
                wind_speeds_all[throttles_all == throttle],
                stats_all['crosswind_power']['mean'][throttles_all == throttle]
                / 1e3,
                label='%0.2f' % throttle)
        # Reset the color cycle so we get the same colors for tension.
        pylab.gca().set_color_cycle(None)
        for throttle in throttle_list:
            pylab.plot(wind_speeds_all[throttles_all == throttle],
                       stats_all['tension']['max'][throttles_all == throttle] /
                       1e3,
                       linestyle='--')
        self._ShadeFailureRegions(pylab, wind_speeds_all,
                                  data_all['sim_success'])
        pylab.axhline(0, color='black')
        pylab.xlim([min(wind_speeds_all), max(wind_speeds_all)])
        pylab.title('Power curve by throttle position')
        pylab.xlabel('Wind speed [m/s]')
        pylab.ylabel('Aerodynamic power [kW] / Tension [kN]')
        pylab.legend(title='Throttle position', loc=2)
        pylab.grid()
        pylab.savefig(FLAGS.output_dir + '/power_curve_by_throttle.svg')
        pylab.close()

        # Plot power and tension curves.
        pylab.figure().patch.set_alpha(0.0)
        pylab.subplot(2, 1, 1)
        pylab.plot(annotations['power_curve']['v_wind'],
                   annotations['power_curve']['P'] / 1e3,
                   color='gray',
                   linestyle='-',
                   linewidth=4,
                   alpha=0.6)
        pylab.plot(wind_speeds,
                   stats['crosswind_power']['mean'] / 1e3,
                   label='Aerodynamic power')
        pylab.fill_between(wind_speeds,
                           stats['crosswind_power']['min'] / 1e3,
                           stats['crosswind_power']['max'] / 1e3,
                           color='blue',
                           alpha=0.3)
        pylab.fill_between(wind_speeds,
                           (stats['crosswind_power']['mean'] -
                            stats['crosswind_power']['std']) / 1e3,
                           (stats['crosswind_power']['mean'] +
                            stats['crosswind_power']['std']) / 1e3,
                           color='blue',
                           alpha=0.3)
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.axhline(0, color='black')
        pylab.title('Power and tension curves')
        pylab.ylabel('Aerodynamic power [kW]')
        pylab.grid()
        # Annotate plot with the date and time of creation, and git commit hash.
        datestr = datetime.datetime.now().strftime('%Y-%m-%d %H:%M %Z')
        git_commit = outputs[0]['git_commit'] if 'git_commit' in outputs[
            0] else ''
        pylab.text(0.05,
                   0.8,
                   '%s %s' % (datestr, git_commit[0:7]),
                   transform=pylab.gca().transAxes,
                   fontdict={
                       'size': 16,
                       'color': 'grey'
                   })
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        pylab.ylim([
            -1.0 * annotations['P_max'] / 1e3, 1.5 * annotations['P_max'] / 1e3
        ])

        pylab.subplot(2, 1, 2)
        pylab.plot(wind_speeds,
                   stats['tension']['max'] / 1e3,
                   color='green',
                   label='Tension')
        pylab.plot(wind_speeds,
                   stats['tension']['mean'] / 1e3,
                   color='green',
                   linestyle=':',
                   label='Tension')
        pylab.fill_between(wind_speeds,
                           stats['tension']['min'] / 1e3,
                           stats['tension']['max'] / 1e3,
                           color='green',
                           alpha=0.3)
        pylab.fill_between(
            wind_speeds,
            (stats['tension']['mean'] - stats['tension']['std']) / 1e3,
            (stats['tension']['mean'] + stats['tension']['std']) / 1e3,
            color='green',
            alpha=0.3)
        pylab.axhline(y=annotations['T_max'] / 1e3,
                      color='gray',
                      linestyle='--',
                      label='Max Tension',
                      linewidth=2)
        pylab.axhline(y=annotations['T_NE'] / 1e3,
                      color='gray',
                      linestyle='-',
                      label='Tension NE',
                      linewidth=2)
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.axhline(0, color='black')
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        pylab.ylim([0.0, 1.2 * annotations['T_max'] / 1e3])
        pylab.xlabel('Wind speed [m/s]')
        pylab.ylabel('Tension [kN]')
        pylab.grid()
        pylab.savefig(FLAGS.output_dir + '/power_and_tension_curve.svg')
        pylab.close()

        # Plot angles.
        pylab.figure().patch.set_alpha(0.0)
        pylab.subplot(3, 1, 1)
        pylab.plot(wind_speeds, stats['tether_roll']['mean'], color='blue')
        pylab.fill_between(wind_speeds,
                           stats['tether_roll']['min'],
                           stats['tether_roll']['max'],
                           color='blue',
                           alpha=0.3)
        pylab.fill_between(
            wind_speeds,
            stats['tether_roll']['mean'] - stats['tether_roll']['std'],
            stats['tether_roll']['mean'] + stats['tether_roll']['std'],
            color='blue',
            alpha=0.3)
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.axhline(0, color='black')
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        pylab.ylim([-0.2, 0.4])
        pylab.title('Angles')
        pylab.ylabel('Tether roll [rad]')
        pylab.grid()
        pylab.subplot(3, 1, 2)
        pylab.plot(wind_speeds, stats['alpha']['mean'], color='green')
        pylab.fill_between(wind_speeds,
                           stats['alpha']['min'],
                           stats['alpha']['max'],
                           color='green',
                           alpha=0.3)
        pylab.fill_between(wind_speeds,
                           stats['alpha']['mean'] - stats['alpha']['std'],
                           stats['alpha']['mean'] + stats['alpha']['std'],
                           color='green',
                           alpha=0.3)
        pylab.axhline(0, color='black')
        pylab.ylabel('Angle-of-attack [rad]')
        pylab.grid()
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        pylab.ylim([-0.15, 0.15])
        pylab.subplot(3, 1, 3)
        pylab.plot(wind_speeds, stats['beta']['mean'], color='red')
        pylab.fill_between(wind_speeds,
                           stats['beta']['min'],
                           stats['beta']['max'],
                           color='red',
                           alpha=0.3)
        pylab.fill_between(wind_speeds,
                           stats['beta']['mean'] - stats['beta']['std'],
                           stats['beta']['mean'] + stats['beta']['std'],
                           color='red',
                           alpha=0.3)
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.axhline(0, color='black')
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        pylab.ylim([-0.15, 0.15])
        pylab.xlabel('Wind speed [m/s]')
        pylab.ylabel('Sideslip [rad]')
        pylab.grid()
        pylab.savefig(FLAGS.output_dir + '/angles_vs_wind_speed.svg')
        pylab.close()

        # Plot angle errors.
        pylab.figure().patch.set_alpha(0.0)
        pylab.subplot(3, 1, 1)
        pylab.plot(wind_speeds,
                   stats['tether_roll_error']['mean'],
                   color='blue')
        pylab.fill_between(wind_speeds,
                           stats['tether_roll_error']['min'],
                           stats['tether_roll_error']['max'],
                           color='blue',
                           alpha=0.3)
        pylab.fill_between(wind_speeds,
                           stats['tether_roll_error']['mean'] -
                           stats['tether_roll_error']['std'],
                           stats['tether_roll_error']['mean'] +
                           stats['tether_roll_error']['std'],
                           color='blue',
                           alpha=0.3)
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.axhline(0, color='black')
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        pylab.ylim([-0.3, 0.3])
        pylab.title('Angle errors')
        pylab.ylabel('Tether roll\nerror [rad]')
        pylab.grid()
        pylab.subplot(3, 1, 2)
        pylab.plot(wind_speeds, stats['alpha_error']['mean'], color='green')
        pylab.fill_between(wind_speeds,
                           stats['alpha_error']['min'],
                           stats['alpha_error']['max'],
                           color='green',
                           alpha=0.3)
        pylab.fill_between(
            wind_speeds,
            stats['alpha_error']['mean'] - stats['alpha_error']['std'],
            stats['alpha_error']['mean'] + stats['alpha_error']['std'],
            color='green',
            alpha=0.3)
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.axhline(0, color='black')
        pylab.ylabel('Angle-of-attack\nerror [rad]')
        pylab.grid()
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        pylab.ylim([-0.15, 0.15])
        pylab.subplot(3, 1, 3)
        pylab.plot(wind_speeds, stats['beta_error']['mean'], color='red')
        pylab.fill_between(wind_speeds,
                           stats['beta_error']['min'],
                           stats['beta_error']['max'],
                           color='red',
                           alpha=0.3)
        pylab.fill_between(
            wind_speeds,
            stats['beta_error']['mean'] - stats['beta_error']['std'],
            stats['beta_error']['mean'] + stats['beta_error']['std'],
            color='red',
            alpha=0.3)
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.axhline(0, color='black')
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        pylab.ylim([-0.15, 0.15])
        pylab.xlabel('Wind speed [m/s]')
        pylab.ylabel('Sideslip\nerror [rad]')
        pylab.grid()
        pylab.savefig(FLAGS.output_dir + '/angle_errors_vs_wind_speed.svg')
        pylab.close()

        # Plot radius versus wind speed.
        pylab.figure().patch.set_alpha(0.0)
        pylab.plot(wind_speeds, stats['radius']['mean'], color='blue')
        pylab.fill_between(wind_speeds,
                           stats['radius']['min'],
                           stats['radius']['max'],
                           color='blue',
                           alpha=0.3)
        pylab.fill_between(wind_speeds,
                           stats['radius']['mean'] - stats['radius']['std'],
                           stats['radius']['mean'] + stats['radius']['std'],
                           color='blue',
                           alpha=0.3)
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        radius_round_50 = 50.0 * round(
            numpy.median(stats['radius']['mean']) / 50.0)
        pylab.ylim([radius_round_50 - 25.0, radius_round_50 + 25.0])
        pylab.title('Radius')
        pylab.xlabel('Wind speed [m/s]')
        pylab.ylabel('Radius [m]')
        pylab.grid()
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.savefig(FLAGS.output_dir + '/radius_vs_wind_speed.svg')
        pylab.close()

        # Plot curvature errors.
        pylab.figure().patch.set_alpha(0.0)
        pylab.subplot(2, 1, 1)
        pylab.plot(wind_speeds,
                   stats['geom_curvature_error']['mean'],
                   color='blue')
        pylab.fill_between(wind_speeds,
                           stats['geom_curvature_error']['min'],
                           stats['geom_curvature_error']['max'],
                           color='blue',
                           alpha=0.3)
        pylab.fill_between(wind_speeds,
                           stats['geom_curvature_error']['mean'] -
                           stats['geom_curvature_error']['std'],
                           stats['geom_curvature_error']['mean'] +
                           stats['geom_curvature_error']['std'],
                           color='blue',
                           alpha=0.3)
        pylab.axhline(0, color='black')
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        pylab.ylim([-0.01, 0.01])
        pylab.title('Curvature errors')
        pylab.ylabel('Geometric curvature\nerror [1/m]')
        pylab.grid()
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.subplot(2, 1, 2)
        pylab.plot(wind_speeds,
                   stats['aero_curvature_error']['mean'],
                   color='green')
        pylab.fill_between(wind_speeds,
                           stats['aero_curvature_error']['min'],
                           stats['aero_curvature_error']['max'],
                           color='green',
                           alpha=0.3)
        pylab.fill_between(wind_speeds,
                           stats['aero_curvature_error']['mean'] -
                           stats['aero_curvature_error']['std'],
                           stats['aero_curvature_error']['mean'] +
                           stats['aero_curvature_error']['std'],
                           color='green',
                           alpha=0.3)
        pylab.axhline(0, color='black')
        pylab.xlim([min(wind_speeds), max(wind_speeds)])
        pylab.ylim([-0.01, 0.01])
        pylab.xlabel('Wind speed [m/s]')
        pylab.ylabel('Aerodynamic curvature\nerror [1/m]')
        pylab.grid()
        self._ShadeFailureRegions(pylab, wind_speeds, data['sim_success'])
        pylab.savefig(FLAGS.output_dir + '/curvature_errors_vs_wind_speed.svg')
        pylab.close()

        pylab.figure().patch.set_alpha(0.0)
        for success_val, plot_style in [(True, 'g+'), (False, 'rs')]:
            pylab.plot([
                output['parameters']['wind_speed']
                for output in outputs if output['sim_success'] == success_val
            ], [
                output['parameters']['joystick_throttle']
                for output in outputs if output['sim_success'] == success_val
            ], plot_style)
        pylab.xlabel('Wind speed [m/s]')
        pylab.ylabel('Joystick throttle')
        pylab.ylim([0.0, 1.1])
        pylab.legend(['successful simulations', 'crashed simulations'],
                     loc='lower right')
        pylab.savefig(FLAGS.output_dir + '/sim_success_param_space.svg')

        # Copy HTML file that displays the charts to the output directory.
        dashboard_file = os.path.join(
            makani.HOME, 'analysis/power_curve/power_curve_dashboard.html')
        final_output_file = os.path.join(FLAGS.output_dir, 'index.html')
        shutil.copyfile(dashboard_file, final_output_file)
        logging.info('Output may be viewed at file://%s.',
                     os.path.abspath(final_output_file))
Exemple #17
0
# limitations under the License.
"""Command line client for controlling anti-collision lights."""

import os
import re
import socket

import makani
from makani.avionics.common import aio
from makani.avionics.common import cmd_client
from makani.avionics.common import pack_avionics_messages
from makani.avionics.network import aio_node
from makani.avionics.network import message_type
from makani.lib.python import c_helpers

aio_node_helper = c_helpers.EnumHelper('AioNode', aio_node)


def BuildLightParamDict():
    """Builds a dict mapping light param names to their indices."""
    # Build up parameter list.
    filename = os.path.join(makani.HOME,
                            'avionics/firmware/drivers/faa_light.c')
    with open(filename) as f:
        f_text = f.read()

    # Get parameter array string.
    re_string = r'static float \*g_mutable_param_addrs\[\] = {\s*^([\s\S]*)^};'
    array_string = re.search(re_string, f_text, re.MULTILINE)

    re_string = r'^ *&[\w.]+\[kLightType([\w\[\]\.]+)'
Exemple #18
0
 def testBadLength(self):
   bad_enum = FULL_ENUM.copy()
   bad_enum['kNumTestEnums'] = len(ENUM_VALUES) + 1
   module = FakeModule(bad_enum)
   with self.assertRaises(AssertionError):
     c_helpers.EnumHelper('TestEnum', module)
Exemple #19
0
from makani.control import sensor_util
from makani.control import system_params
from makani.gs.monitor import monitor_params
from makani.gs.monitor2.apps.layout import checks
from makani.gs.monitor2.apps.layout import indicator
from makani.gs.monitor2.apps.layout import stoplights
from makani.gs.monitor2.apps.layout import widgets
from makani.gs.monitor2.apps.plugins import common
from makani.gs.monitor2.project import settings
from makani.lib.python import c_helpers
from makani.lib.python import ctype_util
from makani.lib.python import struct_tree
import numpy as np


_AIO_SI7021_HELPER = c_helpers.EnumHelper('AioSi7021Monitor', aio_types)
_SERVO_LABEL_HELPER = c_helpers.EnumHelper('ServoLabel', aio_labels,
                                           prefix='kServo')
_CS_LABEL_HELPER = c_helpers.EnumHelper('CoreSwitchLabel', aio_labels,
                                        prefix='kCoreSwitch')
_CS_SI7021_HELPER = c_helpers.EnumHelper('CsSi7021Monitor', cs_types)
_FLIGHT_COMPUTER_HELPER = c_helpers.EnumHelper('FlightComputer', aio_labels)
_BRIDLE_JUNC_WARNING_HELPER = c_helpers.EnumHelper('BridleJuncWarning',
                                                   loadcell_types)
_MOTOR_LABELS_HELPER = c_helpers.EnumHelper('MotorLabel', aio_labels,
                                            prefix='kMotor')
_PITOT_COVER_STATUS_HELPER = c_helpers.EnumHelper('PitotCoverStatus',
                                                  pitot_cover_types)
_MONITOR_PARAMS = monitor_params.GetMonitorParams().contents
_SYSTEM_PARAMS = system_params.GetSystemParams().contents
Exemple #20
0
from makani.avionics.network import aio_labels
from makani.avionics.network import aio_node
from makani.avionics.network import message_type as aio_message_type
from makani.control import control_types
from makani.control import system_params
from makani.gs.monitor import monitor_params
from makani.gs.monitor2.apps.layout import stoplights
from makani.gs.monitor2.apps.plugins import common
from makani.gs.monitor2.apps.plugins.indicators import control
from makani.gs.monitor2.apps.receiver import test_util
from makani.gs.monitor2.high_frequency_filters import filter_handlers
from makani.lib.python import c_helpers
from makani.lib.python import struct_tree
import mock

AIO_NODE_HELPER = c_helpers.EnumHelper('AioNode', aio_node)
MESSAGE_TYPE_HELPER = c_helpers.EnumHelper('MessageType', aio_message_type)
MONITOR_PARAMS = monitor_params.GetMonitorParams().contents


class TestIndicators(unittest.TestCase):
    @classmethod
    def setUp(cls):
        aio_util.InitFilters()

    def _SynthesizeControlTelemetry(self, sequence=0):
        return test_util.SynthesizeMessages(
            ['ControlTelemetry', 'ControlSlowTelemetry'], sequence)

    def _MockMessage(self,
                     message,
Exemple #21
0
# See the License for the specific language governing permissions and
# limitations under the License.
"""Indicators for GPS."""

from makani.analysis.checks.collection import gps_checks
from makani.avionics.common import novatel_types
from makani.avionics.common import pack_avionics_messages
from makani.avionics.common import septentrio_types
from makani.gs.monitor2.apps.layout import indicator
from makani.gs.monitor2.apps.layout import stoplights
from makani.gs.monitor2.apps.plugins import common
from makani.lib.python import c_helpers
from makani.system import labels
import numpy

NOVATEL_SOLUTION_STATUS_HELPER = c_helpers.EnumHelper('NovAtelSolutionStatus',
                                                      novatel_types)
NOVATEL_SOLUTION_TYPE_HELPER = c_helpers.EnumHelper('NovAtelSolutionType',
                                                    novatel_types)
SEPTENTRIO_ERROR_HELPER = c_helpers.EnumHelper('SeptentrioPvtError',
                                               septentrio_types)
SEPTENTRIO_MODE_HELPER = c_helpers.EnumHelper('SeptentrioPvtMode',
                                              septentrio_types)

SEPTENTRIO_MODE_BITMASK = c_helpers.EnumHelper(
    'SeptentrioPvtModeBit', septentrio_types).Value('SolutionMask')

TETHER_GPS_SOLUTION_STATUS_HELPER = c_helpers.EnumHelper(
    'TetherGpsSolutionStatus', pack_avionics_messages)

WING_GPS_RECEIVER_HELPER = c_helpers.EnumHelper('WingGpsReceiver', labels)
Exemple #22
0
def GetParams(wing_model, wing_serial, use_wake_model=True):
    """Returns the set of parameters used for the model.

  Args:
    wing_model: Wing model (e.g. 'm600').
    wing_serial: String giving the desired wing serial number (e.g. '01').
    use_wake_model: Boolean flag that determines whether the advected
        rotor wake is included in the calculation of the local
        apparent wind.

  Returns:
    Parameter structure for the hover model.
  """
    wing_config_name = wing_flag.WingModelToConfigName(wing_model)

    if wing_config_name == 'oktoberkite':
        wing_serial_helper = c_helpers.EnumHelper('WingSerialOktoberKite',
                                                  system_types)
        db_name = 'avl/oktoberkite.avl'
    elif wing_config_name == 'm600':
        wing_serial_helper = c_helpers.EnumHelper('WingSerial', system_types)
        db_name = 'avl/m600_low_tail_no_winglets.avl'
    else:
        assert False, 'Wing model, %s, is not recognized.' % wing_config_name

    mconfig.WING_MODEL = wing_config_name
    system_params = mconfig.MakeParams(
        wing_config_name + '.system_params',
        overrides={'wing_serial': wing_serial_helper.Value(wing_serial)},
        override_method='derived')

    # Thrust level is necessary for the propeller wake model.  It is
    # determined by assuming the kite is supporting the full weight of
    # the tether and has to balance the pitching moment about the
    # C.G. with differential thrust between the top and bottom motor
    # rows:
    #
    #   4.0 * thrust_top + 4.0 * thrust_bot = weight
    #   z_top * thrust_top + z_bot * thrust_bot = 0.0
    total_mass = (system_params['wing']['m'] +
                  (system_params['tether']['linear_density'] *
                   system_params['tether']['length']))
    weight = system_params['phys']['g'] * total_mass

    main_wing_incidence_deg = system_params['wing']['wing_i']

    rotor_pos_z = [
        rotor['pos'][2] - system_params['wing']['center_of_mass_pos'][2]
        for rotor in system_params['rotors']
    ]

    z_bot = np.mean([z for z in rotor_pos_z if z > 0.0])
    z_top = np.mean([z for z in rotor_pos_z if z < 0.0])
    thrust_bot = weight / (4.0 * (1.0 + (-z_bot / z_top)))
    thrust_top = thrust_bot * (-z_bot / z_top)

    rotors = [{
        'pos': rotor['pos'],
        'radius': rotor['D'] / 2.0,
        'thrust': thrust_bot if rotor['pos'][2] > 0.0 else thrust_top
    } for rotor in system_params['rotors']]

    # It is assumed that all rotors have the same pitch angle.
    rotor_pitches = [
        np.arctan2(-rotor['axis'][2], rotor['axis'][0])
        for rotor in system_params['rotors']
    ]
    assert np.all(rotor_pitches == rotor_pitches[0])

    aero_home = os.path.join(makani.HOME, 'analysis/aero/')

    wing = avl_reader.AvlReader(os.path.join(aero_home, db_name))

    # TODO: Extract airfoil information from avl_reader.py.
    if wing_config_name == 'm600':
        # The maximum value of 16.0 degrees for the M600 is because of the airfoil
        # hysteresis going from attached flow to detached flow, which occures during
        # HoverAccel.
        stall_angles_deg = [1.0, 16.0]
    elif wing_config_name == 'oktoberkite':
        # (b/146071300) Currently, there is no understanding of the hysteresis
        # curve. This needs to be understood and modified once available.
        # (b/146061441) Additional ramifications for this choice.
        stall_angles_deg = [1.0, 20.0]
    else:
        assert False, 'Unknown wing model.'

    # (b/146081917) Oktoberkite will utilize the same airfoils as the M600.
    outer_wing_airfoil = airfoil.Airfoil(os.path.join(
        aero_home, 'hover_model/airfoils/oref.json'),
                                         stall_angles_deg=stall_angles_deg)
    inner_wing_airfoil = airfoil.Airfoil(os.path.join(
        aero_home, 'hover_model/airfoils/ref.json'),
                                         stall_angles_deg=stall_angles_deg)
    pylon_airfoil = airfoil.Airfoil(os.path.join(
        aero_home, 'hover_model/airfoils/mp6d.json'),
                                    stall_angles_deg=[-10.0, 10.0])

    airfoils = {
        'Wing (panel 0)':
        outer_wing_airfoil,
        'Wing (panel 1)':
        outer_wing_airfoil,
        'Wing (panel 2)':
        inner_wing_airfoil,
        'Wing (panel 3)':
        inner_wing_airfoil,
        'Wing (panel 4)':
        inner_wing_airfoil,
        'Wing (panel 5)':
        inner_wing_airfoil,
        'Wing (panel 6)':
        inner_wing_airfoil,
        'Wing (panel 7)':
        inner_wing_airfoil,
        'Wing (panel 8)':
        outer_wing_airfoil,
        'Wing (panel 9)':
        outer_wing_airfoil,
        'Pylon 1':
        pylon_airfoil,
        'Pylon 2':
        pylon_airfoil,
        'Pylon 3':
        pylon_airfoil,
        'Pylon 4':
        pylon_airfoil,
        'Horizontal tail':
        airfoil.Airfoil(os.path.join(aero_home,
                                     'hover_model/airfoils/f8.json'),
                        stall_angles_deg=[-10.0, 10.0]),
        'Vertical tail':
        airfoil.Airfoil(os.path.join(
            aero_home, 'hover_model/airfoils/approx_blade_rj8.json'),
                        stall_angles_deg=[-10.0, 10.0])
    }

    # TODO: Extract flap index information from
    # avl_reader.py.
    # The indices of the wing pannel indicate which flap number they are going to
    # be in the controller, i.e. "0" is A1 for the M600 and "7" is the rudder for
    # the M600. An index of -1 means that the panel has no flap section.
    if wing_config_name == 'm600':
        delta_indices = {
            'Wing (panel 0)': 0,
            'Wing (panel 1)': 1,
            'Wing (panel 2)': -1,
            'Wing (panel 3)': 2,
            'Wing (panel 4)': -1,
            'Wing (panel 5)': -1,
            'Wing (panel 6)': 3,
            'Wing (panel 7)': -1,
            'Wing (panel 8)': 4,
            'Wing (panel 9)': 5,
            'Pylon 1': -1,
            'Pylon 2': -1,
            'Pylon 3': -1,
            'Pylon 4': -1,
            'Horizontal tail': 6,
            'Vertical tail': 7
        }
    elif wing_config_name == 'oktoberkite':
        delta_indices = {
            'Wing (panel 0)': 0,
            'Wing (panel 1)': 1,
            'Wing (panel 2)': 2,
            'Wing (panel 3)': -1,
            'Wing (panel 4)': -1,
            'Wing (panel 5)': -1,
            'Wing (panel 6)': -1,
            'Wing (panel 7)': 3,
            'Wing (panel 8)': 4,
            'Wing (panel 9)': 5,
            'Pylon 1': -1,
            'Pylon 2': -1,
            'Pylon 3': -1,
            'Pylon 4': -1,
            'Horizontal tail': 6,
            'Vertical tail': 7
        }

    # TODO: Modify the hover model to accept the
    # avl_reader.py surface dictionary directly.
    hover_model_panels = []
    for surface in wing.properties['surfaces']:
        if surface['name'] in ('Horizontal tail', 'Vertical tail', 'Pylon 1',
                               'Pylon 2', 'Pylon 3', 'Pylon 4'):
            hover_model_panels.append({
                'name':
                surface['name'],
                'area':
                surface['area'],
                'span':
                surface['span'],
                'surface_span':
                surface['span'],
                'chord':
                surface['standard_mean_chord'],
                'aspect_ratio':
                surface['span']**2.0 / surface['area'],
                # The 2.0 is a fudge factor to match the C_Y slope from AVL.
                'cl_weight':
                2.0 if surface['name'][0:5] == 'Pylon' else 1.0,
                'pos_b':
                surface['aerodynamic_center_b'],
                'airfoil':
                airfoils[surface['name']],
                'incidence':
                surface['mean_incidence'],
                # These surfaces are single panel. So there is no relative incidence.
                'relative_incidence':
                0.0,
                'dcm_b2s':
                surface['dcm_b2surface'],
                'delta_index':
                delta_indices[surface['name']]
            })
        elif surface['name'] == 'Wing':
            for i, panel in enumerate(surface['panels']):
                panel_name = surface['name'] + ' (panel %d)' % i
                hover_model_panels.append({
                    'name':
                    panel_name,
                    'area':
                    panel['area'],
                    'span':
                    panel['span'],
                    'surface_span':
                    surface['span'],
                    'chord':
                    panel['standard_mean_chord'],
                    'aspect_ratio':
                    surface['span']**2.0 / surface['area'],
                    'cl_weight':
                    (surface['mean_incidence'] *
                     surface['standard_mean_chord'] /
                     (panel['mean_incidence'] * panel['standard_mean_chord'])),
                    'pos_b':
                    panel['aerodynamic_center_b'],
                    'airfoil':
                    airfoils[panel_name],
                    'incidence':
                    panel['mean_incidence'],
                    'relative_incidence':
                    (panel['mean_incidence'] -
                     np.deg2rad(main_wing_incidence_deg)),
                    'dcm_b2s':
                    surface['dcm_b2surface'],
                    'delta_index':
                    delta_indices[panel_name]
                })
        else:
            assert False

    # Check that we aren't missing any panels.
    assert (len(hover_model_panels) == len(delta_indices)
            and len(hover_model_panels) == len(airfoils))

    return {
        'wing_serial': wing_serial,
        'git_commit': build_info.GetGitSha(),
        'use_wake_model': use_wake_model,
        'rotors': rotors,
        'rotor_pitch': rotor_pitches[0],
        'phys': {
            'rho': 1.1,
            'dynamic_viscosity': 1.789e-5
        },
        'wing': {
            'area': system_params['wing']['A'],
            'b': system_params['wing']['b'],
            'c': system_params['wing']['c'],
            'wing_i': system_params['wing']['wing_i']
        },
        'center_of_mass_pos': system_params['wing']['center_of_mass_pos'],
        'panels': hover_model_panels
    }
Exemple #23
0
# limitations under the License.
"""Indicators for network status."""

import collections

from makani.analysis.checks import check_range
from makani.avionics.common import cvt
from makani.avionics.network import aio_node
from makani.control import system_params
from makani.control import system_types
from makani.gs.monitor2.apps.layout import indicator
from makani.gs.monitor2.apps.layout import stoplights
from makani.gs.monitor2.apps.plugins import common
from makani.lib.python import c_helpers

_TETHER_NODE_FLAGS_HELPER = c_helpers.EnumHelper('TetherNodeFlag', cvt)
_AIO_NODE_HELPER = c_helpers.EnumHelper('AioNode', aio_node)
_SYSTEM_PARAMS = system_params.GetSystemParams().contents
_WING_TMS570_NODES = common.WingTms570Nodes()


class BaseTetherNodeStatusIndicator(indicator.BaseAttributeIndicator):
    """Base indicator class for individual node status."""
    def __init__(self, name, node_name):
        node_id = _AIO_NODE_HELPER.Value(node_name)
        super(BaseTetherNodeStatusIndicator, self).__init__([
            ('filtered', 'merge_tether_down', 'node_status[%d]' % node_id),
            ('filtered', 'merge_tether_down',
             'node_status_valid[%d]' % node_id),
        ], name)
Exemple #24
0
 def __init__(self, for_log, message_type, node, **base_kwargs):
     super(AioMonBusCurrentChecker, self).__init__(
         for_log, message_type, node, 'aio_mon.ina219_data[:].current',
         'aio_mon.ina219_populated',
         c_helpers.EnumHelper('AioIna219Monitor', aio_types), **base_kwargs)
Exemple #25
0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Classes to perform checks on servos."""

from makani.analysis.checks import base_check
from makani.analysis.checks.collection import avionics_checks
from makani.avionics.firmware.monitors import servo_types
from makani.avionics.network import aio_node
from makani.lib.python import c_helpers

_SERVO_LABELS_HELPER = c_helpers.EnumHelper('ServoLabel',
                                            aio_node,
                                            prefix='kAioNodeServo')
_SERVO_ANALOG_VOLTAGE_HELPER = c_helpers.EnumHelper('ServoAnalogVoltage',
                                                    servo_types)
_SERVO_MCP9800_MONITOR_HELPER = c_helpers.EnumHelper('ServoMcp9800',
                                                     servo_types)
_SERVO_MONITOR_ERROR_HELPER = c_helpers.EnumHelper('ServoMonitorError',
                                                   servo_types)
_SERVO_MONITOR_WARNING_HELPER = c_helpers.EnumHelper('ServoMonitorWarning',
                                                     servo_types)


class ServoMonAnalogChecker(avionics_checks.BaseVoltageChecker):
    """The monitor to check servo voltage."""
    @base_check.RegisterSpecs
    def __init__(self,
Exemple #26
0
 def setUp(self):
   module = FakeModule(FULL_ENUM)
   self.helper = c_helpers.EnumHelper('TestEnum', module)
This module looks for an 'ads7828_config' tuple in the configuration file
(specified on command line). The ads7828_config tuple should contain the
hardware revision EnumHelper and a dictionary that maps the board's hardware
revision to a list of dictionaries. Each dictionary in this list specifies
the configuration for each ADS7828 chip.
"""

import sys
import textwrap

from makani.avionics.firmware.drivers import ads7828_types
from makani.avionics.firmware.monitors import generate_monitor_base
from makani.lib.python import c_helpers

select_helper = c_helpers.EnumHelper('Ads7828Select', ads7828_types)
convert_helper = c_helpers.EnumHelper('Ads7828PowerConverter', ads7828_types)
ref_helper = c_helpers.EnumHelper('Ads7828PowerReference', ads7828_types)


class Ads7828DeviceConfig(generate_monitor_base.DeviceConfigBase):
    """Generate ADS7828 voltage/current monitor configuration."""

    # TODO: Add unit tests.

    def __init__(self, config):
        expected_parameters = {
            'name', 'address', 'channel', 'converter', 'reference',
            'input_divider', 'input_offset', 'nominal', 'min', 'max'
        }
Exemple #28
0
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Functions to write controller gains into output files."""

import json
import pprint

from makani.control import system_types
from makani.lib.python import c_helpers

_WING_SERIAL_HELPER = c_helpers.EnumHelper('WingSerial', system_types)


def WriteControllers(generating_file, filename, controllers):
    """Writes gain matrices to configuration file.

  Args:
    generating_file: File calling this function.
    filename: Full path to the gain matrix file to write.
    controllers: OrderedDict of airspeed values and gain matrices.
  """

    docstring = ('  """Returns control gain matrices'
                 'for any kite serial number."""')

    with open(filename, 'w') as f:
Exemple #29
0
import collections
import copy
import datetime
import logging
import threading

from makani.avionics.network import message_type as aio_message_type
from makani.gs.monitor2.apps.receiver import base_receiver
from makani.lib.python import c_helpers
from makani.lib.python import struct_tree
from makani.lib.python.trackers import json_obj
import numpy
import pytz

_MESSAGE_TYPE_HELPER = c_helpers.EnumHelper('MessageType', aio_message_type)


class LogMessage(json_obj.JsonObj):
    """A message reconstructed from the log."""
    def __init__(self, payload, timestamp, seq_num, version, msg_enum, source):
        self._payload = payload
        self._timestamp = timestamp
        self._sequence = seq_num
        self._version = version
        self._msg_enum = msg_enum
        self._source = source
        self._message = None

    def Get(self, readonly):
        """Obtain a JSON representation of the message.
Exemple #30
0
from makani.analysis.control import flap_limits
from makani.avionics.common import pack_avionics_messages
from makani.avionics.common import servo_types as servo_common
from makani.avionics.firmware.monitors import servo_types
from makani.avionics.network import aio_labels
from makani.control import control_types
from makani.gs.monitor2.apps.layout import indicator
from makani.gs.monitor2.apps.layout import stoplights
from makani.gs.monitor2.apps.plugins import common
from makani.gs.monitor2.apps.plugins.indicators import avionics
from makani.lib.python import c_helpers
from makani.lib.python import struct_tree

import numpy

_SERVO_WARNING_HELPER = c_helpers.EnumHelper('ServoWarning', servo_common)
_SERVO_ERROR_HELPER = c_helpers.EnumHelper('ServoError', servo_common)

_SERVO_STATUS_HELPER = c_helpers.EnumHelper('ServoStatus', servo_common)

_SERVO_LABELS_HELPER = c_helpers.EnumHelper('ServoLabel',
                                            aio_labels,
                                            prefix='kServo')

_SERVO_ANALOG_VOLTAGE_HELPER = c_helpers.EnumHelper('ServoAnalogVoltage',
                                                    servo_types)

_SERVO_MON_WARNING_HELPER = c_helpers.EnumHelper('ServoMonitorWarning',
                                                 servo_types)
_SERVO_MON_ERROR_HELPER = c_helpers.EnumHelper('ServoMonitorError',
                                               servo_types)