Data flow: offline pools → selection → placement¶
Every task-generation pipeline runs the same four-stage flow, with pipeline-specific code only at the per-stage edges. Understanding these stages makes it easier to:
- Add a new pipeline (you mostly fill in
select_objectsandplace_objects). - Diagnose "why was this object/scene picked?" or "why isn't this container in the pool?".
- Regenerate the offline pools after asset changes or graspability re-runs.
Stage 1 — offline pool generation¶
One-time object filtering (raycasts + simulator), produces JSON files committed to the repo so runtime selection is a pure dict lookup. Mostly the objects that are going to be interacted with need to be graspable which is filtered by the graspability csv. Here are some examples with the existing pipelines:
Manual overrides¶
docs/graspability_classified.csv is the canonical readiness gate. Rows can be flipped manually (e.g. an asset marked no_grasp in the survey but geometrically valid for transport) by tagging the note column with ;manual_override. The override survives a future regeneration of the CSV because the note tag is the marker.
When CSV rows are flipped, regenerate the downstream pools:
conda activate behavior
# scan_top_full.json: extend the raycast scan for newly-graspable models
python -m maniguard.task_generation.utils.stack_pipeline.scan_top_surface \
--output scan_top_full.json --resume
# Then in dependency order:
python -m maniguard.task_generation.utils.food_transfer_pipeline.derive_container_openings
python -m maniguard.task_generation.utils.food_transfer_pipeline.build_transfer_compatibility
python -m maniguard.task_generation.utils.lid_transport_pipeline.build_lid_transport_food_compat
Stage 2 — object selection (runtime)¶
Each pipeline package has a select.py that pulls from its JSON pool. Selection is uniform-by-category, then uniform-by-model — the category-first restructure prevents categories with many models (e.g. hardback ×245) from drowning out single-model categories.
| Pipeline | Selector | Pool |
|---|---|---|
| Stack | stack_pipeline/select.select_stack_objects(mode, rng, ...) |
stack_same_pool.json / stack_flat_compatibility.json / stack_recep_compatibility.json per --stack-mode |
| Transfer | food_transfer_pipeline/... (called inline in transfer_scene_pipeline.build_transfer_objects) |
transfer_compatibility.json |
| Lid transport (food) | lid_transport_pipeline/select.select_pair_for_food(rng, ...) |
lid_transport_food_compat.json |
| Lid transport (liquid) | lid_transport_pipeline/select.select_pair_for_liquid(rng, ...) |
lid_cap_container_pairs.json (kept verdicts only) |
CLI overrides (--target-model, --item-model, --food-model, --source-model, --dest-model, …) bypass the random sampler by pinning a specific model id; the selector still validates the pin against the pool.
Stage 3 — scene + surface selection (runtime)¶
pipeline_common.pick_scene_from_placeable picks a (scene, support_object, region_of_object) triple that fits the pipeline's required_area_m2 (computed from the selected objects' footprints via estimate_object_set_footprint).
The picker reads pre-computed surface profiles from placeable_surfaces_v1.json per scene/object. Each profile is a 24×24 raycast at the placeable plane that yields connected-component regions (with area, x/y bounds, top-z) — so a 2-region desk like desk/puapey (split by a centerline divider) exposes both halves independently.
CLI pins:
| Flag | Effect |
|---|---|
--scene-model |
Restrict to a single scene. |
--surface-category |
Require the support's BEHAVIOR category (e.g. countertop, breakfast_table). |
--surface-model |
Pin the support's asset model id. Picker still chooses the region within the model based on required_area_m2. |
Output of the picker becomes args._picked_surface = {"scene_model", "category", "model", "instance_name", "room", region geometry, top_plane_z_local, ...}.
Stage 4 — placement (runtime)¶
BasePipeline._setup_session orchestrates placement in this order:
env.reset()— load the picked scene from its snapshot. Partial-room load (load_room_instances=[...]) is used by default for speed, except when GPU dynamics is on (PhysX articulation pool sized to the partial scene crashes when new task objects are spawned).- Build task-object configs upfront for ALL episodes via
build_task_object_cfgs(intocfg["objects"], spawned at env load), with episode-labelled inst_ids likebowl_ep1_1, and role-prefixed object names liketarget_bowl_ep1_1/fragile_cup_ep1_2so downstream code can filter task objects by role); ep > 0 are parked atz = −100. Spec-levelabilitiesare merged INTO the BEHAVIOR taxonomy abilities (not replacing). - Find the support object by
(category, model)from the picked surface; pin to world. clear_support_arearemoves non-structural scene props overlapping the picked region + a margin. Excludes the support, spawned task objects, andenv.robots(the FrankaMounted at world origin would otherwise be deleted in scenes where the surface is near origin).identify_objects+place_objects(pipeline-specific). The shared placement primitives are:_upright_half_height(obj)— orientation-independent Z extent fromnative_bbox * scale(avoidsaabb's shrinkage when the object is tilted).- Gap-aware X offset for paired objects (container + lid/cap) so wide pairs don't interpenetrate.
food_transfer_pipeline.lookup.container_drop_xy(obj)— applies the offline-derived AABB-relative cavity-opening offset (fromcontainer_openings.json) to the live AABB center, so food drops above the actual opening (e.g. jug spout offset+7.9 cm Y) rather than the AABB center.place_food_on_source(env, food, source)— drop just above source rim, settle 60 sim steps so gravity actually descends the food into the cavity.
place_franka_edge_alignedpicks a table edge for the robot mount (collision-checked against scene + spawned objects), thenclear_robot_base_regionclears any preset props in the keepout zone (also excludesenv.robots).set_position_orientationmoves the FrankaMounted to the chosen edge pose atfloor_z; gripper at home pose.
Per-episode work between rollouts is just teleporting the next episode's objects from their park position onto the surface — no scene mutations during the run, sidestepping OG's registry-staleness on objects added while the sim is playing.
See also¶
- Clutter pickup, Stack retrieve, Food transfer, Lid transport — per-pipeline pages document the specific selection / placement code for that family.
- Architecture overview — repo layout + LTL safety system.