### Install FlyGym with examples optional dependency Source: https://neuromechfly.org/installation Adds the 'examples' optional dependency to follow the tutorials. ```bash pip install flygym[examples] ``` -------------------------------- ### Imports and output directory setup for FlyBody tutorial Source: https://neuromechfly.org/tutorials/5b_using_flybody_model Imports required for the FlyBody hybrid turning controller example and creates the output directory 'demo_output/flybody_turning_controller'. ```python from pathlib import Path import matplotlib.pyplot as plt import numpy as np from tqdm import trange from flygym import Simulation from flygym.anatomy import BodySegment, JointDOF, RotationAxis from flygym.compose import ActuatorType, FlatGroundWorld, KinematicPosePreset from flygym.compose.fly import FlyBody from flygym.flybody import ( FlyBodyActuatedDOFPreset, FlyBodyAxisOrder, FlyBodyContactBodiesPreset, FlyBodyJointPreset, FlyBodySkeleton, FlyBodyBodySegment, ) from flygym.utils.math import Rotation3D from flygym_demo.complex_terrain import ( HybridControllerObservation, HybridTurningController, FlyBodyPreprogrammedSteps, apply_locomotion_action, ) from flygym_demo.complex_terrain.common import LocomotionAction output_dir = Path("demo_output/flybody_turning_controller") output_dir.mkdir(parents=True, exist_ok=True) ``` -------------------------------- ### Install flygym-gymnasium (legacy API) Source: https://neuromechfly.org/migration Install the migrated Gymnasium-compliant FlyGym 1.x.x API from the flygym-gymnasium repository. The second command includes optional dependencies for examples and development. ```bash pip install flygym-gymnasium # or, if you want optional dependencies: pip install "flygym-gymnasium[examples,dev]" ``` -------------------------------- ### Install FlyGym with uv and optional extras Source: https://neuromechfly.org/installation Uses uv to sync the project with all optional dependencies (warp, dev, examples). Remove extras as needed. ```bash uv sync --extra warp --extra dev --extra examples ``` -------------------------------- ### Install flygym-gymnasium (legacy API) - repeated Source: https://neuromechfly.org/migration Repeated installation command for the legacy API, with an alternative comment for optional dependencies. ```bash pip install flygym-gymnasium # or, to include optional dependencies: pip install "flygym-gymnasium[examples,dev]" ``` -------------------------------- ### Install nsight-systems via apt Source: https://neuromechfly.org/tutorials/7_performance_profiling Install NVIDIA Nsight Systems on Ubuntu/Debian via NVIDIA's CUDA apt repository. This is required for GPU profiling. ```bash apt-get install nsight-systems ``` -------------------------------- ### Install FlyGym with pip (basic) Source: https://neuromechfly.org/installation Installs the core FlyGym package from PyPI using pip. Recommended for basic usage. ```bash pip install flygym ``` -------------------------------- ### Install FlyGym with rl optional dependency Source: https://neuromechfly.org/installation Adds the 'rl' optional dependency for reinforcement-learning training, installing Gymnasium, Stable-Baselines3, and TensorBoard. ```bash pip install flygym[rl] ``` -------------------------------- ### Install FlyGym with multiple optional dependencies Source: https://neuromechfly.org/installation Combines multiple optional dependencies in one pip install command. ```bash pip install flygym[warp,examples,rl] ``` -------------------------------- ### Install nbstripout filter Source: https://neuromechfly.org/installation Activates the virtual environment and installs the nbstripout filter to remove Jupyter Notebook outputs on git add. ```bash source .venv/bin/activate nbstripout --install --attributes .gitattributes ``` -------------------------------- ### Output of RuleBasedController setup Source: https://neuromechfly.org/tutorials/4b_rule_based_controller Shows the printed output from the controller setup: 42 actuated DoFs, simulation timestep 0.0001, kinematic spline cycle rate 7.4074 Hz, the rule weights, and the rule graph edges for rules 1, 2, and 3. ```text Actuated DoFs: 42 Simulation timestep: 0.0001 Kinematic spline cycle rate (Hz): 7.4074 Rule weights: {'rule1': -10.0, 'rule2_ipsi': 2.5, 'rule2_contra': 1.0, 'rule3_ipsi': 3.0, 'rule3_contra': 2.0} rule1: {'lm': ('lf',), 'lh': ('lm',), 'rm': ('rf',), 'rh': ('rm',)} rule2: {'lf': ('rf',), 'lm': ('rm', 'lf'), 'lh': ('rh', 'lm'), 'rf': ('lf',), 'rm': ('lm', 'rf'), 'rh': ('lh', 'rm')} rule3: {'lf': ('rf', 'lm'), 'lm': ('rm', 'lh'), 'lh': ('rh',), 'rf': ('lf', 'rm'), 'rm': ('lm', 'rh'), 'rh': ('lh',)} ``` -------------------------------- ### KinematicPose initialization example Source: https://neuromechfly.org/api_reference/flygym/compose/pose Shows how to create a KinematicPose from a YAML file with mirroring enabled. After creation, use the joint_angles_lookup_rad attribute to access the joint angles. ```python pose = KinematicPose(path="neutral.yaml", mirror_left2right=True) # then use `pose.joint_angles_lookup_rad` ``` -------------------------------- ### Setup simulation environment and fly with camera Source: https://neuromechfly.org/tutorials/4b_rule_based_controller Imports required modules, creates a fly with adhesion and colorization, adds a tracking camera, sets up a flat ground world, spawns the fly, and initializes the simulation with a renderer. ```python from pathlib import Path import matplotlib.pyplot as plt import numpy as np from tqdm import trange from flygym import Simulation from flygym.anatomy import BodySegment from flygym.compose import FlatGroundWorld from flygym_demo.complex_terrain import ( LocomotionAction, PreprogrammedSteps, RuleBasedController, apply_locomotion_action, construct_rules_graph, make_locomotion_fly, ) from flygym.utils.math import Rotation3D output_dir = Path("demo_output/rule_based_controller") output_dir.mkdir(parents=True, exist_ok=True) fly = make_locomotion_fly( name="rule_demo", add_adhesion=True, colorize=True, ) body_cam = fly.add_tracking_camera( name="body_cam", pos_offset=(-0.5, -7.5, 0.0), rotation=Rotation3D("euler", (1.57, 0.0, 0.0)), fovy=30.0, ) world = FlatGroundWorld() spawn_pos = [0, 0, 0.5] # FlyGym v1 default spawn z spawn_rot = Rotation3D("quat", [1, 0, 0, 0]) world.add_fly(fly, spawn_pos, spawn_rot) sim = Simulation(world) renderer = sim.set_renderer([body_cam]) ``` -------------------------------- ### Initialize Hybrid Controller Source: https://neuromechfly.org/tutorials/4c_hybrid_controller Sets up the hybrid controller with preprogrammed steps and prints simulation parameters. ```python preprogrammed_steps = PreprogrammedSteps() dof_order = fly.get_actuated_jointdofs_order("position") controller = HybridController( timestep=sim.timestep, preprogrammed_steps=preprogrammed_steps, output_dof_order=dof_order, ) print("Actuated DoFs:", len(dof_order)) print("Simulation timestep:", sim.timestep) print( "Controller CPG frequency (Hz):", float(controller.cpg_network.intrinsic_freqs[0]) ) ``` ```text Actuated DoFs: 42 Simulation timestep: 0.0001 Controller CPG frequency (Hz): 12.0 ``` -------------------------------- ### Google Colab setup for FlyGym Source: https://neuromechfly.org/installation Configures headless EGL rendering and installs FlyGym from GitHub in Google Colab. Run this in the first code cell of a tutorial notebook. ```python import os import sys if "google.colab" in sys.modules: os.environ["MUJOCO_GL"] = "egl" os.environ["PYOPENGL_PLATFORM"] = "egl" %pip install -q tqdm "flygym @ git+https://github.com/NeLy-EPFL/flygym.git@v2.1.0" ``` -------------------------------- ### Google Colab setup for FlyBody tutorial Source: https://neuromechfly.org/tutorials/5a_replaying_experimental_flybody_onball Run this cell first when using Google Colab to install FlyGym v2.1.0 and enable headless EGL rendering. It is a no-op when run elsewhere. ```python # --- Google Colab setup --- # If you opened this notebook in Google Colab, run this cell first to # install FlyGym and enable headless (EGL) rendering. It is a no-op when # the notebook is run anywhere else. import os import sys if "google.colab" in sys.modules: os.environ["MUJOCO_GL"] = "egl" os.environ["PYOPENGL_PLATFORM"] = "egl" %pip install -q tqdm "flygym @ git+https://github.com/NeLy-EPFL/flygym.git@v2.1.0" ``` -------------------------------- ### Start interactive shell in FlyGym container Source: https://neuromechfly.org/installation Starts an interactive shell inside the FlyGym Docker container. ```bash docker run -it nelyepfl/flygym ``` -------------------------------- ### Configure Fly and Simulation Environment Source: https://neuromechfly.org/tutorials/4d_turning_controller Initializes the fly model, adds a tracking camera, sets up the flat ground world, and configures the renderer. ```python fly = make_locomotion_fly( name="turning_demo", add_adhesion=True, colorize=True, ) body_cam = fly.add_tracking_camera( name="body_cam", pos_offset=(-0.5, -7.5, 0.0), rotation=Rotation3D("euler", (1.57, 0.0, 0.0)), fovy=35.0, ) world = FlatGroundWorld() world.add_fly( fly, [0, 0, 0.8], Rotation3D("quat", [1, 0, 0, 0]), bodysegs_with_ground_contact=ContactBodiesPreset.TIBIA_TARSUS_ONLY, add_ground_contact_sensors=False, ) sim = Simulation(world) renderer = sim.set_renderer( [body_cam], camera_res=(240, 320), playback_speed=0.1, output_fps=25, ) ``` -------------------------------- ### Defining Source and Package Paths Source: https://neuromechfly.org/gen_ref_pages Setting up the root directory and source package path for the documentation generation script. ```python package = "flygym" root = Path(__file__).resolve().parents[1] src_root = root / "src" src_pkg = src_root / package ``` -------------------------------- ### Initialize ImitationEnv Source: https://neuromechfly.org/tutorials/6_muscle_imitation Demonstrates how to build a musculoskeletal simulation and initialize the imitation environment with a default dataset. ```python from flygym.compose import build_musculoskeletal_simulation from flygym_demo.muscle_imitation import ImitationConfig, ImitationEnv, MoCapDataset sim, fly = build_musculoskeletal_simulation() # Simulation backed by the muscle model env = ImitationEnv( sim, fly_name=fly.name, dataset=MoCapDataset.default(), config=ImitationConfig(clip="0002"), ) obs, _ = env.reset() for _ in range(200): action = env.action_space.sample() # 15 muscle activations in [0, 1] obs, reward, terminated, truncated, info = env.step(action) ``` -------------------------------- ### FlatGroundWorld.__init__ Source: https://neuromechfly.org/api_reference/flygym/compose/world/flat_ground Initializes a FlatGroundWorld instance with a name and half_size parameter. Sets up the ground plane geometry and materials. ```APIDOC ## FlatGroundWorld.__init__ ### Description Initializes a FlatGroundWorld instance with a name and half_size parameter. Sets up the ground plane geometry and materials. ### Method Constructor ### Signature ```python FlatGroundWorld(name: str = "flat_ground_world", *, half_size: float = 1000) ``` ### Parameters - **name** (str) - Optional - Name of the world. Default: `'flat_ground_world'`. - **half_size** (float) - Optional - Half-size of the ground plane in mm. Default: `1000`. ### Notes - The `half_size` parameter is keyword-only. - The constructor sets up a checkerboard texture and material for the ground plane. - The ground plane is added as a geometry with type 'plane', name 'ground_plane', and size `(half_size, half_size, 1)`. - The ground geometry is stored in `self.ground_geom` and `self.ground_geoms`. ### Example ```python world = FlatGroundWorld(name="my_world", half_size=500) ``` ``` -------------------------------- ### Install EGL dependencies on Ubuntu/Debian Source: https://neuromechfly.org/installation Install the necessary EGL development libraries on Ubuntu or Debian systems to support headless rendering. ```bash apt-get install libegl1-mesa-dev ``` -------------------------------- ### Initialize Hybrid Turning Controller Source: https://neuromechfly.org/tutorials/4d_turning_controller Sets up the hybrid turning controller with the simulation timestep and preprogrammed steps, then prints simulation parameters. ```python preprogrammed_steps = PreprogrammedSteps() dof_order = fly.get_actuated_jointdofs_order("position") controller = HybridTurningController( timestep=sim.timestep, preprogrammed_steps=preprogrammed_steps, output_dof_order=dof_order, ) print("Actuated DoFs:", len(dof_order)) print("Simulation timestep:", sim.timestep) ``` ```text Actuated DoFs: 42 Simulation timestep: 0.0001 ``` -------------------------------- ### Initialize Fly and Simulation Environment Source: https://neuromechfly.org/tutorials/4c_hybrid_controller Configures the fly model, adds a tracking camera, sets up the mixed terrain world, and initializes the simulation renderer. ```python fly = make_locomotion_fly( name="hybrid_demo", add_adhesion=True, colorize=True, ) body_cam = fly.add_tracking_camera( name="body_cam", pos_offset=(-0.5, -7.5, 0.0), rotation=Rotation3D("euler", (1.57, 0.0, 0.0)), fovy=35.0, ) world = MixedTerrainWorld() world.add_fly( fly, [0, 0, 1.2], Rotation3D("quat", [1, 0, 0, 0]), bodysegs_with_ground_contact=ContactBodiesPreset.TIBIA_TARSUS_ONLY, add_ground_contact_sensors=False, ) sim = Simulation(world) renderer = sim.set_renderer( [body_cam], camera_res=(240, 320), playback_speed=0.1, output_fps=25, ) ``` -------------------------------- ### Initializing Navigation Source: https://neuromechfly.org/gen_ref_pages Creating a navigation object to manage the generated documentation structure. ```python nav = mkdocs_gen_files.Nav() ``` -------------------------------- ### Instantiate RuleBasedController with preprogrammed steps and weights Source: https://neuromechfly.org/tutorials/4b_rule_based_controller Creates the preprogrammed step table, builds the rule graph, sets rule weights (rule1 inhibitory, rules 2 and 3 excitatory), and constructs the RuleBasedController. Prints the number of actuated DoFs, simulation timestep, kinematic spline cycle rate, weights, and rule graph edges. ```python preprogrammed_steps = PreprogrammedSteps() dof_order = fly.get_actuated_jointdofs_order("position") rules_graph = construct_rules_graph() weights = { "rule1": -10.0, "rule2_ipsi": 2.5, "rule2_contra": 1.0, "rule3_ipsi": 3.0, "rule3_contra": 2.0, } controller = RuleBasedController( timestep=sim.timestep, rules_graph=rules_graph, weights=weights, preprogrammed_steps=preprogrammed_steps, output_dof_order=dof_order, seed=0, ) print("Actuated DoFs:", len(dof_order)) print("Simulation timestep:", sim.timestep) print( "Kinematic spline cycle rate (Hz):", round(preprogrammed_steps.step_cycle_frequency_hz, 4), ) print("Rule weights:", weights) for rule_name, edges_by_source in rules_graph.items(): print(f"{rule_name}:", edges_by_source) ``` -------------------------------- ### Skeleton.iter_jointdofs Source: https://neuromechfly.org/api_reference/flygym/anatomy Iterates through joint DOFs in depth-first order starting from the root. ```APIDOC ## Skeleton.iter_jointdofs ### Description Iterates through joint degrees of freedom (DOFs) in depth-first order starting from the root segment. ### Method `iter_jointdofs(self, root: BodySegment | str = "c_thorax") -> Iterator[JointDOF]` ### Parameters - **root** (BodySegment | str) - Optional - The root segment to start iteration from. Defaults to "c_thorax". ### Yields - **JointDOF** - Each joint DOF in depth-first order. ``` -------------------------------- ### Import Dependencies and Configure Output Directory Source: https://neuromechfly.org/tutorials/4c_hybrid_controller Imports necessary libraries and sets up the output directory for saving simulation results. ```python from pathlib import Path import matplotlib.pyplot as plt import numpy as np from tqdm import trange from flygym import Simulation from flygym.anatomy import BodySegment, ContactBodiesPreset from flygym.compose import MixedTerrainWorld from flygym_demo.complex_terrain import ( HybridController, HybridControllerObservation, LocomotionAction, PreprogrammedSteps, apply_locomotion_action, make_locomotion_fly, ) from flygym.utils.math import Rotation3D output_dir = Path("demo_output/hybrid_controller") output_dir.mkdir(parents=True, exist_ok=True) ``` -------------------------------- ### Get base skeleton Source: https://neuromechfly.org/api_reference/flygym/compose/fly/base_fly Initializes the base skeleton for the fly model. ```python def _get_base_skeleton(self) -> Skeleton: return self.BASE_SKELETON_CLASS( joint_preset=self._all_possible_joint_preset(), axis_order=self.AXIS_ORDER_CLASS.DONTCARE, ) ``` -------------------------------- ### Initialize CPG Controller and Tripod Network Source: https://neuromechfly.org/tutorials/4a_cpg_controller Instantiates the preprogrammed step table and the tripod-gait CPG network, then combines them into a CPGController. This snippet also prints diagnostic information about the simulation and CPG network state. ```python preprogrammed_steps = PreprogrammedSteps() dof_order = fly.get_actuated_jointdofs_order("position") cpg_network = make_tripod_cpg_network( timestep=sim.timestep, intrinsic_amplitude=1.0, coupling_strength=10.0, convergence_coef=20.0, seed=0, ) controller = CPGController( cpg_network=cpg_network, preprogrammed_steps=preprogrammed_steps, output_dof_order=dof_order, ) print("Actuated DoFs:", len(dof_order)) print("Simulation timestep:", sim.timestep) print( "CPG intrinsic frequency (network, Hz):", float(cpg_network.intrinsic_freqs[0]), ) print( "Kinematic spline cycle rate (Hz, informational):", round(preprogrammed_steps.step_cycle_frequency_hz, 4), ) print("CPG phases:", np.round(cpg_network.curr_phases, 3)) ``` -------------------------------- ### Constructing MusculoskeletalWorld Source: https://neuromechfly.org/api_reference/flygym/compose/world/musculoskeletal Example showing how to instantiate a MusculoskeletalFly and wrap it in a MusculoskeletalWorld for simulation. ```python from flygym import Simulation from flygym.compose import MusculoskeletalFly, MusculoskeletalWorld fly = MusculoskeletalFly() world = MusculoskeletalWorld(fly) sim = Simulation(world) ``` -------------------------------- ### Set up simulation scaffold for rule-based controller Source: https://neuromechfly.org/tutorials/4b_rule_based_controller Creates a legs-only fly with adhesion and tracking camera, adds it to a flat ground world, and initializes the simulation with a renderer. Uses the make_locomotion_fly helper to separate model setup from controller logic. ```python from pathlib import Path import matplotlib.pyplot as plt import numpy as np from tqdm import trange from flygym import Simulation from flygym.anatomy import BodySegment from flygym.compose import FlatGroundWorld from flygym_demo.complex_terrain import ( LocomotionAction, PreprogrammedSteps, RuleBasedController, apply_locomotion_action, construct_rules_graph, make_locomotion_fly, ) from flygym.utils.math import Rotation3D output_dir = Path("demo_output/rule_based_controller") output_dir.mkdir(parents=True, exist_ok=True) fly = make_locomotion_fly( name="rule_demo", add_adhesion=True, colorize=True, ) body_cam = fly.add_tracking_camera( name="body_cam", pos_offset=(-0.5, -7.5, 0.0), rotation=Rotation3D("euler", (1.57, 0.0, 0.0)), fovy=30.0, ) world = FlatGroundWorld() spawn_pos = [0, 0, 0.5] # FlyGym v1 default spawn z spawn_rot = Rotation3D("quat", [1, 0, 0, 0]) world.add_fly(fly, spawn_pos, spawn_rot) sim = Simulation(world) renderer = sim.set_renderer([body_cam]) ``` -------------------------------- ### get_site_positions(fly_name) Source: https://neuromechfly.org/api_reference/flygym/simulation Gets global 3D positions of anatomical-joint sites for a specified fly. ```APIDOC ## get_site_positions(fly_name) ### Description Gets global 3D positions of anatomical-joint sites for a specified fly. ### Method SDK method call ### Parameters - **fly_name** (str) - Required - Name of the fly. ### Returns - **Float[ndarray, 'n_sites 3']** - Site positions in mm, shape (n_sites, 3), ordered as in `fly.get_sites_order()`. ### Example ```python positions = simulation.get_site_positions("fly1") ``` ``` -------------------------------- ### Add mesh to FlyBody Source: https://neuromechfly.org/api_reference/flygym/compose/fly/flybody Example of adding a mesh to the MJCF root and associating it with a specific body segment. ```python mesh = self.mjcf_root.add_mesh( name=mesh_name, file=str(mesh_path), scale=(self.SCALE, y_sign * self.SCALE, self.SCALE), ) if segment_name not in self.bodyseg_to_mjcfmesh: self.bodyseg_to_mjcfmesh[segment_name] = [mesh] else: self.bodyseg_to_mjcfmesh[segment_name].append(mesh) # add abdomen8 mesh (just a mesh connected to c_abdomen7) self.bodyseg_to_mjcfmesh["c_abdomen7"].append( self.mjcf_root.add_mesh( name="c_abdomen8_body", file=str(mesh_dir / "c_abdomen8_body.obj"), scale=(self.SCALE, self.SCALE, self.SCALE), ) ) ``` -------------------------------- ### Compile and Preview Simulation Source: https://neuromechfly.org/tutorials/1a_basic_model_composition Compile the world model and launch a preview to visualize the simulation. ```python mj_model, mj_data = world.compile() preview_model(mj_model, mj_data, camera, show_in_notebook=True) ``` -------------------------------- ### Run the full test suite Source: https://neuromechfly.org/contributing Execute the entire test suite using the uv package manager. ```bash uv run pytest tests/ ``` -------------------------------- ### iter_jointdofs Method Source: https://neuromechfly.org/api_reference/flygym/flybody/anatomy_flybody Iterates through joint degrees of freedom in depth-first order, starting from the specified root segment. ```python def iter_jointdofs( self, root: FlyBodyBodySegment | str = "c_thorax", ) -> Iterator[FlyBodyJointDOF]: """Iterate through joint DOFs in depth-first order starting from the root.""" if isinstance(root, str): root = FlyBodyBodySegment(root) tree = self.get_tree() for parent, child in tree.dfs_edges(root): anatomical_joint = self.joint_lookup[(parent, child)] for jointdof in anatomical_joint.iter_dofs(self.axis_order): yield jointdof ``` -------------------------------- ### reset() Source: https://neuromechfly.org/api_reference/flygym/rendering Clears buffered frames and resets the render timer. This method is used to start a fresh recording session. ```APIDOC ## reset() ### Description Clear buffered frames and reset the render timer. ### Method reset() ### Signature ```python def reset(self) -> None: ``` ### Parameters None ### Returns None ### Example ```python renderer.reset() ``` ```