Skip to content

Define composable state sets for starts, goals, and path constraints #17

Description

@siddhss5

Motivation

CBiRRT is naturally a planner between sets. Let $\mathcal{Q}$ be the configuration space, $\mathcal{S} \subseteq \mathcal{Q}$ the start set, $\mathcal{G} \subseteq \mathcal{Q}$ the goal set, and $\mathcal{C} \subseteq \mathcal{Q}$ the path-admissible set. The planning problem is to find a continuous path $\tau : [0,1] \to \mathcal{Q}$ such that

$$\tau(0) \in \mathcal{S}, \qquad \tau(1) \in \mathcal{G}, \qquad \tau(t) \in \mathcal{C} \quad \forall t \in [0,1].$$

The current API represents these sets through separate arguments such as fixed configurations, start_tsrs, goal_tsrs, and constraint_tsrs. Their composition semantics are implicit and depend on the argument:

  • multiple start or goal TSRs are treated as a union;
  • multiple path-constraint TSRs are treated as an intersection;
  • projection onto an intersection greedily chooses the most violated TSR.

This makes a Python list carry different mathematical meanings in different places. It also conflates the definition of a set with one particular way of sampling or projecting onto it. In particular, projecting onto the most violated TSR is a heuristic for an intersection, not an operation proposed by CBiRRT or implied by the definition of an intersection.

The original CBiRRT paper separates the bidirectional search from a problem-specific ConstrainConfig operation. The later CBiRRT2 formulation further distinguishes direct sampling, projection, and rejection as different constraint-satisfaction strategies. We should make this latent structure explicit before adding TSR chains or more general constraint representations.

References:

Proposal

1. Give sets a minimal semantic interface

A state set should first define only membership:

class StateSet(Protocol):
    def contains(self, q: np.ndarray) -> bool: ...

Fixed configurations, finite collections of configurations, predicates, and TSR-induced configuration sets should all be representable through this abstraction.

A TSR is a set in task space. It induces a configuration-space set through forward kinematics:

$$\mathcal{C}_{\mathrm{TSR}} = \{q \in \mathcal{Q} \mid \mathrm{FK}(q) \in \mathrm{TSR}\}.$$

The planner should consume an adapter for this induced set rather than branch on the concrete TSR type.

2. Make Boolean composition explicit

Introduce explicit set constructors with arbitrary nesting:

AnyOf([set_a, set_b])  # union
AllOf([set_a, set_b])  # intersection

Their membership semantics are:

$$q \in \mathrm{AnyOf}(C_i) \iff \exists i : q \in C_i,$$ $$q \in \mathrm{AllOf}(C_i) \iff \forall i : q \in C_i.$$

Nesting must preserve grouping. For example,

$$(L_1 \land R_1) \lor (L_2 \land R_2)$$

describes two matched bimanual grasps, whereas

$$(L_1 \lor L_2) \land (R_1 \lor R_2)$$

allows all four pairings.

We should not add complement/Not initially. Exclusion constraints such as collision are better handled by state and motion validators, and complements generally do not provide useful sampling or projection operations.

3. Separate set semantics from planner capabilities

Sampling, distance or violation evaluation, projection, and motion validation are operations associated with a set, not part of the definition of a set. They should be represented as separate optional capabilities, for example:

class SetSampler(Protocol):
    def sample(self, rng: np.random.Generator) -> np.ndarray | None: ...

class SetProjector(Protocol):
    def project(
        self,
        q_previous: np.ndarray,
        q_proposed: np.ndarray,
    ) -> np.ndarray | None: ...

class MotionValidator(Protocol):
    def is_valid_motion(self, q1: np.ndarray, q2: np.ndarray) -> bool: ...

The exact Python organization can be decided during implementation. The required semantic distinction is:

  • a finite set may be directly sampleable but need no projector;
  • a collision-free set supports rejection and edge validation but generally no projection;
  • a TSR-induced set can support membership, pose sampling, distance evaluation, and IK-based projection;
  • an implicit equality constraint may support projection without direct sampling;
  • an arbitrary predicate may support only membership.

Composition of capabilities must also be explicit:

  • an AnyOf sampler needs a stated mixture policy;
  • an AnyOf projector may try children and choose a successful nearby result;
  • a single-child AllOf or AnyOf delegates its capabilities to that child and needs no strategy;
  • an AllOf projector with two or more children generally requires a joint projection strategy;
  • alternating projection or projection onto the most violated child may be provided as named heuristics, but must not be silently implied by AllOf.

4. Express planner inputs in terms of roles

The internal planning problem should distinguish the role a set plays without changing what a set means:

PlanningProblem(
    state_space=...,
    start=...,
    goal=...,
    path_constraint=...,
    motion_validator=...,
)

CBiRRT can then declare the capabilities it requires from each role:

  • roots or a sampler for the start and goal sets;
  • projection or rejection for the path-admissible set;
  • state and full-edge validation for every local extension;
  • distance and interpolation supplied by the state space.

The existing plan(...) API should initially remain available and lower its arguments into this representation. This issue should not require a public breaking change.

Representative compositions

A bimanual goal with two matched grasp strategies:

AnyOf([
    AllOf([left_grasp_1, right_grasp_1]),
    AllOf([left_grasp_2, right_grasp_2]),
])

The heavy-object example from the CBiRRT paper is approximately:

$$\mathrm{Upright} \cap \left( \mathrm{Liftable} \cup \bigcup_i (\mathrm{OnSurface}_i \cap \mathrm{TorqueValid}_i) \right).$$

These examples show why both composition operators and their nesting are part of the core problem representation rather than planner-specific conveniences.

Acceptance criteria

  • Add a short design document defining the state space, start set, goal set, path-admissible set, membership, and composition semantics.
  • Define a minimal configuration-set abstraction whose core semantic operation is membership.
  • Implement explicit AnyOf and AllOf composition with arbitrary nesting.
  • Keep sampling, projection, violation/distance evaluation, and motion validation as distinct capabilities or strategies.
  • Add adapters for finite configuration sets and TSR-induced configuration sets.
  • Preserve the existing plan(...) entry point by lowering legacy inputs into the new representation.
  • Do not silently provide a generic AllOf projector for two or more children. A single-child AllOf delegates projection to that child. Multi-child intersections require an explicit joint or named heuristic projection strategy.
  • Give membership tolerance, projection progress tolerance, tree-connection tolerance, and edge-checking resolution distinct meanings.
  • Add tests for union, intersection, nested grouping, unsupported capabilities, and TSRs with non-identity T0_w and Tw_e frames.
  • Add at least one planning test whose goal is an AnyOf of alternatives and one whose path constraint is an AllOf composition.
  • Document the relationship between this abstraction and TSR chains in Support TSR chains for multi-link pose constraints #7. A TSR chain defines one pose set through kinematic composition; it is not an AllOf of its constituent TSRs.

Non-goals

  • Extracting a general ssplanning package.
  • Rewriting CBiRRT in C++.
  • Integrating OMPL or RoboPlan.
  • Implementing TSR chains as part of this issue.
  • Supporting arbitrary Boolean negation.
  • Claiming that every composed set is sampleable or projectable.

The purpose of this issue is to establish a precise and testable problem representation inside pycbirrt. Broader extraction should be considered only after this interface has been exercised by the existing planner.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions