Skip to content

Parse flybody

parse_actuators(xml_path, yaml_path, ignore_ctrlrange=True, merge_equivalent=True)

Parse inherited actuator defaults from MuJoCo defaults tree.

The output groups are class-based defaults containing actuator-related tags (e.g. general, adhesion, motor, position, ...), plus an apply_to section inferred from body/joint class usage.

Source code in src/flygym/flybody/parse_flybody.py
def parse_actuators(xml_path, yaml_path, ignore_ctrlrange=True, merge_equivalent=True):
    """Parse inherited actuator defaults from MuJoCo defaults tree.

    The output groups are class-based defaults containing actuator-related tags
    (e.g. general, adhesion, motor, position, ...), plus an apply_to section
    inferred from body/joint class usage.
    """
    tree = ET.parse(xml_path)
    root = tree.getroot()
    default_lookup = build_effective_default_lookup(root)
    class_to_targets = _collect_class_apply_targets(root.find("worldbody"))
    class_hierarchy = _collect_default_class_hierarchy(root)

    actuator_tags = {
        "general",
        "motor",
        "position",
        "velocity",
        "intvelocity",
        "damper",
        "cylinder",
        "muscle",
    }

    representative_to_targets = {}
    for class_name, targets in class_to_targets.items():
        representative = _resolve_representative_class(
            class_name, class_hierarchy, actuator_tags, ignore_ctrlrange
        )
        if representative is None:
            continue
        representative_to_targets.setdefault(representative, set()).update(targets)

    parsed = {}
    for class_name, targets in representative_to_targets.items():
        if class_name == "__root__" or class_name not in default_lookup:
            continue
        class_params = default_lookup[class_name]

        group_cfg = {}
        for tag in actuator_tags:
            if tag not in class_params:
                continue

            tag_cfg = _clean_actuator_tag_config(
                tag, class_params[tag], ignore_ctrlrange
            )

            if tag_cfg:
                group_cfg[tag] = _scale_actuator_tag_config(tag_cfg)

        if not group_cfg:
            continue

        apply_to = sorted(targets)
        if len(apply_to) == 1:
            group_cfg["apply_to"] = apply_to[0]
        else:
            group_cfg["apply_to"] = apply_to

        parsed[class_name] = group_cfg

    if merge_equivalent:
        parsed = _merge_equivalent_actuator_groups(parsed)

    _write_yaml_file(yaml_path, parsed)