Ejemplo n.º 1
0
def load_chrono_sensor_from_json(system: 'WAChronoSystem', filename: str,
                                 **kwargs) -> 'WAChronoSensor':
    """Load a chrono sensor from json

    If the passed json file isn't a chrono type, it will call the correct method.

    Args:
        system (WAChronoSystem): The system for the simulation
        filename (str): The json specification file that describes the sensor

    Returns:
            WAChronoSensor: The created sensor
    """
    if missing_chrono_sensor:
        sens_import_error('load_chrono_sensor_from_json')

    # Check if the file can be found in the chrono portion of the data folder
    try:
        j = _load_json(filename)
    except FileNotFoundError:
        # File is not chrono specific, try that now
        j = _load_json(get_wa_data_file(filename))
        return load_sensor_from_json(system, filename, **kwargs)

    return WAChronoSensor(system, filename, **kwargs)
Ejemplo n.º 2
0
def create_path_from_json(filename: str) -> 'WAPath':
    """Creates a WAPath object from json

    json file options:

    * Waypoints Input File (str, required): A csv file describing the path waypoints. Loaded using :meth:`~load_waypoints_from_csv`.

    * Additional keyworded arguments necessary for the path template

    Args:
        filename (str): The json specification that describes the path
    """

    j = _load_json(filename)

    # Validate the json file
    _check_field(j, 'Type', value='Path')
    _check_field(j, 'Template', allowed_values=['WASplinePath'])
    _check_field(j, 'Waypoints Input File', field_type=str)

    # Grab the waypoints
    waypoints_file = get_wa_data_file(j['Waypoints Input File'])
    waypoints = load_waypoints_from_csv(waypoints_file, delimiter=",")

    excluded_keys = ['Type', 'Template', 'Waypoints Input File']
    kwargs = {x: j[x] for x in j if x not in excluded_keys}

    # Create the path
    path = eval(j['Template'])(waypoints, **kwargs)

    return path
Ejemplo n.º 3
0
def create_tire_from_json(tire_filename: str) -> veh.ChTire:
    """Creates a ChTire from a tire file

    .. info:
        Currently, only TMeasyTires and RigidTires are supported

    Args:
        tire_filename (str): the tire json specification file

    Returns:
        ChTire: the created tire

    Raises:
        TypeError: If the tire type is not recognized
    """
    j = _load_json(tire_filename)

    # Valide json file
    _check_field(j, "Type", value="Tire")
    _check_field(j,
                 "Template",
                 allowed_values=["TMeasyTire", "RigidTire", "Pac02Tire"])

    tire_type = j["Template"]
    if tire_type == "TMeasyTire":
        return veh.TMeasyTire(tire_filename)
    elif tire_type == "RigidTire":
        return veh.RigidTire(tire_filename)
    elif tire_type == "Pac02Tire":
        return veh.Pac02Tire(tire_filename)
    else:
        raise TypeError(f"'{tire_type} not a recognized tire type")
Ejemplo n.º 4
0
    def __init__(self,
                 system: 'WASystem',
                 filename: str,
                 vehicle: 'WAVehicle' = None,
                 body: 'WABody' = None):
        super().__init__(vehicle, body)

        if body is not None:
            raise NotImplementedError(
                "Setting 'body' is currently not supported. Please pass a vehicle instead"
            )

        self._vehicle = vehicle

        j = _load_json(filename)

        # Validate the json file
        _check_field(j, 'Type', value='Sensor')
        _check_field(j, 'Template', value='Wheel Encoder')
        _check_field(j, 'Properties', field_type=dict)

        p = j['Properties']
        _check_field(p, 'Update Rate', field_type=int)
        _check_field(p,
                     'Axle',
                     field_type=str,
                     allowed_values=['Front', 'Rear', 'Steering'])
        _check_field(p, 'Noise Model', field_type=dict, optional=True)

        if 'Noise Model' in p:
            _check_field(p['Noise Model'],
                         'Noise Type',
                         allowed_values=["Normal", "Normal Drift"])

        self._load_properties(p)
Ejemplo n.º 5
0
def read_vehicle_model_file(filename: str) -> tuple:
    """Read a json specification file to get additional file names to be loaded into ChVehicle classes

    Will find the vehicle, powertrain and tire input files. The input files are other json files that are
    readable by the Chrono simulator to be used to create bodies attached to the vehicle.

    Args:
        filename (str): the json specification file with Vehicle, Powertrain and Tire input models

    Returns:
        tuple: returns each json specification file for the vehicle, powertrain and tire
    """
    j = _load_json(filename)

    # Validate json file
    _check_field(j, "Vehicle", field_type=dict)
    _check_field(j, "Powertrain", field_type=dict)
    _check_field(j, "Tire", field_type=dict)

    _check_field(j["Vehicle"], "Input File", field_type=str)
    _check_field(j["Powertrain"], "Input File", field_type=str)
    _check_field(j["Tire"], "Input File", field_type=str)

    # Extract the actual files
    vehicle_filename = veh.GetDataFile(j["Vehicle"]["Input File"])
    powertrain_filename = veh.GetDataFile(j["Powertrain"]["Input File"])
    tire_filename = veh.GetDataFile(j["Tire"]["Input File"])

    return vehicle_filename, powertrain_filename, tire_filename
Ejemplo n.º 6
0
    def __init__(self,
                 system: 'WAChronoSystem',
                 filename: str,
                 vehicle: 'WAChronoVehicle' = None,
                 body: 'WABody' = None):
        if missing_chrono_sensor:
            sens_import_error('WAChronoSensor.__init__')

        super().__init__(vehicle, body)

        j = _load_json(filename)

        # Validate the json file
        _check_field(j, 'Type', value='Sensor')
        _check_field(j,
                     'Template',
                     allowed_values=['Camera', 'Lidar', 'IMU', 'GPS'])  # noqa
        _check_field(j, 'Offset Pose', field_type=dict)

        offset_pose = ChFrame_from_json(j['Offset Pose'])

        if vehicle is not None:
            body = vehicle._vehicle.GetChassisBody()
        else:
            asset = body
            body = chrono.ChBody()
            body.SetPos(WAVector_to_ChVector(asset.position))
            body.SetBodyFixed(True)
            system._system.AddBody(body)

            # Create the chrono sensor through the Sensor chrono class
        self._sensor = sens.Sensor.CreateFromJSON(filename, body,
                                                  offset_pose)  # noqa
Ejemplo n.º 7
0
def load_sensor_from_json(system: 'WASystem', filename: str,
                          **kwargs) -> 'WASensor':
    """Load a sensor from json

    Args:
        system (WASystem): The system for the simulation
        filename (str): The json specification file that describes the sensor
        kwargs: Keyworded arguments. Must contain a 'vehicle' or 'body', not both.

    Returns:
        WASensor: The created sensor
    """
    j = _load_json(filename)

    # Validate the json file
    _check_field(j, 'Type', value='Sensor')
    _check_field(j, 'Template', allowed_values=['IMU', 'GPS', 'Wheel Encoder'])

    # Check the template and create a sensor based off what it is
    if j['Template'] == 'IMU':
        sensor = WAIMUSensor(system, filename, **kwargs)
    elif j['Template'] == 'GPS':
        sensor = WAGPSSensor(system, filename, **kwargs)
    elif j['Template'] == 'Wheel Encoder':
        sensor = WAWheelEncoderSensor(system, filename, **kwargs)
    else:
        raise TypeError(f"{j['Template']} is not an implemented sensor type")

    return sensor
Ejemplo n.º 8
0
    def test_check_field_allowed_values(self):
        """Tests the check_field_allowed_values method"""
        j = utils._load_json(utils.get_wa_data_file('test/test.json'))

        try:
            utils._check_field_allowed_values(
                j, 'Name', ['Test GPS Sensor Model', 'Test', 'Type'])  # noqa
        except:
            self.fail("Raise exception unexpectedly!")

        with self.assertRaises(ValueError):
            utils._check_field_allowed_values(j, 'Name',
                                              ['Test', 'Type'])  # noqa
Ejemplo n.º 9
0
def load_environment_from_json(environment: 'WAEnvironment', filename: str):
    j = _load_json(filename)

    # Validate the json file
    _check_field(j, 'Type', value='Environment')
    _check_field(j, 'Template')
    _check_field(j, 'World', field_type=dict, optional=True)
    _check_field(j, 'Objects', field_type=list, optional=True)

    if 'World' in j:
        w = j['World']

    if 'Objects' in j:
        objects = j['Objects']

        for o in objects:
            _check_field(o, 'Size', field_type=list)
            _check_field(o, 'Position', field_type=list, optional=True)
            _check_field(o, 'Color', field_type=list, optional=True)

            kwargs = {}
            kwargs['size'] = WAVector(o['Size'])
            kwargs['position'] = WAVector(o['Position'])

            if 'Color' in o:
                kwargs['color'] = WAVector(o['Color'])

            if 'Texture' in o:
                kwargs['texture'] = o['Texture']

            if 'Name' in o:
                kwargs['name'] = o['Name']

            environment.add_asset(WABody(**kwargs))

    if 'Track' in j:
        t = j['Track']

        # Validate json
        _check_field(t, 'Track Input File', field_type=str)

        track_file = t['Track Input File']
        track = create_track_from_json(get_wa_data_file(track_file),
                                       environment)

        environment.add_asset(track.center)
Ejemplo n.º 10
0
    def test_load_json(self):
        """Tests the load_json method"""

        try:
            j = utils._load_json(utils.get_wa_data_file('test/test.json'))
        except:
            self.fail("Raise exception unexpectedly!")

        self.assertTrue('Name' in j)
        self.assertTrue('Type' in j)
        self.assertTrue('Template' in j)
        self.assertTrue('Properties' in j)

        self.assertTrue(j['Name'] == 'Test GPS Sensor Model')

        self.assertTrue('Update Rate' in j['Properties'])
        self.assertTrue(isinstance(j['Properties'], dict))
Ejemplo n.º 11
0
def load_chrono_sensor_scene_from_json(manager: "WAChronoSensorManager",
                                       filename: str):
    """Load a chrono sensor scene from a json specification file. A scene may consist of "World" attributes (i.e. lights) or sensors

    Args:
        manager (WASensorManager): The sensor manager to edit the scene of
        filename (str): The json specification file describing the scene
    """
    if missing_chrono_sensor:
        sens_import_error('load_chrono_sensor_scene_from_json')

    j = _load_json(filename)

    # Validate the json file
    _check_field(j, 'Type', value='Sensor')
    _check_field(j, 'Template', value='Chrono Sensor Scene')
    _check_field(j, 'World', field_type=dict, optional=True)
    _check_field(j, 'Sensors', field_type=list, optional=True)
    _check_field(j, 'Objects', field_type=list, optional=True)

    if 'World' in j:
        w = j['World']

        _check_field(w, 'Point Lights', field_type=list)

        # Create the point lights
        # NOTE: Might be optional in the future
        for p in w['Point Lights']:
            _check_field(p, 'Position', field_type=list)
            _check_field(p, 'Color', field_type=list)
            _check_field(p, 'Maximum Range', field_type=float)

            pos = ChVector_from_list(p['Position'], chrono.ChVectorF)
            color = ChVector_from_list(p['Color'], chrono.ChVectorF)
            max_range = p['Maximum Range']

            manager._manager.scene.AddPointLight(pos, color, max_range)

    if 'Sensors' in j:
        s = j['Sensors']

        for sensor in s:
            new_sensor = load_chrono_sensor_from_json(manager._system, sensor)
            manager.add_sensor(new_sensor)
Ejemplo n.º 12
0
def load_sensor_suite_from_json(manager: 'WASensorManager', filename: str):
    """Load a sensor suite from json

    Each loaded sensor will be added to the manager

    Args:
        manager (WASensorManager): The sensor manager to store all created objects in
        filename (str): The json specification file that describes the sensor suite
    """
    j = _load_json(filename)

    # Validate the json file
    _check_field(j, 'Type', value='Sensor')
    _check_field(j, 'Template', value='Sensor Suite')
    _check_field(j, 'Sensors', field_type=list)

    # Load the sensors
    for sensor in j['Sensors']:
        new_sensor = load_sensor_from_json(sensor, manager._system)
        manager.add_sensor(new_sensor)
Ejemplo n.º 13
0
def load_properties_from_json(filename: str, prop: str) -> dict:
    """Load a specified property from a json specification file

    Will load a json file and extract the passed property field for use
    by the underyling vehicle object

    Args:
        filename (str): the filename location within the set WA data folder for the json file
        property (str): the property to get. Ex: "Vehicle Properties"

    Raises:
        ValueError: The property field isn't found

    Returns:
        dict: the property field extracted from the json file
    """
    j = _load_json(filename)

    if prop not in j:
        raise ValueError(f"{prop} not found in json.")

    return j[prop]
Ejemplo n.º 14
0
    def __init__(self,
                 system: 'WASystem',
                 filename: str,
                 vehicle: 'WAVehicle' = None,
                 body: 'WABody' = None):
        super().__init__(vehicle, body)

        if body is not None:
            raise NotImplementedError(
                "Setting 'body' is currently not supported. Please pass a vehicle instead"
            )

        self._vehicle = vehicle
        self._pos_dtdt = None
        self._rot = None
        self._rot_dt = None

        j = _load_json(filename)

        # Validate the json file
        _check_field(j, 'Type', value='Sensor')
        _check_field(j, 'Template', value='IMU')
        _check_field(j, 'Properties', field_type=dict)

        p = j['Properties']
        _check_field(p, 'Update Rate', field_type=int)
        _check_field(p, 'Noise Model', field_type=dict, optional=True)

        if 'Noise Model' in p:
            _check_field(p['Noise Model'],
                         'Noise Type',
                         allowed_values=["Normal", "Normal Drift"])

        self._load_properties(p)

        self._acc = WAVector()
        self._omega = WAVector()
        self._orientation = WAVector()
Ejemplo n.º 15
0
def load_chrono_terrain_from_json(system: 'WAChronoSystem', filename: str):
    """Load a ChTerrain from a json specification file

    Args:
        filename (str): the relative path to a terrain json file
        system (WAChronoSystem): the chrono system used to handle the terrain

    Returns:
        ChTerrain: The loaded terrain
    """
    j = _load_json(filename)

    # Validate the json file
    _check_field(j, 'Terrain', field_type=dict)

    t = j['Terrain']
    _check_field(t, 'Input File', field_type=str)
    _check_field(t, 'Texture', field_type=str, optional=True)

    terrain = veh.RigidTerrain(system._system, chrono.GetChronoDataFile(t['Input File']))  # noqa

    # Add texture to the terrain, if desired
    if 'Texture' in t:
        texture_filename = chrono.GetChronoDataFile(t['Texture'])

        vis_mat = chrono.ChVisualMaterial()
        vis_mat.SetKdTexture(texture_filename)
        vis_mat.SetSpecularColor(chrono.ChVectorF(0.0, 0.0, 0.0))
        vis_mat.SetFresnelMin(0)
        vis_mat.SetFresnelMax(0.1)

        patch_asset = terrain.GetPatches()[0].GetGroundBody().GetAssets()[0]
        patch_visual_asset = chrono.CastToChVisualization(patch_asset)
        patch_visual_asset.material_list.append(vis_mat)

    return terrain
Ejemplo n.º 16
0
    def test_check_field(self):
        """Tests the check_field method"""
        j = utils._load_json(utils.get_wa_data_file('test/test.json'))

        try:
            utils._check_field(j, 'Name')
            utils._check_field(j, 'Test', optional=True)
            utils._check_field(j, 'Template', value='GPS')
            utils._check_field(j, 'Properties', field_type=dict)
            utils._check_field(j['Properties']['Noise Model'],
                               'Noise Type',
                               field_type=str,
                               allowed_values=['Normal', 'Test'])
        except:
            self.fail("Raise exception unexpectedly!")

        with self.assertRaises(KeyError):
            utils._check_field(j, "Test")
        with self.assertRaises(TypeError):
            utils._check_field(j, "Name", field_type=bool)
        with self.assertRaises(ValueError):
            utils._check_field(j, "Name", value='Noise Model')
        with self.assertRaises(ValueError):
            utils._check_field(j, "Name", value='Noise Model', optional=True)
Ejemplo n.º 17
0
def create_track_from_json(filename: str,
                           environment: 'WAEnvironment' = None) -> 'WATrack':
    """Creates a WATrack object from a json specification file

    json file options:

    * Center Input File (``str``, required): A json file describing the centerline. Loaded using :meth:`~create_path_from_json`

    * Width (``float``, required): The constant width between the left and right boundaries of the track.

    * Origin(``list``, required): The GPS origin of the first centerline point

    * Visualization (``dict``, optional): Additional visualization properties.

      * Center/Right/Left (``dict``, optional): The each paths visualization properties

        * Color (``list``, optional): Visualization color.

        * Object (``dict``, optional): An object that is placed along the path. Only parsed if ``environment`` is set.

          * Size (``list``, optional): Size of the objects.

          * Color (``list``, optional): Color of the objects.

          * Color #1 (``list``, optional): Color of an alternating set of objects. Must come with Color #2 and without Color.

          * Color #2 (``list``, optional): Color of an alternating set of objects. Must come with Color #1 and without Color.

          * Mode (``str``, optional): The mode for the object placement along the path. Options include 'Solid', 'Dashed' (3[m] separation) and 'Spread' (6[m] separation).

    .. todo::

        Add a variable width loader

    Args:
        filename (str): The json specification that describes the track 
        environment (WAEnvironment, optional): Adds objects to the environment, if present. Defaults to None (doesn't parse objects).

    Returns:
        WATrack: The created track
    """

    j = _load_json(filename)

    # Validate the json file
    _check_field(j, 'Type', value='Track')
    _check_field(j, 'Template', allowed_values='Constant Width Track')
    _check_field(j, 'Center Input File', field_type=str)
    _check_field(j, 'Width', field_type=float)
    _check_field(j, 'Origin', field_type=list)
    _check_field(j, 'Visualization', field_type=dict, optional=True)

    # Create the centerline path
    center_file = get_wa_data_file(j['Center Input File'])
    center = create_path_from_json(center_file)

    width = j['Width']
    origin = WAVector(j['Origin'])

    # Create the track
    track = create_constant_width_track(center, width)
    track.origin = origin

    # Load the visualization, if present
    if 'Visualization' in j:
        v = j['Visualization']
        _check_field(v, 'Center', field_type=dict, optional=True)
        _check_field(v, 'Left', field_type=dict, optional=True)
        _check_field(v, 'Right', field_type=dict, optional=True)

        def _load_vis(path, path_name):
            if path_name in v:
                p = v[path_name]

                _check_field(p, 'Color', field_type=list, optional=True)
                _check_field(p, 'Object', field_type=dict, optional=True)

                if 'Color' in p:
                    path.get_vis_properties()['color'] = WAVector(p['Color'])

                if 'Object' in p and environment is not None:
                    o = p['Object']

                    _check_field(o, 'Size', field_type=list)
                    _check_field(o, 'Color', field_type=list, optional=True)
                    _check_field(o, 'Mode', field_type=str, optional=True)

                    kwargs = {}
                    kwargs['size'] = WAVector(o['Size'])

                    if 'Color' in o:
                        kwargs['color'] = WAVector(o['Color'])

                        if 'Color #1' in o or 'Color #2' in o:
                            raise ValueError(
                                "'Color' cannot be used with 'Color #1' or 'Color #2'"
                            )
                    elif 'Color #1' in o and 'Color #2' in o:
                        kwargs['color1'] = WAVector(o['Color #1'])
                        kwargs['color2'] = WAVector(o['Color #2'])
                    elif 'Color #1' in o or 'Color #2' in o:
                        raise ValueError(
                            "'Color #1' and 'Color #2' must be used together.")

                    s = path.calc_length_cummulative()[-1]
                    size = WAVector(o['Size'])
                    if 'Mode' in o:
                        m = o['Mode']

                        if m == 'Continuous':
                            n = s / size.y
                        elif m == 'Dashed':
                            n = s / 3  # Spaced as dashed center lines are (3[m] apart)
                        elif m == 'Spread':
                            n = s / 6
                        else:
                            raise ValueError(
                                f"'{m}' is not a supported road marker type")
                    else:
                        # Defaults to continuous
                        n = s / size.y

                    points = path.get_points()
                    d_points = path.get_points(der=1)

                    s = path.calc_length_cummulative()[-1]
                    size = WAVector(o['Size'])

                    l = len(points)
                    for e, i in enumerate(
                            range(0, l, 1 if l < n else int(l / n))):
                        p = points[i]
                        dp = d_points[i]

                        kwargs['position'] = WAVector(p)
                        kwargs['yaw'] = -np.arctan2(dp[1], dp[0])

                        if 'color1' in kwargs:
                            if e % 2 == 0:
                                kwargs['color'] = kwargs['color1']
                            else:
                                kwargs['color'] = kwargs['color2']

                        environment.create_body(**kwargs)

        _load_vis(track.center, 'Center')
        _load_vis(track.right, 'Right')
        _load_vis(track.left, 'Left')

    return track