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.01andplan_batch_size=1, instead of theplan_dt=1.0/render_hzandplan_batch_size=40used 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 oversynthesize()/ execute until it returnsFalse; the walkthrough plans once and executes once.Discarding failed episodes. When motion planning is exhausted (
StopIteration) or the episode raises, the generator callsenv.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_episodessuccessful episodes have been collected, callingmp_agent.reset()between them.