Using planning contracts¶
From workflow to code¶
GraspPlanningWorkflow orchestrates the processing steps shown below. It does
not evaluate or rank candidates itself.
Planning step |
Interface or component |
Request → result |
Contract status |
|---|---|---|---|
Generate grasp candidates |
implemented |
||
Check grasp collisions |
|
implemented |
|
Plan robot motion |
|
implemented |
|
Simulate motion |
|
|
planned |
Evaluate, rank, and select candidates |
|
candidates + available stage results → ranked selection; interface not yet defined |
planned |
Render grasp poses |
|
|
planned |
Render simulation video |
|
|
planned |
Here, implemented means that the interface and its data types exist in
configrip-contracts; it does not describe backend completeness.
The workflow may invoke the planned CandidateEvaluator after grasp generation,
collision checking, and simulation. This allows it to reduce the candidate set
before expensive downstream steps.
Calling a planning backend¶
The caller constructs a validated request and invokes any implementation of
GraspPlanner. One request may contain one or several concrete gripper
designs; max_candidates_per_gripper applies to each design independently.
This example shows the programmatic contract implemented by the current
GraspGenX adapter. Backend construction, model configuration, asset resolution,
and command-line usage are documented in the grasp-pose-generation tool.
from configrip_contracts import (
AssetRef,
GeometryRef,
GraspObject,
GraspPlanner,
GraspPlanningRequest,
GraspPlanningResult,
GripperRef,
)
def generate_candidates(planner: GraspPlanner) -> GraspPlanningResult:
request = GraspPlanningRequest(
object=GraspObject(
geometry=GeometryRef(
asset=AssetRef(
asset_id="objects/filigree_box",
version="1",
),
frame="input_mesh",
scale_to_metre=1.0,
)
),
grippers=(
GripperRef(
gripper_id="robotiq_2f_85",
description=AssetRef(
asset_id="grippers/x_grippers/robotiq_2f_85",
version="assets-v1",
),
),
GripperRef(
gripper_id="franka_panda",
description=AssetRef(
asset_id="grippers/x_grippers/franka_panda",
version="assets-v1",
),
),
),
max_candidates_per_gripper=10,
seed=0,
)
return planner.plan_grasps(request)
The application supplies the concrete backend without changing the calling code:
result = generate_candidates(graspgenx_adapter)
Asset identifiers and versions in this example are illustrative. The using application resolves them through its Asset Store or a local asset resolver.
Implementing a backend¶
Pydantic models validate requests and results. Protocols define the methods a backend must provide. Matching the method signature is sufficient; inheritance is not required.
from configrip_contracts import (
GraspPlanner,
GraspPlanningRequest,
GraspPlanningResult,
)
class GraspGenXAdapter:
def plan_grasps(
self, request: GraspPlanningRequest
) -> GraspPlanningResult:
# Call GraspGenX and map its output to GraspPlanningResult.
...
planner: GraspPlanner = GraspGenXAdapter()
request = GraspPlanningRequest.model_validate(input_data)
result = planner.plan_grasps(request)
Pydantic validates each model when it is created. The planner: GraspPlanner
assignment lets a type checker verify the adapter interface.