%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 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
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%