%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Programma per un robot accentratore

% Giuseppe Lipori, Fabrizio Magni, Jacopo Mantovani

% sul codice originale "delivery.pl" di H.Levesque e M.Pagnucco

% Milano, 26/06/2001

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% DECLARATIONS

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Actions

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% senses(+Action, +Fluent): Action senses the value of Fluent

senses(_,_) :-

fail. % No sensing actions

% prim_action(?Action): Action is a primitive action and it can be executed

% on the RCX

prim_action(start_to_next_station). % Go to next station following the black line

prim_action(turnaround). % Change direction

prim_action(signal_arrival). % Announce arrival at waystation

prim_action(close). % Close hands

% exog_action(?Action): Actions is an exogenous action and its occurrence

% can be reported to Golog

exog_action(arrive_at_center). % Arrive successfully at center and stop

exog_action(arrive_at_suburbs). % Arrive successfully at suburbs and stop

exog_action(stop_abnormally). % Stop because confused

exog_action(push_go_button). % Go button on robot is pushed

exog_action(push_grasp_button). % Grasp button on robot is pushed

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Fluents

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% prim_fluent(?Fluent): Fluent is a primitive fluent

prim_fluent(location). % location=center or location=suburbs

prim_fluent(motion). % Moving, stopped, or suspended (lost)

prim_fluent(delivery_requested). % Delivery request is pending

prim_fluent(holding_delivery). % Holding an object, waiting to drop it off at center

prim_fluent(next_station). % set to 1 when there is no delivery need at current suburbs location

 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Causal laws

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% causes_val(+Action, +Fluent, +Value, +Cond): When Cond holds, doing

% Action causes Fluent to have Value

 

causes_val(start_to_next_station, motion, moving, true).

causes_val(arrive_at_center, location, center, true).

causes_val(arrive_at_center, motion, stopped, true).

causes_val(arrive_at_center, delivery_requested, 1, true).

causes_val(arrive_at_center, next_station, 0, true).

causes_val(signal_arrival, holding_delivery, 0, true).

causes_val(arrive_at_suburbs, motion, stopped, true).

causes_val(arrive_at_suburbs, location, suburbs, true).

causes_val(arrive_at_suburbs, next_station, 0, true).

causes_val(stop_abnormally, motion, suspended, true).

causes_val(push_grasp_button, delivery_requested, 0, location = suburbs).

causes_val(push_grasp_button, holding_delivery, 0, location = center).

causes_val(push_grasp_button, holding_delivery, 1, delivery_requested = 1).

causes_val(push_grasp_button, next_station, 0, true).

causes_val(push_go_button, next_station, 1, true).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Preconditions of prim actions

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% poss(+Action, +Condition): When Condition is true, Action is possible

poss(turnaround, true).

poss(close, true).

poss(signal_arrival, true).

poss(start_to_next_station, motion = stopped).

poss(arrive_at_center, motion = moving).

poss(arrive_at_suburbs, motion = moving).

poss(stop_abnormally, motion = moving).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Initial state

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% initially(+Fluent, +Value): Fluent has Value at S0, the initial situation

initially(location, center).

initially(motion, stopped).

initially(delivery_requested, 1).

initially(holding_delivery, 0). % No pending dropoffs

initially(next_station, 0).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Golog PROGRAM

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Definitions of complex conditions

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% proc(+Name, +Program): A user-defined procedure called Name with

% Program body

proc(load_station(N), and(N = suburbs, delivery_requested = 1)).

proc(unload_station(N), and(N = center, holding_delivery = 1)).

% proc(next_location_to_serve(N), stop_requested(N)). % Random choice

 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Definitions of complex actions

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

 

proc(recover_position, ?(reset(location, direction))).

% reset(Location, Direction): auxiliary predicate

reset(Location,_) :-

write('**** Mi sono perso venendo da '), write(Location),nl,

write('**** Per favore posizionami al centro della stella. '), nl,

write('Premi un tasto quando sei pronto: '),

get(_).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Main Routine

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

proc(control, prioritized_interrupts(

[interrupt(motion = suspended, [recover_position, start_to_next_station]),

interrupt(motion = moving, wait),

interrupt(next_station = 1, [turnaround, start_to_next_station]),

interrupt(load_station(location), [close, signal_arrival, wait]),

interrupt(unload_station(location), [signal_arrival, turnaround]),

interrupt(location = center, start_to_next_station),

interrupt(location = suburbs, [turnaround, start_to_next_station]),

interrupt(true, wait)

])).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% HOOKS TO legorcx.pl CODE

% This section provides predicates for executing actions from the IndiGolog

% interpreter on the RCX and returning exogenous actions detected by

% the RCX to the interpreter

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% initialize: Perform any application dependent initialization

initialize :-

initializeRcx,

initializeExog.

% finalize: Application dependent wrap-up

finalize :-

finalizeRcx,

finalizeExog.

% execute(+Action, +History, -SensingResult): Execute Action on RCX returning

% SensingResult. Current action History is supplied for debugging

% purposes in case something goes wrong

execute(Action, History, SensingResult) :-

write('Executing action: '), write(Action), nl,

actionNum(Action, N),

sendRcxActionNumber(N, SensingNumber),

translateSensorValue(Action, SensingNumber, SensingResult),

write(' Sensing result: '), write(SensingResult), nl, nl,

errorRecoveryData(History).

% If previous clause fails, call user-defined debug routine.

% The debug routine can reattempt the action returning SensingResult

execute(Action, History, SensingResult) :-

debugRcx(Action, History, SensingResult).

% exog_occurs(-ExogList): Check for occurrence of exogenous actions and

% return them in list ExogList. Exogenous actions can occur at

% various sources: here we check the RCX and the keyboard

exog_occurs(ExogList) :-

checkRcxExog(RcxExogList),

(RcxExogList == [] -> true;

(write(' Rcx exogenous action: '), write(RcxExogList), nl, nl)),

checkOtherExog(OtherExogList),

(OtherExogList == [] -> true;

(write(' Other exogenous action: '), write(OtherExogList), nl, nl)),

append(RcxExogList, OtherExogList, ExogList).

% checkRcxExog(-RcxExogList): Check for occurrence of exogenous actions

% at RCX. At present RCX can only report one exogenous action at a time

checkRcxExog([Action]) :-

receiveRcxActionNumber([N]),

actionNum(Action, N),

write('Exogenous action: *'), write(Action), write('* has occurred'), nl, !.

checkRcxExog([]). % No exogenous action from RCX

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Use the following for testing independent of legorcx.pl.

% Uncomment to run.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%

%%execute(Action, _, SensingResult) :-

%% write('Executing action: '), write(Action), nl,

%% (senses(Action, _) ->

%% (write('[Enter Sensing value, terminate with "."]: '),

%% read(SensingResult));

%% nl),

%% write(' Sensing result: '), write(SensingResult), nl, nl.

%%

%%% If previous clause fails, call user-defined debug routine

%%execute(Action, History, SensingResult) :-

%% debugRcx(Action, History, SensingResult).

%%

%%% It is probably better to do this by only checking for exogenous actions

%%% from the keyboard but, if you want to go through the process slowly,

%%% do it this way!

%%

%%exog_occurs(ExogList) :-

%% write('Enter list (possibly empty) of exogenous actions: '),

%% read(TempExogList),

%% ((TempExogList = [_|_] ; TempExogList == []) ->

%% (ExogList=TempExogList,

%% write(' Exogenous actions: *'), write(ExogList),

%% write('* have occurred'), nl, nl);

%% (write('ERROR: You must enter a list (possibly empty) of actions'),nl,

%% exog_occurs(ExogList))

%% ).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Action/message mappings - numbers must correspond to NQC code

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% actionNum(?Action, ?ActionNumber): Returns ActionNumber associated

% with Action and vice versa. ActionNumber can be sent to the RCX

% for execution of Action. It can be returned from the RCX to

% report the occurrence of exogenous Action

actionNum(turnaround, 0).

actionNum(signal_arrival, 1).

actionNum(start_to_next_station, 2).

actionNum(close, 3).

actionNum(stop_abnormally, 4).

actionNum(push_grasp_button, 5).

actionNum(recover_position, 6).

actionNum(arrive_at_center, 7).

actionNum(arrive_at_suburbs, 8).

actionNum(push_go_button, 9).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Translation of sensor values from RCX

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% translateSensorValue(+Action, +SensorValue, SensingResult): Translate

% the value SensorValue returned by the RCX sensor into a legal

% SensingResult under Action

translateSensorValue(_, SensorValue, SensorValue). % Just leave it for now

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% DEBUG ROUTINES

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% debugRcx(+Action, +History, -SensingResult): The sendRcxActionNumber/2

% predicate failed (RCX panicked or there was a problem with the

% communication). This predicate attempts to provide some basic debug

% and error recovery.

% If you can't be bothered, uncomment the following clause and

% the program will abort on failure to execute an action

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%debugRcx(_, _, _) :-

%% write('ERROR: A problem was encountered while trying to execute action'),

%% nl,

%% abort.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

debugRcx(Action, History, SensingResult) :-

write('** There is a problem with the RCX. It may need to be reset.'), nl,

errorRecoveryData(History),

errorRecoveryProc,

execute(Action, History, SensingResult). % Try action again

% errorRecoveryData(+History): Extract values of primitive fluents at

% the point where Hist actions are performed.

errorRecoveryData(History) :-

write(' Actions performed so far: '),

write(History), nl,

bagof(U, prim_fluent(U), FluentList),

printFluentValues(FluentList, History).

% printFluentValues(+FluentList, +History): Print value of primitive fluents

% at the point where History actions have been performed

printFluentValues([], _) :-

write('-----------------------------------------------'),

nl.

printFluentValues([Hf | FluentList], History) :-

write(' Primitive fluent '),

write(Hf),

write(' has value '),

has_val(Hf, Hv, History),

write(Hv), nl,

printFluentValues(FluentList, History).

% errorRecoveryProc: What to do in case of error. In this case, ask the user

% to reposition the RCX so that last action can be re-attempted

errorRecoveryProc:-

write('If you wish to abort, enter "a".'), nl,

write('If you wish to continue execution, place RCX in a position'), nl,

write('consistent with these values and hit any other key.'), nl,

get0(Val),

get0(_), % Clear carriage return

(Val == 65; Val == 97) -> % 65 is ASCII 'A', 97 is ASCII 'a'

abort;

true.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% EOF: Delivery/delivery.pl

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%