Search code examples
planningpddl

PDDL: Forall and when in action effect


I have a robot that has to transport each component present in the warehouse to the working table, this can be done only after identifying the component and only one component at time can be picked up. To align with a real context, I should "lost" the identification of the component when the robot leaves the site, while the component in the hand should remain identified.

Looking at the PDDL wiki, I found that forall cannot be used in effect, but the plan seems to work. Is the implementation of the action robot_move correct?

(:action robot_move
    :parameters (?from - site ?to - site ?c - component ?g1 - gripper ?g2 - gripper)
    :precondition (and (at-robby ?from) (different ?g1 ?g2) (or (connected ?from ?to) (connected ?to ?from)) (or (free ?g1) (free ?g2))) ; This force the robot to move only one component at time from the warehouse
    :effect(and (not (at-robby ?from)) (at-robby ?to)
                (forall (?c - component) 
                    (when (and (at ?c ?from) (identified_component ?c))
                        (not (identified_component ?c)))) ; When the robot moves from a site, the identified components are not identified anymore
                (when (or (picked_up ?c ?g1) (picked_up ?c ?g2))
                    (and (not (at ?c ?from)) (at ?c ?to) (identified_component ?c)))) ; When the robot moves the component, the component moves with it and it is identified
)

Solution

  • I think it would technically work, and you absolutely can use forall in an effect. But there are some simplifications you can make:

    (:action robot_move
    
        :parameters (?from ?to - site ?c - component ?g1 ?g2 - gripper)
    
        :precondition (and
    
          (at-robby ?from)
          (different ?g1 ?g2)
    
          ; I'd suggest defining both to avoid the or
          (or (connected ?from ?to) (connected ?to ?from)) 
    
          ; I'd suggest having just a `(holding ?c)` predicate that mirrors this -- again to avoid or
          (or (free ?g1) (free ?g2)) ; This force the robot to move only one component at time from the warehouse
    
    )
    
        :effect(and
    
          (not (at-robby ?from)) (at-robby ?to)
    
          ; When the robot moves from a site, the identified components are not identified anymore
          (forall (?c - component) (not (identified_component ?c))))
    
          ; When the robot moves the component, the component moves with it and it is identified
          (not (at ?c ?from))
          (at ?c ?to)
          (identified_component ?c)
    
    )
    

    Some notes:

    • When you have an or in a condition, it creates axioms which makes things harder to solve. Avoid if at all possible.
    • If the connected predicates never change (i.e., they're static), then define them both ways.
    • The forall just de-identifies everything, which is overwritten later.
    • Avoiding conditional effects is also good for performance, which is why you see it simplified.
    • The final effect will override the de-identification that happens in the forall -- all delete effects that are relevant (checking conditional effects) are applied, and then all add effects are applied.