00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <iostream>
00032 #include <sstream>
00033 #include "iwakishi.h"
00034 #include "log.h"
00035 #include <string>
00036 #include <csignal>
00037 #include <algorithm>
00038 #include <ncursesw/ncurses.h>
00039
00040 #include <sys/time.h>
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <getopt.h>
00044
00045 #include <math.h>
00046
00047 #include "ros/ros.h"
00048 #include "std_msgs/String.h"
00049 #include "iwaki/ActionMsg.h"
00050 #include "iwaki/AtomMsg.h"
00051 #include "iwaki/ActionStatusMsg.h"
00052
00053 #include <sstream>
00054
00055
00056
00061 InteractionManager im;
00062 TextUI textUI;
00063
00064 #define KB_ENTER int('\n')
00065
00066 ActionStatus convertActionStatusMsgToActionStatus(const iwaki::ActionStatusMsg
00067 &anActionStatusMsg) {
00068 ActionStatus newActionStatus;
00069 for (std::vector<iwaki::ArgSlot>::const_iterator argslot_it =
00070 anActionStatusMsg.return_args.begin();
00071 argslot_it != anActionStatusMsg.return_args.end(); argslot_it++) {
00072 ArgSlot anArgSlot;
00073 anArgSlot.name = argslot_it->name;
00074 anArgSlot.value = argslot_it->value;
00075 anArgSlot.default_value = argslot_it->default_value;
00076 anArgSlot.type = argslot_it->type;
00077 anArgSlot.unit = argslot_it->unit;
00078 anArgSlot.var = argslot_it->var;
00079
00080 newActionStatus.return_args.push_back(anArgSlot);
00081 }
00082
00083 newActionStatus.action_id = anActionStatusMsg.action_id;
00084 newActionStatus.executor = anActionStatusMsg.executor;
00085 newActionStatus.status = anActionStatusMsg.status;
00086 return newActionStatus;
00087 }
00088
00089
00090
00091
00092
00093
00094
00095 void actionStatusCallback(const iwaki::ActionStatusMsg::ConstPtr& anActionStatusMsg_p) {
00096 ActionStatus newActionStatus = convertActionStatusMsgToActionStatus(*anActionStatusMsg_p);
00097 im.processActionCompletionStatus(newActionStatus);
00098 }
00099
00100
00101
00102 string makeSnippetFromAtom(Atom anAtom) {
00103 string snippet;
00104
00105 for (std::list<VarSlot>::iterator varslot_it = anAtom.varslots.begin();
00106 varslot_it != anAtom.varslots.end(); varslot_it++) {
00107 if (varslot_it->name == "uu_string") {
00108 snippet += varslot_it->val;
00109 }
00110 }
00111 return snippet;
00112 }
00113
00114 Atom convertAtomMsgToAtom(const iwaki::AtomMsg &anAtomMsg) {
00115 Atom new_atom;
00116
00117 for (std::vector<iwaki::VarSlot>::const_iterator varslot_it = anAtomMsg.varslots.begin();
00118 varslot_it != anAtomMsg.varslots.end(); varslot_it++) {
00119 VarSlot newVarSlot;
00120 newVarSlot.name = varslot_it->name;
00121 newVarSlot.val = varslot_it->val;
00122 newVarSlot.relation = varslot_it->relation;
00123 newVarSlot.type = varslot_it->type;
00124 newVarSlot.unique_mask = varslot_it->unique_mask;
00125
00126 new_atom.varslots.push_back(newVarSlot);
00127 }
00128 return new_atom;
00129 }
00130
00131
00132
00133
00134
00135
00136
00137 void inputAtomCallback(const iwaki::AtomMsg::ConstPtr& anAtomMsg_p) {
00138 Atom new_atom = convertAtomMsgToAtom(*anAtomMsg_p);
00139 textUI.push_msg("INFO: received message: " + makeSnippetFromAtom(new_atom));
00140 im.input_queue.push_back(new_atom);
00141
00142 }
00143
00144
00145
00146 iwaki::ActionMsg convertActionToActionMsg(Action &anAction) {
00147
00148 iwaki::ActionMsg anActionMsg;
00149
00150
00151 for (std::list<ArgSlot>::iterator arg_it = anAction.args.begin();
00152 arg_it != anAction.args.end(); arg_it++) {
00153 iwaki::ArgSlot anArgSlot;
00154 anArgSlot.name = arg_it->name;
00155 anArgSlot.value = arg_it->value;
00156 anArgSlot.default_value = arg_it->default_value;
00157 anArgSlot.type = arg_it->type;
00158 anArgSlot.unit = arg_it->unit;
00159 anArgSlot.var = arg_it->var;
00160
00161 anActionMsg.args.push_back(anArgSlot);
00162 }
00163
00164
00165 for (std::list<ArgSlot>::iterator arg_it = anAction.return_args.begin();
00166 arg_it != anAction.return_args.end(); arg_it++) {
00167 iwaki::ArgSlot anArgSlot;
00168 anArgSlot.name = arg_it->name;
00169 anArgSlot.value = arg_it->value;
00170 anArgSlot.default_value = arg_it->default_value;
00171 anArgSlot.type = arg_it->type;
00172 anArgSlot.unit = arg_it->unit;
00173 anArgSlot.var = arg_it->var;
00174
00175 anActionMsg.return_args.push_back(anArgSlot);
00176 }
00177
00178 anActionMsg.name = anAction.name;
00179 anActionMsg.id = anAction.id;
00180 anActionMsg.actor = anAction.actor;
00181
00182
00183 anActionMsg.thetimeout = anAction.timeout;
00184 anActionMsg.if_timeout = anAction.if_timeout;
00185 anActionMsg.priority = anAction.priority;
00186
00187 return anActionMsg;
00188 }
00189
00190
00191
00192
00193
00194
00195 void publishAction(Action &anAction, ros::Publisher &action_pub) {
00196
00197
00198 iwaki::ActionMsg anActionMsg = convertActionToActionMsg(anAction);
00199
00200 FILE_LOG(logDEBUG1) << "Publishing ROS ActionMsg named: " << anActionMsg.name;
00201 FILE_LOG(logDEBUG1) << " id: " << anActionMsg.id;
00202 FILE_LOG(logDEBUG1) << " actor: " << anActionMsg.actor;
00203
00204
00211 action_pub.publish(anActionMsg);
00212
00213 }
00214
00215
00216
00217
00218
00219 void dispatchActionsFromOutputQueue(ros::Publisher &action_pub) {
00220
00221 std::list<Action>::iterator action_it = im.output_queue.begin();
00222
00223 FILE_LOG(logDEBUG4) << "Action queue has length: " <<
00224 im.output_queue.size();
00225 while( action_it != im.output_queue.end() ) {
00226
00227
00228
00229
00230
00231
00232 publishAction(*action_it, action_pub);
00233 action_it++;
00234 im.output_queue.pop_front();
00235 }
00236 }
00237
00238
00239 void updateKbBuffer(string &kb_buffer, int ch) {
00240 char buffer[8];
00241 sprintf (buffer, "%c", ch);
00242 if ((ch >= 32) && (ch <= 126)) {
00243
00244 kb_buffer += string(buffer);
00245 } else if (ch == KEY_BACKSPACE) {
00246
00247 if (!kb_buffer.empty()) {
00248 kb_buffer = kb_buffer.substr(0, kb_buffer.size() - 1);
00249 }
00250 } else if (ch == KB_ENTER) {
00251
00252
00253
00254 kb_buffer = "";
00255 }
00256 }
00257
00258
00262 int main(int argc, char **argv)
00263 {
00264 std::string logfile_name;
00265 bool text_ui = false;
00266 std::string debug_level;
00267 unsigned int timer_period_microsec = 1000000;
00268 int c;
00269 UICommand ui_command;
00270 int ch;
00271 string kb_buffer;
00272
00273
00274 ros::init(argc, argv, "iwakishi");
00275
00276
00277 opterr = 0;
00278 char* cvalue;
00279 while (1)
00280 {
00281 static struct option long_options[] =
00282 {
00283
00284
00285
00286
00287
00288 {"help", no_argument, 0, 'h'},
00289 {"text_ui", no_argument, 0, 'x'},
00290 {"log", required_argument, 0, 'l'},
00291 {"debug", required_argument, 0, 'd'},
00292 {"timer", required_argument, 0, 't'},
00293 {"init", required_argument, 0, 'i'},
00294 {"atoms", required_argument, 0, 'a'},
00295 {"path", required_argument, 0, 'p'},
00296 {0, 0, 0, 0}
00297 };
00298
00299 int option_index = 0;
00300
00301 c = getopt_long (argc, argv, "hxl:d:t:i:a:p:",
00302 long_options, &option_index);
00303
00304
00305 if (c == -1)
00306 break;
00307
00308 switch (c) {
00309 case 0:
00310
00311 if (long_options[option_index].flag != 0)
00312 break;
00313 printf ("option %s", long_options[option_index].name);
00314 if (optarg)
00315 printf (" with arg %s", optarg);
00316 printf ("\n");
00317 break;
00318
00319 case 'h':
00320 cout << "\
00321 Usage: imcore [OPTION]... \n \
00322 ";
00323 cout << "Mandatory arguments to long options are mandatory for short options too.\n\
00324 ";
00325 cout << "\
00326 -d --debug DEBUG_LEVEL DEBUG_LEVEL is one of the \n \
00327 following: ERROR, WARNING, INFO, \n \
00328 DEBUG, DEBUG1, DEBUG2, DEBUG3, DEBUG4\n\
00329 ";
00330 cout << "\
00331 -t --timer TIMER_PERIOD if present, this option causes \n \
00332 IM to run in timer mode, with every TIMER_PERIOD\n \
00333 seconds IM state update is forced. If the option is\n \
00334 not present IM runs in callback mode\n \
00335 ";
00336 cout << "\
00337 -l --log LOG_FILE if present, this option causes \n \
00338 all the debug output be directed to the LOG_FILE\n \
00339 ";
00340 cout << "\
00341 -i --init INIT_FILE name of the IM init file that overrides\n \
00342 default initialize_im.xml\n \
00343 ";
00344 cout << "\
00345 -a --atoms DEFAULTS_FILE name of the atom defaults file that overrides\n \
00346 default default_atoms.xml\n \
00347 ";
00348 cout << "\
00349 -p --path PATH path to recipes, actions and functions directories\n \
00350 ";
00351 cout << "\
00352 -x --text_ui turn on text ui. will supress normal debug and error \n \
00353 terminal output\n \
00354 ";
00355
00356 cout << "\
00357 -h --help This info." << endl;
00358 return -1;
00359 case 'x':
00360 text_ui = true;
00361 break;
00362 case 'd':
00363 cvalue = optarg;
00364 debug_level=string((const char*) cvalue);
00365 break;
00366 case 'l':
00367 {
00368 cvalue = optarg;
00369 logfile_name = (string)((const char*) cvalue);
00370 if (!setLogFile(logfile_name)) {
00371 return -1;
00372 }
00373 break;
00374 }
00375 case 't':
00376 {
00377 cvalue = optarg;
00378 std::string cvalue_str = string((const char*) cvalue);
00379 double timer_period_sec = string_to_double(cvalue_str);
00380 if ((timer_period_sec > 1.0)||(timer_period_sec <= 0)) {
00381 cout << "Timer period should be positive and not more \
00382 than 1.0 seconds." << endl;
00383 return -1;
00384 }
00385 timer_period_microsec =
00386 (unsigned int) floor(timer_period_sec*1000000);
00387 break;
00388 }
00389 case 'i':
00390 {
00391 cvalue = optarg;
00392 im.init_file_name = (string) ((const char*) cvalue);
00393 break;
00394 }
00395 case 'a':
00396 {
00397 cvalue = optarg;
00398 im.default_atoms_file_name = (string) ((const char*) cvalue);
00399 break;
00400 }
00401 case 'p':
00402 {
00403 cvalue = optarg;
00404 im.script_path = (string) ((const char*) cvalue);
00405 break;
00406 }
00407 default:
00408 cout <<
00409 "Unknown option. Try 'soundboard --help' for more information.\n";
00410 return -1;
00411 }
00412 }
00413
00414
00415 if (optind < argc)
00416 {
00417 printf ("non-option ARGV-elements: ");
00418 while (optind < argc)
00419 printf ("%s ", argv[optind++]);
00420 putchar ('\n');
00421 }
00422
00423
00424 FILELog::ReportingLevel() =
00425 FILELog::FromString(debug_level.empty() ? "DEBUG1" : debug_level);
00426
00427
00428
00429 im.timer_period_microsec = timer_period_microsec;
00430
00431 if (!im.initialize())
00432 {
00433 FILE_LOG(logERROR) << "Initialization of IM failed.";
00434 } else {
00435 FILE_LOG(logINFO) << "Initialization of IM succeeded.";
00436 }
00437
00438
00439
00440
00441 if ( text_ui ) {
00442 textUI.init();
00443 }
00444
00445 FILE_LOG(logINFO) << "Running timer with the period of " <<
00446 timer_period_microsec << " microseconds." << endl;
00447
00448
00449 ros::NodeHandle n;
00450 ros::Publisher action_pub = n.advertise<iwaki::ActionMsg>("IwakiAction", 1000);
00451 ros::Subscriber atom_sub = n.subscribe("IwakiInputAtom", 1000, inputAtomCallback);
00452 ros::Subscriber actionStatus_sub = n.subscribe("IwakiActionStatus", 1000, actionStatusCallback);
00453
00454
00455
00456 usleep(1000000.0);
00457
00458
00459
00460
00461
00462
00463
00464
00465 while (ros::ok())
00466 {
00467
00468 double start_tick = getSystemTimeMSec()/1000.0;
00469 FILE_LOG(logDEBUG4) <<
00470 "############ Re-entering the main loop at: "
00471 << setprecision(20) << start_tick ;
00472
00473 im.doTick();
00474
00475
00476 dispatchActionsFromOutputQueue(action_pub);
00477
00478
00479
00480 ch = getch();
00481
00482 updateKbBuffer(kb_buffer, ch);
00483
00484 if (text_ui) {
00485
00486 textUI.keyboardBuffer = kb_buffer;
00487 ui_command = textUI.update(im, ch);
00488 if ( ui_command == uiQuit) {
00489 textUI.close();
00490 FILE_LOG(logINFO) << "TextUI requested quit. Goodbye.";
00491 return -1;
00492 }
00493 }
00494
00495
00496
00497
00498
00499
00500 FILE* pStream = Output2FILE::Stream();
00501
00502 int logfile_size = ftell( pStream );
00503 FILE_LOG(logDEBUG3) << "Logfile size: " << logfile_size;
00504 if (logfile_size > MAX_LOGFILE_SIZE ) {
00505
00506 if (!setLogFile(logfile_name)) {
00507 return -1;
00508 }
00509 }
00510
00511 double end_tick = getSystemTimeMSec()/1000.0;
00512
00513 FILE_LOG(logDEBUG4) <<
00514 "############ Done tick at: " << setprecision(20) <<
00515 end_tick ;
00516
00517 FILE_LOG(logDEBUG4) <<
00518 "############ Cycle took: " << setprecision(20) <<
00519 (end_tick - start_tick) << " seconds.";
00520
00522 if (im.timing_dump_counter == 0) {
00523 FILE_LOG(logINFO) << "Print subcycle timings...";
00524 for (std::map<string, std::list<double> >::const_iterator
00525 map_it = im.subcycle_timings.begin();
00526 map_it != im.subcycle_timings.end(); map_it++) {
00527 string timings_str;
00528
00529 for (std::list<double>::const_iterator
00530 list_it = map_it->second.begin();
00531 list_it != map_it->second.end(); list_it++) {
00532 timings_str = timings_str + to_string(*list_it) + ", ";
00533 }
00534
00535 FILE_LOG(logINFO) << "Timing subcycle " << map_it->first
00536 << ": " << timings_str;
00537 }
00538 im.ptree.print(logINFO);
00539 im.getGlobalBindings()->print(logINFO);
00540 FILE_LOG(logINFO) << "Print subcycle timings...";
00541 }
00542
00543 if ((end_tick - start_tick) < (timer_period_microsec/1000000.0)) {
00544 FILE_LOG(logDEBUG4) <<
00545 "########### intentially wasting: " << setprecision(20) <<
00546 ((timer_period_microsec/1000000.0) - (end_tick - start_tick)) <<
00547 " seconds.";
00548 usleep(timer_period_microsec - (end_tick - start_tick)*1000000.0);
00549 } else {
00550 FILE_LOG(logWARNING) <<
00551 "########### sampling period is short of: " << setprecision(20) <<
00552 ((end_tick - start_tick) - (timer_period_microsec/1000000.0)) <<
00553 " seconds.";
00554 im.ptree.print(logWARNING);
00555 im.getGlobalBindings()->print(logWARNING);
00556 }
00557
00558
00559
00560
00561
00562 ros::spinOnce();
00563
00564
00565 }
00566
00567
00568 return 0;
00569 }