1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2% 3% FILE : Env/env_rcx.pl 4% 5% AUTHOR : Sebastian Sardina (2002) 6% EMAIL : ssardina@cs.toronto.edu 7% WWW : www.cs.toronto.edu/~ssardina www.cs.toronto.edu/cogrobo 8% TYPE : system dependent predicates (uses event_after to query RCX) 9% TESTED : ECLiPSe 5.3 on RedHat Linux 6.2-8.0 10% 11% This files provides the environment for working with the RCX. 12% An event-after event is used to talk to the RCX every some number of 13% seconds. At each talk, if there is an action pending to be executed 14% (to_execute/3), such action is sent to the RCX. Otherwise, the RCX is 15% queried for an occurred exogenous action. 16% 17% This environment is self-contained (automatically it loads the required 18% libraries). It should be called as follows: 19% 20% eclipse host=<HOST> port=<PORT> -b env_rcx.pl -e start 21% 22% where HOST/PORT is the address of the environment manager socket. 23% 24% 25% Written for ECLiPSe Prolog (http://www.icparc.ic.ac.uk/eclipse/) 26% running under Linux 6.2-7.2-8.0 27%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 28% 29% November 15, 2002 30% 31% This software was developed by the Cognitive Robotics Group under the 32% direction of Hector Levesque and Ray Reiter. 33% 34% Do not distribute without permission. 35% Include this notice in any copy made. 36% 37% 38% Copyright (c) 2000 by The University of Toronto, 39% Toronto, Ontario, Canada. 40% 41% All Rights Reserved 42% 43% Permission to use, copy, and modify, this software and its 44% documentation for non-commercial research purpose is hereby granted 45% without fee, provided that the above copyright notice appears in all 46% copies and that both the copyright notice and this permission notice 47% appear in supporting documentation, and that the name of The University 48% of Toronto not be used in advertising or publicity pertaining to 49% distribution of the software without specific, written prior 50% permission. The University of Toronto makes no representations about 51% the suitability of this software for any purpose. It is provided "as 52% is" without express or implied warranty. 53% 54% THE UNIVERSITY OF TORONTO DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 55% SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 56% FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF TORONTO BE LIABLE FOR ANY 57% SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 58% RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF 59% CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 60% CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 61% 62%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 63% 64% This file assumes that the following is defined in env_gen.pl: 65% 66% -- start/0 : initialization of the environment (called when loaded) 67% -- finalize/0 : finalization of the environment (called when exiting) 68% -- main_dir/1 : obtain the root IndiGolog directory 69% -- report_exog_event(A, M): 70% report exogenous event A with message M to the 71% environment manager 72% 73% -- All compatibility libraries depending on the architecture such us: 74% -- compat_swi/compat_ecl compatibility libraries providing: 75% 76% -- The following two dynamic predicates should be available: 77% 78% -- listen_to(Type, Name, Channel) 79% listen to Channel of Type (stream/socket) with Name 80% -- terminate/0 81% order the termination of the application 82% 83% 84% -- The following should be implemented here: 85% 86% -- name_dev/1 : mandatory * 87% -- initializeInterfaces(L) : mandatory * 88% -- finalizeInterfaces(L) : mandatory * 89% -- execute/4 : mandatory * 90% -- handle_steam/1 : as needed 91% -- listen_to/3 : as needed 92% 93%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 94:- include(env_gen). % INCLUDE THE CORE OF THE DEVICE MANAGER 95 96% Consult Lego low-level subsystem manager 97% This file is in charge of the actual communication with the RCX brick 98:- use_module(rcx_ecl). 99 100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 101% CONSTANTS TO BE USED 102% 103% name_dev/1 : state the name of the device manager (e.g., simulator, rcx) 104%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 105% This predicate is used to state that an action should be executed 106% whenever possible. 107:- dynamic to_execute/3. 108 109% Name of the environment: <RCX> 110% Set name of the environment here. 111% THIS CONSTANT IS MANDATORY, DO NOT DELETE! 112name_dev(rcx). 113 114% Set verbose debug level 115:- set_debug_level(1). 116 117 118% No of times we should retry when sending an action order to the RCX 119noTries(10). 120 121% Frequency to trigger a new comunication to the RCX 122ask_rcx_every(3). 123 124 125%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 126% A - INITIALIZATION AND FINALIZATION OF INTERFACES 127% initializeInterfaces/1 and finalizeInterfaces/1 128% 129% HERE YOU SHOULD INITIALIZE AND FINALIZE EACH OF THE INTERFACES TO BE USED 130%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 131 132initializeInterfaces(_) :- initializeExog(rcx). 133finalizeInterfaces(_) :- finalizeExog(rcx). 134 135 136%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 137% COMMUNICATION Process with the RCX via after_every/2 event 138% 139% A special after_every/2 event is set to continously communicatate the PC 140% with the RCX. Every some number of seconds the PC talks to the RCX: 141% 142% If there is a pending action to be executed (to_execute/4), such action 143% is sent to the RCX. Sensing outcome is stored in the database. 144% If no action is pending, then the process asks the RCX for any exogenous 145% action. If there is an exogenous event from the RCX, it is handled 146% by calling the corresponding handle_event/2 147%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 148% Set up an after_every event to trigger event rcx_talk every Sec seconds 149initializeExog(rcx) :- 150 printKbInstructions, 151 initializeRcx, 152 set_event_handler(rcx_talk, rcx_com/0), 153 ask_rcx_every(Sec), 154 event_after_every(rcx_talk, Sec), 155 report_message(system(3), 'Opening RCX communication'). 156 157% Stop the after_every event 158finalizeExogRcx(rcx) :- 159 cancel_after_event(rcx_talk), 160 report_message(system(3), 'Closing RCX communication'). 161 162% If there is something pending to execute, execute it on the RCX 163% Otherwise ask for possible exogenous events 164rcx_com :- 165 retract(to_execute(Action, T, N)) -> 166 report_message(action,['Executing action: *', Action,'*']), 167 executeRcx(Action, 1, T, S), 168 report_sensing(Action, N, S, _) % REPORT SENSING OUTCOME! 169 ; 170 report_message(system(2), 'Querying the RCX for exogenous events'), 171 queryRcxExogAction, 172 report_message(system(3), 'Finished with RCX communication'). 173 174% Ask for exogenous events. If there is one, then send it to the 175% environment manager via soutput 176queryRcxExogAction:- 177 checkRcxExog(ExogList), !, 178 (ExogList == [] -> 179 true 180 ; 181 ExogList = [A], 182 Message = ['Exogenous action *',A,'* received from RCX'], 183 report_exog_event(A, Message) % REPORT EXOGENOUS ACTION! 184 ). 185 186queryRcxExogAction :- 187 report_message(warning, 'No reply from the RCX for exog. events'). 188 189 190% checkRcxExog(-RcxExogList): Check for occurrence of exogenous actions 191% at RCX. At present RCX can only report one exogenous action at a time 192checkRcxExog([Action]) :- receiveRcxActionNumber([Action]), !. 193checkRcxExog([]). % No exogenous action from RCX 194 195% printKbInstructions: Print instructions on how to enter keyboard input 196printKbInstructions :- 197 writeln('*********************************************************'), 198 writeln('* NOTE: This is the RCX device manager'), 199 writeln('* This window will show the communication'), 200 writeln('* with the RCX brick'), 201 writeln('*********************************************************'), nl. 202 203 204%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 205% B - HANDLERS FOR EACH STREAM/SOCKET THAT IS BEING HEARD: handle_stream/1 206% 207% HERE YOU SHOULD WRITE HOW TO HANDLE DATA COMMING FROM EACH OF THE 208% INTERFACES/CHANNELS USED 209%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 210 211% Handle tcl/tk stream: called when there is data comming from the tcl/tk app 212handle_stream(tcltk) :- 213 read(tcltk, A), 214 (A=end_of_file -> 215 true % Tcl/Tk finished 216 ; 217 Message = ['Exogenous action *',A,'* received from TCL/TK'], 218 report_exog_event(A, Message) 219 ). 220 221 222%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 223% C - EXECUTION MODULE: execute/4 224% 225% This part implements the execution capabilities of the environment 226% 227% execute(Action, Type, N, Sensing) : execute Action of Type and return Sensing 228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 229 230% Just assert the action to_execute/3 so that it is sent to the rcx 231% in the next communication 232% No sensing is sent now, but it will be sent in rcx_com/0. 233execute(Action, Type, N, null) :- 234 report_message(action,['Action to be executed received: ', Action]), 235 assert(to_execute(Action, Type, N)). 236 237 238% executeRcx(Action, NoTry, Type, Sensing) 239% execute Action for the NoTry time on the RCX 240executeRcx(ActionCode, _, sim_sensing, SensingResult) :- 241 sendRcxActionNumber(ActionCode, _), !, 242 write('---> Enter Sensing value, terminate with ".": '), 243 read(SensingResult). 244 245executeRcx(ActionCode, _, T, SensingResult) :- T\== sim_sensing, 246 sendRcxActionNumber(ActionCode, SensingResult), !. 247 248executeRcx(A, NoTry, T, S) :- 249 NoTry2 is NoTry+1, 250 noTries(Limit), 251 Limit >= NoTry2, !, 252 report_message(warning, ['Error executing action ', A, 253 ' Trying again for the ', NoTry2, ' time.']), 254 executeRcx(A, NoTry2, T, S). 255 256executeRcx(A, _, _, failed) :- 257 report_message(action, ['Execution of action ', A, ' has failed!']). 258 259 260 261%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 262%%%%%%%%%%%%%%%%%%%%%%%%%%%% OTHER CODE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 264:- set_event_handler(170, my_system_error_handler/2). 265 266my_system_error_handler(E, Goal) :- 267 ( 268 errno_id(`Interrupted system call`), 269% errno_id(170, M), errno_id(M), % M is "Unknown error 170" ?? 270 restartable_builtin(Goal) 271 -> 272 call(Goal) 273 ; 274 errno_id(M), 275 report_message(error, M), 276 read(_), 277 error(default(E), Goal) 278 ). 279 280% Builtins that can raise EINTR and can be restarted after that 281restartable_builtin(accept(_,_,_)). 282restartable_builtin(cd(_)). 283restartable_builtin(close(_)). 284restartable_builtin(connect(_,_)). 285restartable_builtin(select(_,_,_)). 286restartable_builtin(wait(_,_)). 287 288 289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 290% EOF: Env/env_rcx.pl 291%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%