Skip to content

tethered_world

TetheredWorld

Bases: BaseWorld

World where the fly body is rigidly fixed in space.

The root segment is attached to a static spawn site (no free joint) and held as a mocap body, so the fly's body stays put while its appendages (legs, wings, etc.) can still move. Useful for motor control experiments without locomotion.

Parameters:

Name Type Description Default
name str

Name of the world.

'tethered_world'
Source code in src/flygym/compose/world/tethered_world.py
class TetheredWorld(BaseWorld):
    """World where the fly body is rigidly fixed in space.

    The root segment is attached to a static spawn site (no free joint) and held as a
    mocap body, so the fly's body stays put while its appendages (legs, wings, etc.)
    can still move. Useful for motor control experiments without locomotion.

    Args:
        name: Name of the world.
    """

    @override
    def __init__(self, name: str = "tethered_world") -> None:
        super().__init__(name=name)

    @override
    def _attach_fly_mjcf(
        self, fly: BaseFly, spawn_position: Vec3, spawn_rotation: Rotation3D
    ) -> set[str]:
        spawn_site = self.mjcf_root.worldbody.add_site(
            name=fly.name, pos=spawn_position, **spawn_rotation.as_kwargs()
        )
        self.mjcf_root.attach(fly.mjcf_root, prefix=f"{fly.name}/", site=spawn_site)

        # Hold the root segment fixed as a mocap body rather than via a free joint. With
        # no joint the root would be a static body that the `fusestatic` optimization
        # merges into the worldbody, which breaks the tracking camera parented to it (the
        # camera would track the worldbody and mis-place itself relative to the fly). A
        # mocap body is never fused and is held rigidly in place at zero extra DoFs --
        # exactly the tethered behavior -- while every other jointless segment is still
        # fused for performance. (A free joint + weld equality would also avoid fusing,
        # but the weld is a soft constraint: the body visibly drifts under the leg
        # reaction forces unless its stiffness is tuned, so mocap is the simpler choice.)
        fly.bodyseg_to_mjcfbody[fly.root_segment].mocap = True
        return set()