Task Planning

This tutorial is devoted to illustrate the Planning Domain Definition Language (PDDL) as a tool to describe task planning problems.

This tutorial is partially based on the course Planning Domains and Problem Instances in PDDL.

It has the following sections:

PDDL Basics

PDDL, the Planning Domain Definition Language, was developed with the aim of generating a standard to replace or augment a variety of existing planning domain and problem description languages. It was created mainly to make a series of International Planning Competitions possible.

A PDDL definition consists of two parts: The domain definition and the problem definition, usually set in separate files, using a Lisp-like syntax.

General Syntax of PDDL

The main key points of the PDDL syntax are:

  • Parentheses everywhere

    Every construct is enclosed in ( and ). Example:

    (at robot1 roomA)
    
  • Atoms and symbols

    Inside parentheses you will find:

    • symbols (e.g., at, robot1, roomA)

    • keywords (e.g., :action, :parameters)

    • nested expressions (other parentheses inside)

  • Case insensitivity

    Domain and problem names are usually lowercase, but technically (Robot1) is the same as (robot1).

  • Top-level form

    A file always starts with (define ...), followed by either domain or problem.

    Example:

    (define (domain mydomain)
       ...
    )
    
  • Keywords with colons

    Section headers begin with a colon (e.g., :requirements, :types, :predicates, :action).

  • Indentation

    Whitespace and newlines are ignored by the parser, but indentation improves readability.

  • Variables

    Variables start with a question mark, e.g. ?r.

    Types can be specified using -:

    (at ?r - robot ?l - location)
    
  • Logical connectives

    Preconditions and effects often use logical operators such as:

    • and (conjunction)

    • or (disjunction)

    • not (negation)

    Example:

    (and (at ?r ?from) (connected ?from ?to))
    
  • Comments

    Everything after a semicolon is ignored.

    ; this is a comment
    (at robot1 roomA)
    

    Two semicolons are also used for more structured or aligned comments, like explaining blocks of code.

The Domain file

The Domain file defines the general rules of a planning problem: what can exist and what actions are possible.

The main components of a domain file are:

i.e. the skeleton of domain files is:

(define (domain <domain-name>)

  ;; Requirements
  (:requirements )

  ;; Types
  (:types
     )

  ;; Predicates
  (:predicates
     )

  ;; Actions
  (:action <action-name>
    :parameters ()
    :precondition ()
    :effect ()
  )
)

1. Header: name and requirements

The header declares the domain’s name and the PDDL features used for the domain description, e.g.:

  • :strips: The domain uses the most basic subset of PDDL, consisting only of STRIPS (see A Pure STRIPS Domain example).

  • :equality: The domain uses the predicate =, interpreted as equality.

  • :typing: The domain uses types (see 2. Types).

  • :adl: The domain uses some or all of ADL, i.e. disjunctions and quantifiers in preconditions and goals, and quantified and conditional effects (see An ADL Domain example).

The syntax of the header is the following (elements in square brackets are optional):

(define (domain DOMAIN_NAME)
     (:requirements [:strips] [:equality] [:typing] [:adl] ...)

2. Types

Types define categories or classes of objects that exist in in the domain, e.g.:

(:types robot room object)

Types:

  • Avoid confusion: They help the planner know which actions apply to which objects (like trying a key to “walk into a room”)

  • Make your domain cleaner: Instead of checking manually in every action if the object is the right kind, you define it once using types.

  • Speed up planning: The planner does not have to consider invalid combinations (like trying to move a room into another room).

3. Predicates

Predicates are logical statements that describe the state of the world. They can be true or false at any given time.

(:predicates
  (robot_at ?r - robot ?ro - room)   ; true when robot ?r is located in room ?ro
  (hand_empty ?r - robot)            ; true when robot ?r is not carrying anything
  (object_at ?o - object ?ro - room) ; true when object ?o is located in room ?ro
)

Example: (robot_at tiago entrance) means the robot Tiago is at the entrance.

4. Actions

Each action specifies how the world can change. It consists of:

  • Parameters: the objects involved in the action

  • Preconditions: what must be true before the action

  • Effects: how the world changes after the action

;; robot ?r moves from room ?ro1 to room ?ro2
(:action move
   :parameters (?r - robot ?ro1 - room ?ro2 - room)
   :precondition (and
     (connected ?ro1 ?ro2) ; rooms ?ro1 and ?ro2 must be connected
     (robot_at ?r ?ro1)    ; robot ?r must currently be in room ?ro1
   )
   :effect (and
     (not (robot_at ?r ?ro1)) ; robot is no longer in room ?ro1
     (robot_at ?r ?ro2)       ; robot is now in room ?ro2
   )
 )

This example means that a robot can move from ro1 to ro2 if:

  • The rooms are connected

  • The robot is currently at ro1

After moving, the robot will no longer be at ro1 but will be at ro2.

A Pure STRIPS Domain example

The PDDL subset consisting only of STRIPS (sometimes called basic STRIPS PDDL) is the simplest form of PDDL. It includes:

  • Objects (but without types, unless :typing is declared)

  • Predicates to describe the world

  • Actions with preconditions and effects

It does not allow advanced features like:

  • Equality (=)

  • Negative preconditions

  • Disjunctions (OR) in preconditions

  • Conditional or quantified effects

  • Numeric fluents

(define (domain move-blocks)
(:requirements :strips)

(:predicates
    (on ?x ?y)
    (ontable ?x)
    (clear ?x)
    (holding ?x)
    (handempty)
)

(:action pick-up
    :parameters (?x)
    :precondition (and (clear ?x) (ontable ?x) (handempty))
    :effect (and (holding ?x)
                (not (ontable ?x))
                (not (clear ?x))
                (not (handempty)))
)

(:action put-down
    :parameters (?x)
    :precondition (holding ?x)
    :effect (and (ontable ?x)
                (clear ?x)
                (handempty)
                (not (holding ?x))))
)

An ADL Domain example

ADL stands for Action Description Language, which extends basic STRIPS PDDL with more expressive power. It allows you to write more complex preconditions and effects than STRIPS.

Compared to STRIPS, ADL supports:

  • Typing: restrict parameters to specific types.

  • Equality: use of = and not (= …) in conditions.

  • Negative preconditions: e.g., (not (holding ?x)).

  • Disjunctive preconditions: (or (condition1) (condition2)).

  • Quantified preconditions and effects: (forall …) and (exists …).

  • Conditional effects: (when condition effect).

(define (domain move-blocks-adl)
    (:requirements :typing :equality :adl)

    (:types block table)     ; use of types

    (:predicates
        (on ?x - block ?y - block)
        (ontable ?x - block)
        (clear ?x - block)
        (holding ?x - block)
        (handempty)
        (manipulated ?x - block)
    )

    (:action stack
        :parameters (?x - block ?y - block)
        :precondition (and
          (holding ?x)
          (clear ?y)
          (not (= ?x ?y))        ; equality usage
        )
        :effect (and
          (on ?x ?y)
          (clear ?x)
          (handempty)
          (not (holding ?x))
          (when (not (manipulated ?y)) ; conditional effect
                (manipulated ?y))
        )
    )

    (:action other_actions
      ...
    )
    ...
)

This example illustrated the use of some of the ADL features, in particular:

  • Typing (?x - block)

  • Equality/Inequality ((not (= ?x ?y)))

  • Negative preconditions

  • Conditional effects (when …)

Note that, even though ADL supports typing and equality, the planner will not assume you are using them unless you declare it clearly in the :requirements.

The problem file

A Problem file in PDDL describes a specific planning instance within a domain.

A PDDL problem file describes a specific planning instance within a domain. It provides the objects, the initial state, and the goal state for the planning task. Its main sections are:

i.e. the skeleton of problem files is:

(define (problem PROBLEM_NAME)
  (:domain DOMAIN_NAME)

  (:objects
    ...
  )

  (:init
    ...
  )

  (:goal
    ...
  )
)

1. Header: name and domain

(define (problem PROBLEM_NAME)
  (:domain DOMAIN_NAME)

The header declares the name of the problem and links it to the domain in which it is defined.

2. Objects

(:objects
  block1 block2 - block
  table1 - table
)

This section lists all the objects present in the problem instance, optionally grouped by type (if :typing is enabled in the domain).

3. Initial State

(:init
  (ontable block1)
  (ontable block2)
  (clear block1)
  (clear block2)
  (handempty)
)

The :init section specifies which predicates are true at the start of the planning problem. Any predicate not listed here is assumed to be false (closed-world assumption!).

Note that the :init section is just a list of facts that are true in the initial state; it is not a logical formula so there is no need to wrap it in (and ...).

4. Goal State

(:goal
  (and
    (on block1 block2)
    (on block2 table1)
  )
)

The :goal section describes the conditions that must hold for the problem to be solved. Typically, this is an and of several predicates (the :goal is a logical formula, in contrast to :init), but ADL allows more complex goals such as disjunctions or quantified conditions, e.g.:

(:goal
  (and
    ;; Robot r1 must be in room1 OR room2
    (or
      (robot_at r1 room1)
      (robot_at r1 room2)
    )

    ;; There must exist some object in room1
    (exists (?o - object)
      (object_at ?o room1)
    )

    ;; All robots must have their hands empty
    (forall (?r - robot)
      (hand_empty ?r)
    )
  )
)

Example

An example of a problem file using the blocks-world domain could be:

(define (problem simple-blocks-prob)
     (:domain move-blocks)

     (:objects
         block1 block2 - block
         table1 - table
     )

     (:init
         (ontable block1)
         (ontable block2)
         (clear block1)
         (clear block2)
         (handempty)
     )

     (:goal
         (and
           (on block1 block2)
           (on block2 table1)
         )
     )
 )

PDDL web tools

Fast-Downward Planning on the Web

A PDDL web editor with the Fast Downward solver. It is part of the Fast Downward project.

Link: Fast-Downward Planning on the Web

The PDDL Editor

A PDDL web editor with several available solvers. It is part of the planning.domains project.

Link: PDDL editor

Exercise

Task Statement

The Tiago mobile manipulator operates in a three-room apartment consisting of three rooms:

  • entrance

  • dining

  • bedroom

The rooms are connected as follows:

  • The entrance is connected to the dining room.

  • The dining room is connected to both the entrance and the bedroom.

The Tiago duty is to tide the apartment by collecting the toys and place them in the bedroom.

Initially, Tiago is at the entrance, and there are two toys: toy1 is located in the entrance and toy2 in the dining room.

Tiago can:

  • Move between any two directly connected rooms.

  • Pick an object if the object is in the same room, and Tiago’s hand is empty.

  • Place an object in the room it is currently in if the object is attached to it (i.e., it is holding it).

Tiago can carry only one object at a time, and there are no restrictions on the order in which the toys are moved.

Create a plan for Tiago to:

  1. Navigate through the apartment,

  2. Pick up each toy, one at a time,

  3. Move them to the bedroom, and

  4. Place them there to satisfy the goal condition.

Solution: PDDL Domain file

(define (domain tiago_dom_simple)
  (:requirements :strips :typing )

  (:types
    robot
    room
    object
  )

  (:predicates
    ;robot
    (robot_at ?r - robot ?ro - room)
    (hand_empty ?r - robot)

    ;scenario
    (connected ?ro1 - room ?ro2 - room)

    ;objects
    (object_at ?o - object ?ro - room)
    (attached ?o - object ?r - robot)
  )

  (:action move
    :parameters (?r - robot ?ro1 - room ?ro2 - room)
    :precondition (and
      (connected ?ro1 ?ro2)
      (robot_at ?r ?ro1)
    )
    :effect (and
      (not (robot_at ?r ?ro1))
      (robot_at ?r ?ro2)
    )
  )

  (:action pick
    :parameters (?r - robot ?o - object ?ro - room)
    :precondition  (and
      (hand_empty ?r)
      (object_at ?o ?ro)
      (robot_at ?r ?ro)
    )
    :effect (and
      (attached ?o ?r)
      (not (object_at ?o ?ro))
      (not (hand_empty ?r))
    )
  )

  (:action place
    :parameters (?r - robot ?o - object ?ro - room)
    :precondition (and
      (attached ?o ?r)
      (robot_at ?r ?ro)
    )
    :effect (and
      (not (attached ?o ?r))
      (object_at ?o ?ro)
      (hand_empty ?r)
    )
  )
)

Solution: PDDL problem file

(define (problem tiago_prob_simple)
  (:domain tiago_dom_simple)

  (:objects
    tiago - robot
    entrance dining bedroom - room
    toy1 toy2 - object
  )

  (:init
    (connected entrance dining)
    (connected dining entrance)

    (connected bedroom dining)
    (connected dining bedroom)

    (robot_at tiago entrance)
    (hand_empty tiago)

    (object_at toy1 entrance)
    (object_at toy2 dining)
  )

  (:goal
    (and (object_at toy1 bedroom)
        (object_at toy2 bedroom)
    )
  )
)

Proposed exercise

  1. Use the Fast-Downward Planning on the Web tool to find the solution plan.

  2. Consider now that the Tiago robot has been equipped with a second arm, which allows it to pick up big objects. Modify the domain to include different types of objects (big/small) and add the dual_pick and dual_place actions. Create a problem file to illustrate the new domain.