Beispiel #1
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
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")
Beispiel #3
0
def ChFrame_from_json(j: dict):
    """Creates a ChFrame from a json object.

    Args:
        j (dict): The json object that will be converted to a ChFrame

    Returns:
        ChFrameD: The frame created from the json object
    """

    # Validate the json file
    _check_field(j, 'Position', field_type=list)
    _check_field(j, 'Rotation', field_type=list)

    # Do the conversion
    pos = j['Position']
    rot = j['Rotation']
    return chrono.ChFrameD(
        chrono.ChVectorD(pos[0], pos[1], pos[2]),
        chrono.ChQuaternionD(rot[0], rot[1], rot[2], rot[3]))
Beispiel #4
0
    def __init__(self, p: dict):
        # Validate properties
        _check_field(p, 'Noise Type', value='Normal')
        _check_field(p, 'Mean', field_type=list)
        _check_field(p, 'Standard Deviation', field_type=list)

        self._load_properties(p)
Beispiel #5
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
    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
Beispiel #7
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)
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
Beispiel #9
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)
Beispiel #10
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()
Beispiel #11
0
    def __init__(self, p: dict):
        # Validate properties
        _check_field(p, 'Noise Type', value='Normal Drift')
        _check_field(p, 'Update Rate', field_type=float)
        _check_field(p, 'Mean', field_type=list)
        _check_field(p, 'Standard Deviation', field_type=list)
        _check_field(p, 'Bias Drift', field_type=float)
        _check_field(p, 'Tau Drift', field_type=float)

        self._load_properties(p)
Beispiel #12
0
        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)
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)
    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)
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
Beispiel #16
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)
Beispiel #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