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
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #include "Robots/LoBot/LoApp.H"
00046
00047 #include "Robots/LoBot/control/LoTurnArbiter.H"
00048 #include "Robots/LoBot/control/LoBehavior.H"
00049
00050 #include "Robots/LoBot/slam/LoMap.H"
00051 #include "Robots/LoBot/lgmd/LocustModel.H"
00052
00053 #include "Robots/LoBot/ui/LoMainWindow.H"
00054 #include "Robots/LoBot/ui/LoLocustViz.H"
00055 #include "Robots/LoBot/ui/LoLaserVizFlat.H"
00056 #include "Robots/LoBot/ui/LoLaserViz.H"
00057 #include "Robots/LoBot/ui/LoDrawable.H"
00058
00059 #include "Robots/LoBot/io/LoRobot.H"
00060 #include "Robots/LoBot/io/LoLaserRangeFinder.H"
00061 #include "Robots/LoBot/io/LoDangerZone.H"
00062
00063 #include "Robots/LoBot/io/LoInputSource.H"
00064 #include "Robots/LoBot/io/LoVideoStream.H"
00065 #include "Robots/LoBot/io/LoVideoRecorder.H"
00066 #include "Robots/LoBot/io/LoFireWireBus.H"
00067
00068 #include "Robots/LoBot/config/LoConfigHelpers.H"
00069 #include "Robots/LoBot/config/LoCommonOpts.H"
00070 #include "Robots/LoBot/config/LoDefaults.H"
00071
00072 #include "Robots/LoBot/thread/LoShutdown.H"
00073 #include "Robots/LoBot/thread/LoUpdateLock.H"
00074 #include "Robots/LoBot/thread/LoPause.H"
00075
00076 #include "Robots/LoBot/misc/LoExcept.H"
00077 #include "Robots/LoBot/misc/LoRegistry.H"
00078 #include "Robots/LoBot/misc/factory.hh"
00079
00080 #include "Robots/LoBot/util/LoMath.H"
00081 #include "Robots/LoBot/util/LoDebug.H"
00082 #include "Robots/LoBot/util/range.hh"
00083
00084
00085 #include "Image/Dims.H"
00086
00087
00088 #include "Util/log.H"
00089
00090
00091 #include <glob.h>
00092 #include <unistd.h>
00093
00094
00095 #include <algorithm>
00096 #include <functional>
00097 #include <iterator>
00098 #include <utility>
00099
00100 #include <cmath>
00101 #include <cstdlib>
00102 #include <ctime>
00103
00104
00105
00106 namespace lobot {
00107
00108
00109
00110 bool video_enabled() ;
00111
00112 Dims grab_size() ;
00113 float grab_rate() ;
00114
00115 std::string locust_directions() ;
00116 int locust_fov() ;
00117
00118 bool playback_enabled() ;
00119 bool recording_enabled() ;
00120 std::string playback_stem() ;
00121 std::string recording_stem() ;
00122
00123 bool laser_enabled() ;
00124 std::string laser_device() ;
00125 int laser_baud_rate() ;
00126
00127 bool robot_enabled() ;
00128 std::string robot_platform() ;
00129
00130 bool show_ui() ;
00131 static bool mapping_enabled() ;
00132 static bool viz_on(const Behavior*) ;
00133
00134
00135
00136 App& App::create(int argc, const char* argv[])
00137 {
00138 App& app = instance() ;
00139 app.m_argc = argc ;
00140 app.m_argv = argv ;
00141 return app ;
00142 }
00143
00144
00145
00146 App::App()
00147 : m_compositor(0),
00148 m_lrf(0),
00149 m_input_source(0),
00150 m_robot(0),
00151 m_map(0),
00152 m_laser_viz(0),
00153 m_laser_viz_flat(0),
00154 m_locust_viz(0),
00155 m_model_manager("lobot"),
00156 m_cf_option(& OPT_ConfigFile, & m_model_manager),
00157 m_initialized(false)
00158 {
00159 Shutdown::start_listening() ;
00160 }
00161
00162
00163 static void create_mpeg_video_streams(std::string mpeg_file_names_stem,
00164 App::VideoStreams* V)
00165 {
00166 mpeg_file_names_stem += "*" ;
00167 glob_t buf ;
00168 if (glob(mpeg_file_names_stem.c_str(), 0, 0, & buf) != 0)
00169 throw vstream_error(MPEG_FILES_NOT_FOUND) ;
00170
00171 const int n = buf.gl_pathc ;
00172 V->reserve(n) ;
00173 for (int i = 0; i < n; ++i)
00174 V->push_back(new VideoStream(buf.gl_pathv[i])) ;
00175
00176 globfree(& buf) ;
00177 }
00178
00179
00180
00181 static void create_camera_video_streams(const Dims& resolution,
00182 float frame_rate,
00183 App::VideoStreams* V)
00184 {
00185 const int n = FireWireBus::instance().num_cameras() ;
00186 V->reserve(n) ;
00187 for (int i = 0; i < n; ++i)
00188 V->push_back(new VideoStream(i, resolution, frame_rate)) ;
00189
00190
00191
00192 FireWireBus::instance().release_camera_nodes() ;
00193 }
00194
00195
00196
00197 static void create_video_recorders(const App::VideoStreams& V,
00198 const std::string& mpeg_name_root,
00199 App::VideoRecorders* R)
00200 {
00201 const int n = V.size() ;
00202 R->reserve(n) ;
00203 for (int i = 0; i < n; ++i)
00204 R->push_back(new VideoRecorder(mpeg_name_root + to_string(i), V[i])) ;
00205 }
00206
00207
00208
00209 static LocustModel*
00210 create_locust_model(const std::string& name, const LocustModel::InitParams& p)
00211 {
00212 typedef factory<LocustModel, LocustModel::InitParams> lgmd_factory ;
00213 try
00214 {
00215 return lgmd_factory::create(name, p) ;
00216 }
00217 catch (lgmd_factory::unknown_type&)
00218 {
00219 throw unknown_model(UNKNOWN_LOCUST_MODEL) ;
00220 }
00221 }
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231 static void
00232 create_locust_models(const InputSource* S, App::LocustModels* models)
00233 {
00234 if (S->using_video())
00235 {
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264 }
00265 else if (S->using_laser())
00266 {
00267 std::vector<int> D = string_to_vector<int>(locust_directions());
00268 const int N = D.size() ;
00269 if (N <= 0)
00270 return ;
00271 std::sort(D.begin(), D.end(), std::greater<int>()) ;
00272
00273 const std::string model_name = locust_model() ;
00274 const range<int> lrf_range = S->lrf_angular_range() ;
00275 const int fov = clamp(locust_fov(), lrf_range) ;
00276
00277 Drawable::Geometry g =
00278 get_conf<std::string>(model_name, "geometry", "0 75 975 75") ;
00279 g.width /= N ;
00280
00281 LocustModel::InitParams p ;
00282 p.spike_range =
00283 get_conf<float>(model_name, "spike_range", make_range(0.0f, 300.0f)) ;
00284 p.source = S ;
00285
00286 models->reserve(N) ;
00287 for(int i = 0; i < N; ++i, g.x += g.width)
00288 {
00289 const int L = std::min(D[i] + fov/2, lrf_range.max()) ;
00290 const int R = std::max(D[i] - fov/2, lrf_range.min()) ;
00291
00292 p.direction = D[i] ;
00293 p.lrf_range.reset(L, R) ;
00294 p.name = std::string("lgmd[") + to_string(p.direction) + "]" ;
00295 p.geometry = g ;
00296
00297 models->push_back(create_locust_model(model_name, p)) ;
00298 }
00299 }
00300 }
00301
00302
00303 static void create_behaviours(App::Behaviours* B)
00304 {
00305 std::vector<std::string> behaviours = string_to_vector<std::string>(
00306 global_conf<std::string>("behaviors")) ;
00307
00308
00309 const int N = behaviours.size() ;
00310 B->reserve(N) ;
00311 for (int i = 0; i < N; ++i)
00312 try
00313 {
00314 Behavior* b = factory<Behavior>::create(behaviours[i]) ;
00315 b->name = behaviours[i] ;
00316 B->push_back(b) ;
00317 }
00318 catch (factory<Behavior>::unknown_type&)
00319 {
00320 throw unknown_model(UNKNOWN_BEHAVIOR) ;
00321 }
00322 }
00323
00324
00325
00326 static Robot* create_robot(const std::string& robot_platfom, ModelManager& M)
00327 {
00328 typedef factory<Robot, ModelManager> robot_factory ;
00329 try
00330 {
00331 return robot_factory::create(robot_platfom, M) ;
00332 }
00333 catch (robot_factory::unknown_type&)
00334 {
00335 throw unknown_model(UNKNOWN_ROBOT_PLATFORM) ;
00336 }
00337 return 0 ;
00338 }
00339
00340
00341 void App::signal_init()
00342 {
00343 m_initialized_cond.broadcast(signal_pred()) ;
00344 }
00345
00346 bool App::signal_pred::operator()()
00347 {
00348 App& app = App::instance() ;
00349 app.m_initialized = true ;
00350 return true ;
00351 }
00352
00353
00354 void App::wait_init()
00355 {
00356 m_initialized_cond.wait(wait_pred()) ;
00357 }
00358
00359 bool App::wait_pred::operator()()
00360 {
00361 return App::instance().m_initialized ;
00362 }
00363
00364
00365
00366 void App::parse_command_line()
00367 {
00368 std::string default_config_file = getenv("HOME") ;
00369 default_config_file += "/" ;
00370 default_config_file += LOBOT_DEFAULT_CONFIG_FILE_NAME ;
00371 m_model_manager.setOptionValString(& OPT_ConfigFile,
00372 default_config_file.c_str()) ;
00373
00374 if (! m_model_manager.parseCommandLine(m_argc, m_argv, "", 0, 0))
00375 throw customization_error(BAD_OPTION) ;
00376 }
00377
00378
00379
00380
00381 void App::run()
00382 {
00383 m_model_manager.start() ;
00384
00385
00386 try
00387 {
00388 Configuration::load(config_file()) ;
00389
00390 }
00391 catch (customization_error& e)
00392 {
00393 LERROR("%s", e.what()) ;
00394 }
00395
00396
00397 if (video_enabled()) {
00398 if (playback_enabled())
00399 create_mpeg_video_streams(playback_stem(), & m_video_streams) ;
00400 else
00401 create_camera_video_streams(grab_size(), grab_rate(),
00402 & m_video_streams) ;
00403 m_compositor = new ImageCompositor() ;
00404 connect(m_video_streams, *m_compositor) ;
00405 if (recording_enabled())
00406 create_video_recorders(m_video_streams, recording_stem() + "-",
00407 & m_video_recorders) ;
00408 Configuration::set_internal("frame_rate",
00409 to_string(m_video_streams[0]->frameRate())) ;
00410 }
00411
00412
00413 if (laser_enabled()) {
00414 m_lrf = new LaserRangeFinder(laser_device(), laser_baud_rate()) ;
00415 DangerZone::use(m_lrf) ;
00416 }
00417
00418
00419 if (robot_enabled())
00420 m_robot = create_robot(robot_platform(), m_model_manager) ;
00421
00422
00423 if (mapping_enabled())
00424 m_map = new Map() ;
00425
00426
00427 if (video_enabled() && video_input())
00428 m_input_source = new InputSource(m_compositor) ;
00429 else if (laser_enabled() && laser_input())
00430 m_input_source = new InputSource(m_lrf) ;
00431 if (m_input_source)
00432 create_locust_models(m_input_source, & m_locusts) ;
00433
00434
00435 create_behaviours(& m_behaviours) ;
00436
00437
00438 if (show_ui()) {
00439 MainWindow& W = MainWindow::instance() ;
00440 if (video_enabled() && video_input()) {
00441 }
00442 else if (laser_enabled() && laser_input()) {
00443 if (visualize("laser_viz"))
00444 W.push_back(m_laser_viz = new LaserViz(m_lrf)) ;
00445 if (visualize("laser_viz_flat"))
00446 W.push_back(m_laser_viz_flat = new LaserVizFlat(m_lrf)) ;
00447 }
00448
00449 if (mapping_enabled() && visualize("map"))
00450 W.push_back(m_map) ;
00451
00452 if (visualize(locust_model()))
00453 connect(m_locusts, W) ;
00454 if (visualize("locust_viz"))
00455 W.push_back(m_locust_viz = new LocustViz(m_locusts)) ;
00456
00457 if (visualize("turn_arbiter"))
00458 W.push_back(& TurnArbiter::instance()) ;
00459 connect_if(m_behaviours, W, viz_on) ;
00460 }
00461
00462
00463
00464 bool start_paused = global_conf("start_paused", false) ;
00465 if (start_paused && show_ui())
00466 Pause::set() ;
00467 else
00468 Pause::clear() ;
00469
00470
00471 srand(time(0)) ;
00472 signal_init() ;
00473
00474
00475 int update_delay = clamp(global_conf("update_delay", 100), 1, 1000) * 1000;
00476 while (! Shutdown::signaled())
00477 {
00478 if (Pause::is_clear()) {
00479 UpdateLock::begin_write() ;
00480 std::for_each(m_video_streams.begin(), m_video_streams.end(),
00481 std::mem_fun(& VideoStream::update)) ;
00482 std::for_each(m_video_recorders.begin(), m_video_recorders.end(),
00483 std::mem_fun(& VideoRecorder::update)) ;
00484 if (m_compositor)
00485 m_compositor->update() ;
00486 if (m_lrf) {
00487 m_lrf->update() ;
00488 DangerZone::update() ;
00489 }
00490 if (m_robot)
00491 m_robot->update() ;
00492 std::for_each(m_locusts.begin(), m_locusts.end(),
00493 std::mem_fun(& LocustModel::update)) ;
00494 UpdateLock::end_write() ;
00495 }
00496 usleep(update_delay) ;
00497 }
00498
00499
00500 if (m_robot)
00501 m_robot->off() ;
00502 }
00503
00504
00505
00506 App::~App()
00507 {
00508 LERROR("cleaning up...") ;
00509
00510 purge_container(m_behaviours) ;
00511
00512 delete m_locust_viz ;
00513 delete m_laser_viz_flat ;
00514 delete m_laser_viz ;
00515 delete m_map ;
00516 delete m_robot ;
00517
00518 purge_container(m_locusts) ;
00519 delete m_input_source ;
00520 delete m_lrf ;
00521 delete m_compositor ;
00522
00523 purge_container(m_video_recorders) ;
00524 purge_container(m_video_streams) ;
00525
00526 if (m_model_manager.started())
00527 m_model_manager.stop() ;
00528 }
00529
00530
00531
00532 bool video_enabled()
00533 {
00534 return video_conf("use_video", true) ;
00535 }
00536
00537 Dims grab_size()
00538 {
00539 try
00540 {
00541 Dims d ;
00542 convertFromString(video_conf<std::string>("grab_size"), d) ;
00543 return d ;
00544 }
00545 catch (std::exception&)
00546 {
00547 return LOBOT_DEFAULT_GRAB_SIZE ;
00548 }
00549 }
00550
00551 float grab_rate()
00552 {
00553 return video_conf("grab_rate", LOBOT_DEFAULT_GRAB_RATE) ;
00554 }
00555
00556 bool recording_enabled()
00557 {
00558 return recording_stem() != "" ;
00559 }
00560
00561 std::string recording_stem()
00562 {
00563 return video_conf<std::string>("record") ;
00564 }
00565
00566 bool playback_enabled()
00567 {
00568 return playback_stem() != "" ;
00569 }
00570
00571 std::string playback_stem()
00572 {
00573 return video_conf<std::string>("play") ;
00574 }
00575
00576 bool laser_enabled()
00577 {
00578 return laser_conf("use_laser", true) ;
00579 }
00580
00581 std::string laser_device()
00582 {
00583 return laser_conf<std::string>("serial_port", "/dev/ttyACM0") ;
00584 }
00585
00586 int laser_baud_rate()
00587 {
00588 return laser_conf("baud_rate", 115200) ;
00589 }
00590
00591 std::string locust_directions()
00592 {
00593 return get_conf<std::string>(locust_model(), "locust_directions", "") ;
00594 }
00595
00596 int locust_fov()
00597 {
00598 return get_conf(locust_model(), "locust_fov", LOBOT_DEFAULT_LOCUST_FOV) ;
00599 }
00600
00601 bool show_ui()
00602 {
00603 return ui_conf("show_ui", true) ;
00604 }
00605
00606 static bool mapping_enabled()
00607 {
00608 return get_conf("map", "enable", false) ;
00609 }
00610
00611 static bool viz_on(const Behavior* B)
00612 {
00613 return visualize(B->name) ;
00614 }
00615
00616
00617
00618 }
00619
00620
00621
00622
00623