# Motion Planning Import all built-in environments ``` import typer from typing_extensions import Annotated import gymnasium as gym import simple.envs as _# import all envs from simple.mp.curobo import CuRoboPlanner from simple.agents.mp import MotionPlannerAgent from simple.tasks.franka_tabletop_grasp_mp import FrankaTabletopGraspTaskMP # suppress typer trachback import os os.environ["_TYPER_STANDARD_TRACEBACK"]="1" ``` Pass-in params ``` def main( env_id: Annotated[str, typer.Argument()] = "simple/FrankaTabletopGraspMP-v0", scene_uid: Annotated[str, typer.Option()] = "hssd:scene1", sim_mode: Annotated[str, typer.Option()] = "mujoco_isaac", headless: Annotated[bool, typer.Option()] = False, max_episode_steps: Annotated[int, typer.Option()] = 200, render_hz: Annotated[int, typer.Option()] = 30, data_format: Annotated[str, typer.Option()] = "lerobot", save_dir: Annotated[str, typer.Option()] = "data/datagen", shard_size: Annotated[int, typer.Option()] = 100, ): ```` create environment ``` env = gym.make( env_id, scene_uid=scene_uid, sim_mode=sim_mode, headless=headless, max_episode_steps=max_episode_steps, render_hz=render_hz, ) task: FrankaTabletopGraspTaskMP = env.unwrapped.task # type: ignore ``` create motion planner ``` render_hz = task.metadata["render_hz"] planner = CuRoboPlanner( robot=task.robot, plan_dt=1.0/render_hz, plan_batch_size=40, ) # create motion-planner based agent to solve the task mp_agent = MotionPlannerAgent(task, planner) ``` create data recorder wrapper, depending on data format in this example we only support lerobot format ``` if data_format == "lerobot": from simple.envs.lerobot import LerobotRecorder env = LerobotRecorder(env=env, agent=mp_agent, shard_size=shard_size, root_dir=save_dir) else: raise NotImplementedError ``` reset the episode, plan the motion for the episode ``` observation, info = env.reset() mp_agent.synthesize() ``` loop through the episode ``` episode_over = False while not episode_over: try: action = mp_agent.get_action(observation, info) observation, reward, terminated, truncated, info = env.step(action) episode_over = terminated or truncated except Exception as e: print(f"Error during episode execution: {e}") break ``` close the environment and finalize data saving ``` env.close() ``` ## Differences from the production data generator The snippets above are a minimal, single-episode walkthrough. The shipped generator, `simple/cli/datagen.py` (installed as the `datagen` command), differs in a few ways that matter once you collect data at scale: - **Planner settings.** It uses `plan_dt=0.01` and `plan_batch_size=1`, instead of the `plan_dt=1.0/render_hz` and `plan_batch_size=40` used here. - **Multi-phase plans.** `mp_agent.synthesize()` may return `"phase_break"`, meaning the current phase must be executed before the next one can be planned. The generator loops over `synthesize()` / execute until it returns `False`; the walkthrough plans once and executes once. - **Discarding failed episodes.** When motion planning is exhausted (`StopIteration`) or the episode raises, the generator calls `env.clear_episode_buffer()` so the partial episode is not written to the dataset. The simple loop above just breaks, leaving the partial episode recorded. - **Many episodes.** The generator repeats reset/plan/execute until `num_episodes` successful episodes have been collected, calling `mp_agent.reset()` between them.