Пример #1
0
    def _get_sdf_randomizer(
            self, task: SupportedTasks) -> randomizers.model.sdf.SDFRandomizer:

        if self._sdf_randomizer is not None:
            return self._sdf_randomizer

        # Get the model file
        urdf_model_file = cartpole.CartPole.get_model_file()

        # Convert the URDF to SDF
        sdf_model_string = scenario.urdffile_to_sdfstring(urdf_model_file)

        # Write the SDF string to a temp file
        sdf_model = utils.misc.string_to_file(sdf_model_string)

        # Create and initialize the randomizer
        sdf_randomizer = randomizers.model.sdf.SDFRandomizer(
            sdf_model=sdf_model)

        # Use the RNG of the task
        sdf_randomizer.rng = task.np_random

        # Randomize the mass of all links
        sdf_randomizer.new_randomization().at_xpath(
            "*/link/inertial/mass").method(Method.Additive).sampled_from(
                Distribution.Uniform,
                UniformParams(low=-0.2, high=0.2)).force_positive().add()

        # Process the randomization
        sdf_randomizer.process_data()
        assert len(sdf_randomizer.get_active_randomizations()) > 0

        # Store and return the randomizer
        self._sdf_randomizer = sdf_randomizer
        return self._sdf_randomizer
def test_sdf_randomizer():

    # Get the URDF model
    urdf_model = gym_ignition_models.get_model_file("cartpole")

    # Convert it to a SDF string
    sdf_model_string = scenario.urdffile_to_sdfstring(urdf_model)

    # Write the SDF string to a temp file
    sdf_model = misc.string_to_file(sdf_model_string)

    # Create the randomizer
    randomizer = sdf.SDFRandomizer(sdf_model=sdf_model)

    # Get the original model string. It is parsed and then serialized without changes.
    orig_model = randomizer.sample(pretty_print=True)

    with pytest.raises(ValueError):
        # Setting wrong distribution
        randomizer.new_randomization() \
            .at_xpath("*/link[@name='pole']/inertial/inertia/ixx") \
            .method(Method.Additive) \
            .sampled_from(Distribution.Uniform, GaussianParams(mean=0, variance=0.1)) \
            .add()

    # Add a uniform randomization
    randomizer.new_randomization() \
        .at_xpath("*/link[@name='pole']/inertial/inertia/ixx") \
        .method(Method.Additive) \
        .sampled_from(Distribution.Gaussian, GaussianParams(mean=0, variance=0.1)) \
        .add()

    randomizer.process_data()
    assert len(randomizer.get_active_randomizations()) == 1

    assert randomizer.sample(pretty_print=True) != orig_model

    # Clean the randomizer
    randomizer.clean()
    assert len(randomizer.get_active_randomizations()) == 0
    assert randomizer.sample(pretty_print=True) == orig_model

    # Add a multi-match randomization
    randomizer.new_randomization() \
        .at_xpath("*/link/inertial/inertia/ixx") \
        .method(Method.Coefficient) \
        .sampled_from(Distribution.Uniform, UniformParams(low=0.8, high=1.2)) \
        .add()

    assert len(randomizer.get_active_randomizations()) == 1

    # Expand the matches
    randomizer.process_data()
    assert len(randomizer.get_active_randomizations()) > 1

    # Sample
    assert randomizer.sample(pretty_print=True) != orig_model
def test_randomize_missing_element():

    # Get the URDF model
    urdf_model = gym_ignition_models.get_model_file("pendulum")

    # Convert it to a SDF string
    sdf_model_string = scenario.urdffile_to_sdfstring(urdf_model)

    # Write the SDF string to a temp file
    sdf_model = misc.string_to_file(sdf_model_string)

    # Create the randomizer
    randomizer = sdf.SDFRandomizer(sdf_model=sdf_model)

    # Try to randomize a missing element
    with pytest.raises(RuntimeError):
        # The ode/mu elements are missing
        randomizer.new_randomization() \
            .at_xpath("*/link/collision/surface/friction/ode/mu") \
            .method(Method.Absolute) \
            .sampled_from(Distribution.Uniform,
                          UniformParams(low=0, high=100)) \
            .add()

    # Add the missing friction/ode/mu element. We assume that friction exists.
    frictions = randomizer.find_xpath("*/link/collision/surface/friction")

    for friction in frictions:

        # Create parent 'ode' first
        if friction.find("ode") is None:
            etree.SubElement(friction, "ode")

        # Create child 'mu' after
        ode = friction.find("ode")
        if ode.find("mu") is None:
            etree.SubElement(ode, "mu")

        # Assign a dummy value to mu
        mu = ode.find("mu")
        mu.text = str(0)

    # Apply the same randomization
    randomizer.new_randomization() \
        .at_xpath("*/link/collision/surface/friction/ode/mu") \
        .method(Method.Absolute) \
        .sampled_from(Distribution.Uniform,
                      UniformParams(low=0, high=100)) \
        .ignore_zeros(False) \
        .add()

    # Process the randomization and sample a model
    randomizer.process_data()

    model1 = randomizer.sample(pretty_print=True)
    model2 = randomizer.sample(pretty_print=True)
    assert model1 != model2
Пример #4
0
def test_full_panda_randomization():

    # Get the URDF model
    urdf_model = gym_ignition_models.get_model_file("panda")

    # Convert it to a SDF string
    sdf_model_string = scenario.urdffile_to_sdfstring(urdf_model)

    # Write the SDF string to a temp file
    sdf_model = misc.string_to_file(sdf_model_string)

    # Create the randomizer
    randomizer = sdf.SDFRandomizer(sdf_model=sdf_model)

    joint_dynamics = randomizer.find_xpath("*/joint/axis/dynamics")
    assert len(joint_dynamics) > 0

    # Add the friction and damping elements since they're missing in the model
    for joint_dynamic in joint_dynamics:

        if joint_dynamic.find("friction") is None:
            etree.SubElement(joint_dynamic, "friction")
            friction = joint_dynamic.find("friction")
            friction.text = str(0)

        if joint_dynamic.find("damping") is None:
            etree.SubElement(joint_dynamic, "damping")
            damping = joint_dynamic.find("damping")
            damping.text = str(3)

    randomization_config = {
        "*/link/inertial/mass": {
            # mass + U(-0.5, 0.5)
            "method": Method.Additive,
            "distribution": Distribution.Uniform,
            "params": UniformParams(low=-0.5, high=0.5),
            "ignore_zeros": True,
            "force_positive": True,
        },
        "*/link/inertial/inertia/ixx": {
            # inertia * N(1, 0.2)
            "method": Method.Coefficient,
            "distribution": Distribution.Gaussian,
            "params": GaussianParams(mean=1.0, variance=0.2),
            "ignore_zeros": True,
            "force_positive": True,
        },
        "*/link/inertial/inertia/iyy": {
            "method": Method.Coefficient,
            "distribution": Distribution.Gaussian,
            "params": GaussianParams(mean=1.0, variance=0.2),
            "ignore_zeros": True,
            "force_positive": True,
        },
        "*/link/inertial/inertia/izz": {
            "method": Method.Coefficient,
            "distribution": Distribution.Gaussian,
            "params": GaussianParams(mean=1.0, variance=0.2),
            "ignore_zeros": True,
            "force_positive": True,
        },
        "*/joint/axis/dynamics/friction": {
            # friction in [0, 5]
            "method": Method.Absolute,
            "distribution": Distribution.Uniform,
            "params": UniformParams(low=0, high=5),
            "ignore_zeros": False,  # We initialized the value as 0
            "force_positive": True,
        },
        "*/joint/axis/dynamics/damping": {
            # damping (= 3.0) * [0.8, 1.2]
            "method": Method.Coefficient,
            "distribution": Distribution.Uniform,
            "params": UniformParams(low=0.8, high=1.2),
            "ignore_zeros": True,
            "force_positive": True,
        },
        # TODO: */joint/axis/limit/effort
    }

    for xpath, config in randomization_config.items():

        randomizer.new_randomization().at_xpath(xpath).method(
            config["method"]).sampled_from(
                config["distribution"], config["params"]).force_positive(
                    config["distribution"]).ignore_zeros(
                        config["ignore_zeros"]).add()

    randomizer.process_data()
    assert len(randomizer.get_active_randomizations()) > 0

    randomizer.sample(pretty_print=True)
Пример #5
0
def get_model_resource(
    robot_name: str, resource_type: ResourceType = ResourceType.URDF_PATH
) -> Union[str, IO]:
    """
    Return the resource of the selected robot.

    Args:
        robot_name: The name of the selected robot.
        resource_type: The type of the desired resource.

    Note:
        If a format conversion is performed, this method creates a temporary file.
        If ``ResourceType.*_FILE`` is used, the file gets automatically deleted when
        it goes out of scope. Instead, if ``ResourceType._*PATH`` is used, the caller
        is responsible to delete it.

    Returns:
        The desired resource of the selected robot.
    """

    stored_model = get_model_file(robot_name=robot_name)

    if not stored_model.endswith((".urdf", ".sdf")):
        raise RuntimeError(f"Model '{robot_name} has no urdf nor sdf resource")

    if stored_model.endswith(".urdf"):

        if resource_type is ResourceType.URDF_PATH:
            return stored_model

        if resource_type is ResourceType.URDF_FILE:
            return open(file=stored_model, mode="r+")

        if resource_type is ResourceType.URDF_STRING:
            with open(file=stored_model, mode="r+") as f:
                return f.read()

        if resource_type in {
            ResourceType.SDF_FILE,
            ResourceType.SDF_PATH,
            ResourceType.SDF_STRING,
        }:
            try:
                from scenario import gazebo as scenario_gazebo
            except ImportError:
                msg = "URDF to SDF conversion requires the 'scenario' package"
                raise RuntimeError(msg)

        if resource_type is ResourceType.SDF_FILE:
            file_name = Path(stored_model).with_suffix("").name
            sdf_file = tempfile.NamedTemporaryFile(
                mode="w+", prefix=file_name, suffix=".sdf"
            )
            sdf_string = get_model_resource(
                robot_name=robot_name, resource_type=ResourceType.SDF_STRING
            )
            sdf_file.write(sdf_string)
            return sdf_file

        if resource_type is ResourceType.SDF_PATH:
            file_name = Path(stored_model).with_suffix("").name
            fd, sdf_path = tempfile.mkstemp(prefix=file_name, suffix=".sdf", text=True)
            sdf_string = get_model_resource(
                robot_name=robot_name, resource_type=ResourceType.SDF_STRING
            )
            with open(sdf_path, "w") as f:
                f.write(sdf_string)
            return sdf_path

        if resource_type is ResourceType.SDF_STRING:
            from scenario import gazebo as scenario_gazebo

            return scenario_gazebo.urdffile_to_sdfstring(urdf_file=stored_model)

        raise ValueError(resource_type)

    if stored_model.endswith(".sdf"):

        if resource_type is ResourceType.SDF_PATH:
            return stored_model

        if resource_type in {
            ResourceType.URDF_FILE,
            ResourceType.URDF_PATH,
            ResourceType.URDF_STRING,
        }:
            raise ValueError("SDF to URDF conversion is not supported")

        if resource_type is ResourceType.SDF_STRING:
            with open(file=stored_model, mode="r+") as f:
                return f.read()

        if resource_type is ResourceType.SDF_FILE:
            return open(file=stored_model, mode="r+")

        raise ValueError(resource_type)