/* APPENDIX B Section B.4 A Coffee Delivery Robot. */ :- set_flag(all_dynamic, on). :- dynamic(proc/2). /* A Coffee Delivery Robot */ /* GOLOG Procedures */ /* The coffee serving procedures serve(T) and serveOneCoffee(T) (written in regular Golog) below deliver coffee to all people who can be served in time. serve(T) terminates when there does NOT exist a person who can be served in his/her preferable time. The termination is conditioned only upon temporal inequalities. The procedure timeGoal expresses this termination condition in regular Golog. */ proc(timeGoal, pi(t, ?(now(t)) : pi(rloc, ?(robotLocation(rloc)) : ?(-some(p, some(t1, some(t2, some(travTime1, some(travTime2, some(wait, wantsCoffee(p,t1,t2) & -hasCoffee(p) & wait $>= 0 & travelTime(rloc,cm,travTime1) & travelTime(cm,office(p),travTime2) & t1 $<= t + wait + travTime1 + travTime2 & t + wait + travTime1 + travTime2 $<= t2 ))))))))) ). proc(serve(T), timeGoal # if( holdingCoffee, serveOneCoffeeNew(T), goto(cm,T) : pi(t, ?(now(t)) : pickupCoffee(t) : serveOneCoffee(t) ) ) ). proc(serveOneCoffee(T), pi(p, pi(wait, pi(t1, pi(t2, pi(travTime, pi(rloc, pi(currTime, ?(wantsCoffee(p,t1,t2) & -hasCoffee(p) & (wait $>= 0) & now(currTime) & robotLocation(rloc) & travelTime(rloc,office(p),travTime) & t1 $<= T + wait + travTime & T + wait + travTime $<= t2) ))))) : pi(t, ?(t $= T + wait) : goto(office(p),t)) ) : pi(t, ?(now(t)) : giveCoffee(p,t) ) ) : pi(t, ?(now(t)) : serve(t)) ). goal(s0). goal(do(A,S)) :- A \= giveCoffee(P,T), goal(S). goal(do(A,S)) :- A = giveCoffee(P,T), pref(do(A,S),S,s0), goal(S). proc(visit1, goto(office(mary),1) : pi(t1, ?(now(t1)) : ( (goto(cm,t1) : pi(t2, ?(now(t2)) : goto(office(sue),t2))) # (goto(cm,t1) : pi(t2, ?(now(t2)) : goto(office(bill),t2))) ) ) : pi(t, ?(now(t)) : ?(t $< 40)) ). proc(visit2, pi(p, pi(t1, pi(t2, ?(-hasCoffee(p) & wantsCoffee(p,t1,t2)) : goto(cm,91) : pi(t, ?(now(t)) : pickupCoffee(t)) : pi(t, ?(now(t)) : goto(office(p),t)) : pi(t, ?(now(t)) : ?(t $<= t2) ) ))) ). proc(goto(L,T), pi(rloc,?(robotLocation(rloc)) : pi(deltat,?(travelTime(rloc,L,deltat)) : goBetween(rloc,L,deltat,T)))). proc(goBetween(Loc1,Loc2,Delta,T), ?(Loc1=Loc2 & Delta=0) # ?(-(Loc1=Loc2) & Delta > 0) : startGo(Loc1,Loc2,T) : pi(t, ?(t $= T + Delta) : endGo(Loc1,Loc2,t)) ). /* Preconditions for Primitive Actions */ poss(pickupCoffee(T),S) :- not holdingCoffee(S), robotLocation(cm,S), start(S,TS), TS $<= T. poss(giveCoffee(Person,T),S) :- holdingCoffee(S), robotLocation(office(Person),S), start(S,TS), TS $<= T. poss(startGo(Loc1,Loc2,T),S) :- not going(L,LL,S), robotLocation(Loc1,S), start(S,TS), TS $<= T. poss(endGo(Loc1,Loc2,T),S) :- going(Loc1,Loc2,S), start(S,TS), TS $<= T. /* Successor State Axioms */ hasCoffee(Person,do(A,S)) :- A = giveCoffee(Person,T) ; hasCoffee(Person,S). robotLocation(Loc,do(A,S)) :- A = endGo(Loc1,Loc,T) ; ( robotLocation(Loc,S), not A = endGo(Loc2,Loc3,T) ). going(Loc1,Loc2,do(A,S)) :- A = startGo(Loc1,Loc2,T) ; (going(Loc1,Loc2,S), not A = endGo(Loc1,Loc2,T)). holdingCoffee(do(A,S)) :- A = pickupCoffee(T) ; (holdingCoffee(S), not A = giveCoffee(Person,T)). util(0, s0). util(V2, do(giveCoffee(Person,T),S)) :- util(V, S), wantsCoffee(Person,T1,T2), not hasCoffee(Person,S), V1 $<= (T2 - T)/2, V1 $<= T - (3*T1 - T2)/2, V2 $= V + V1. util(V, do(A,S)) :- A \=giveCoffee(P,T), util(V, S). /* The time of an action occurrence is its last argument. */ time(pickupCoffee(T),T). time(giveCoffee(Person,T),T). time(startGo(Loc1,Loc2,T),T). time(endGo(Loc1,Loc2,T),T). /* Restore situation arguments to fluents. */ restoreSitArg(robotLocation(Rloc),S,robotLocation(Rloc,S)). restoreSitArg(hasCoffee(Person),S,hasCoffee(Person,S)). restoreSitArg(going(Loc1,Loc2),S,going(Loc1,Loc2,S)). restoreSitArg(holdingCoffee,S,holdingCoffee(S)). restoreSitArg(goal,S,goal(S)). /* Primitive Action Declarations */ primitive_action(pickupCoffee(T)). primitive_action(giveCoffee(Person,T)). primitive_action(startGo(Loc1,Loc2,T)). primitive_action(endGo(Loc1,Loc2,T)). /* Initial Situation. */ robotLocation(park,s0). start(s0, 0). wantsCoffee( lounge, 600, 700 ). % (3*660 - 740)/2 = 620 wantsCoffee( ray, 360, 440 ). % (3*460 - 540/2 = 420 wantsCoffee( yves, 160, 240 ). % (3*220 - 320)/2 = 170 travelTime(L,L,0). travelTime(L1,L2,T) :- travelTime0(L1,L2,T) ; travelTime0(L2,L1,T). /* --- TABLE OF AVERAGE TRAVEL TIME FROM cm --- -----------RAY 75 (51, 72 cm->ray; 56, 55 ray->cm) | +-------------- | | +--ITRC 24 CM--+ | | | +--VISITOR 40 | LOUNGE-+ 58 (cm->lounge), 63 (lounge->cm) | ------+-------------------- */ travelTime0( park, cm, 100 ). /* 73, 82 on simulator */ travelTime0( cm, office(ray), 120 ). /* 51,72,56,55 on simulator*/ travelTime0( cm, office(itrc), 30 ). /* 24 on simulator */ travelTime0( cm, office(yves), 45 ). /* 29 on simulator */ travelTime0( cm, office(lounge), 75 ). /* 58, 63 on simulator */ /* Other travel times (measured on simulator): */ travelTime0( office(ray), office(itrc), 70 ). travelTime0( office(ray), office(yves), 120 ). travelTime0( office(ray), office(lounge), 120 ). travelTime0( office(lounge), office(itrc), 70 ). travelTime0( office(lounge), office(yves), 60 ). travelTime0( office(yves), office(itrc), 50 ). travelTime0( park, office(yves), 60 ). /* Geometric coordinates on the real office map. */ /* office(ray)= (3753.4, 1800) cm= (2675, 2555) park= (118, 2487) */ drivePath( cm, office(lounge), [ ( 840, 2560 ), ( 770, 2530 ) ] ). drivePath( cm, office(yves), [ ( 1620, 2500 ) ] ). drivePath( cm, office(ray), [ (3535, 2490 ), (3760, 2480), ( 3770, 1770 ) ] ). drivePath( office(ray), cm, [ ( 3760, 2420 ), (3560, 2500 ), ( 2820, 2560 ), ( 2690, 2550 ) ] ). drivePath( park, cm, [ ( 2685, 2500 ), ( 2700, 2550 ) ] ). drivePath( office(yves), cm, [ ( 3120, 2450 ), ( 2700, 2550 ) ] ). drivePath( _, cm, [ ( 2700, 2550 ) ] ). drivePath( office(yves), office(ray), [ ( 3120, 2450 ), (3535, 2490 ), (3760, 2480), ( 3770, 1770 ) ] ). drivePath( office(ray), office(lounge), [ ( 3760, 2420 ), (3560, 2480 ), ( 840, 2560 ), ( 770, 2530 ) ] ). drivePath( X, Z, BigList) :- drivePath( X, Y, List1), drivePath( Y, Z, List2), append(List1, List2, BigList). driveSim( StartPos, EndPos ) :- nl, write("drive, drive, drive from "), write(StartPos), write(" to "), write(EndPos), nl. /* Drive in the corridor and turn to the goal location */ driveReal( StartPos, EndPos ) :- drivePath( StartPos, EndPos, Path ), % get path hli_go_path( Path ), % drive, drive... look( EndPos, X, Y ), % get aim point for turning hli_turn_to_point( X, Y ). % and turn the robot look( office(lounge), 640, 2670 ). look( office(yves), 1600, 2180 ). look( cm, 2720, 2720 ). look( office(itrc), 2872, 2200 ). look( office(ray), 3728, 1650 ).