PDDL入门

PDDL的组成部分


  • Objects:对象,世界上我们感兴趣的事物。
  • Predicates:谓词,我们感兴趣的事实(例如对象的属性),可以为真,也可以为假。
  • An initial state:初始化状态,我们开始所处的世界状态,即开始时为真的事物。
  • Goal specification:目标状态,我们想要结束的世界的状态,即我们希望最终成为真实的事情。
  • Actions/Operators:动作/操作,改变世界状态的方式,即发生的事情改变了事实。

PDDL语法


PDDL 文件的扩展名通常是.pddl

要素:一份完整的PDDL程序是由domain文件和problem文件

The Domain File:域文件建立了世界的上下文。它决定了状态可以包含哪些类型的细节(Predicates),以及我们可以做什么在世界中的状态之间移动(actions)。

domain file的基础语法:

(define (domain <domain name>)
  (:predicates
    <predicate-list>
  )
  
  (:action
    <action-details>
  )
)

其中,<domain-name>是世界的名称。

The Problem File:问题文件代表着我们在域中建立一个世界的实例,它决定了在计划开始时什么是真的(初始状态),以及我们希望在计划结束时什么是真的(目标状态)。

problem file的基础语法:

(define (problem <title>)
	(:domain <domain-name>)
	(:objects
    	<object-list>
	)

	(:init
		<predicates>
	)
	(:goal 
		<predicates>
	)
)

<title>是problem file 的标题,<domain-name>是指相应域文件的名称。

Eg: Let’s Eat!


让我们想象一下,我们有一个机器人手臂,一个纸杯蛋糕和一个盘子。夹钳是空的,纸杯蛋糕在桌子上,我们想把纸杯蛋糕放在盘子上。

在我们在PDDL中对此进行建模之前,让我们先看看PDDL问题的组成部分:

  1. 首先我们定义域

(define (domain letseat) ;域名为letseat

  1. 然后我们定义objects:盘子、夹钳、纸杯蛋糕。我们还将把杯子蛋糕和夹钳标记为可定位的,稍后我们将创建一个predicate来帮助我们查询这些对象的位置。
  (:requirements :typing) ;声明typing
  (:types         
    location locatable - object ;类型定义, location locatable
		bot cupcake - locatable ;声明子类型bot和cupcake属于locatable
    robot - bot ;声明子类型robot属于bot
  )

层次图

  1. 我们还需要定义一些predicates。夹钳是空的吗?纸杯蛋糕在哪里?
  (:predicates  ; 谓词,用来定义动作
		(on ?obj - locatable ?loc - location) ;-xx属于某类型,定义谓词on:obj在loc上
		(holding ?arm - locatable ?cupcake - locatable) ;定义谓词holding:arm持有cupcake
    (arm-empty) ;定义谓词arm-empty,定义夹钳为空
    (path ?location1 - location ?location2 - location)  ;定义谓词path:locatiob1到location2的路径
  )
  1. 我们还必须定义actions/operators,我们需要能够拿起和放下纸杯蛋糕,以及在桌子和盘子之间移动手臂。
(:action pick-up  ;定义动作捡起
    :parameters ;参数arm属于bot类型,参数cupcake属于locatable类型,参数loc属于location类型
     (?arm - bot  
      ?cupcake - locatable
      ?loc - location)
    :precondition ;前提
     (and 
        (on ?arm ?loc) ;使用前面的谓词on,arm在loc上
        (on ?cupcake ?loc)  ;使用前面的谓词on,cupcake在loc上
        (arm-empty) ;使用前面的谓词arm-empty,夹钳为空
      )
    :effect ;结果
     (and 
        (not (on ?cupcake ?loc))  ;cupcake不在loc上
        (holding ?arm ?cupcake) ;arm持有cupcake
        (not (arm-empty)) ;夹钳不空
     )
  )

  (:action drop ;动作放下
    :parameters ;参数arm属于bot类型,cupcake属于locatable,loc属于location类型
     (?arm - bot
      ?cupcake - locatable
      ?loc - location)
    :precondition ;前提
     (and 
        (on ?arm ?loc)  ;arm在loc上
        (holding ?arm ?cupcake) ;arm持有cupcake
      )
    :effect ;结果
     (and 
        (on ?cupcake ?loc)  ;cupcake在loc上
        (arm-empty) ;夹钳为空
        (not (holding ?arm ?cupcake)) ;arm不再持有cupcake
     )
  )

  (:action move ;定义动作移动
    :parameters ;参数arm为bot类型,from和to为location类型
     (?arm - bot
      ?from - location
      ?to - location)
    :precondition ;前提
     (and 
      (on ?arm ?from) ;arm在from
      (path ?from ?to)  ;从from到to
     )
    :effect ;效果
     (and 
      (not (on ?arm ?from)) ; arm不在from
      (on ?arm ?to) ;arm在to
     )
  )

综合上述内容,我们就可以得到一个 domain file!

现在我们将会查看problem file。

  1. 我们首先让它知道它关联的是哪个域,定义这个世界上存在的对象。
(define (problem letseat-simple)
	(:domain letseat)	;定义problem所属的域
	(:objects	;定义对象,arm属于robot,cupcake属于cupcake,table和plate属于location
	arm - robot
	cupcake - cupcake
	table - location
	plate - location
	)
  1. 然后,我们将会定义初始化状态:夹钳是空的,纸杯蛋糕在桌子上,手臂可以在两者之间移动。
	(:init	;
		(on arm table)	;arm on table
		(on cupcake table)	;cupcake on table
		(arm-empty)	
		(path table plate)	; table path plate
	)
  1. 最后,我们定义了目标规划:纸杯蛋糕在盘子上。
	(:goal 
		(on cupcake plate)	; cupcake on plate
	)

综合上述内容,我们就可以得到一个problem file!

如果使用 OPTIC运行,你可以得到如下的解决方案:

Initial heuristic = 3
Initial stats: t=0s, 4299060kb
b (2 @ n=3, t=0s, 4300084kb)b (1 @ n=6, t=0s, 4308276kb)
;;;; Solution Found
; Time 0.00
; Peak memory 4308276kb
; Nodes Generated: 5
; Nodes Expanded:  3
; Nodes Evaluated: 6
; Nodes Tunneled:  1
; Nodes memoised with open actions: 0
; Nodes memoised without open actions: 6
; Nodes pruned by memoisation: 0
0: (pick-up arm cupcake table) [1]
1: (move arm table plate) [1]
2: (drop arm cupcake plate) [1]

练习


  • 在桌子上添加第二个蛋糕,并将其添加到目标规划中,以确保它也放在盘子上。
;这是我写的一个简单实现,能够成功将两块蛋糕都放到盘子里
(define (problem letseat-) 
(:domain letseat)
(:objects 
    arm - robot
    cupcake1 - cupcake
    cupcake2 - cupcake
    plate - location
    table - location
)

(:init
    (on arm table)
    (on cupcake1 table)
    (on cupcake2 table)
    (arm-empty)
    (path table plate)
    (path plate table)
)

(:goal (and
    (on cupcake1 plate)
    (on cupcake2 plate)
))
)
  • 在域中添加一个unicorn对象,给unicorn设定一个吃纸杯蛋糕的目标,并且unicorn只能吃盘子里的纸杯蛋糕。

复杂例子


如果你想了解一些更复杂的东西,请查看 driverlog domain

持续的动作


实际上,您可以为操作指定在时间域中工作的持续时间,每个条件和效果都被给定了它应该发生的时间。有几种类型的时间约束:
(at start (<condition/effect>))这意味着这必须是真的,或者在动作开始时发生。(at end (<condition/effect>))这意味着这必须是真的,或者在动作结束时发生。(over all (<condition>)),这意味着在整个行动期间,这必须是真的。

下面是一个(move)动作的例子,从我们前面的例子转换为持续动作。

(:durative-action move
  :duration (= ?duration 10) ; Duration goes here.
  :parameters
   (?arm - bot
    ?from - location
    ?to - location)
  :condition ; Note how this is "condition" not "pre-condition"
   (and 
    (at start (on ?arm ?from))
    (over all (path ?from ?to))
   )
  :effect
   (and 
    (at start (not (on ?arm ?from)))
    (at end (on ?arm ?to))
   )
)
posted @ 2022-07-03 21:45  哆啦哆啦呦  阅读(557)  评论(0编辑  收藏  举报