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/control/LoGoal.H"
00046 #include "Robots/LoBot/control/LoMetrics.H"
00047 #include "Robots/LoBot/control/LoTurnArbiter.H"
00048 #include "Robots/LoBot/control/LoSpinArbiter.H"
00049
00050 #include "Robots/LoBot/LoApp.H"
00051 #include "Robots/LoBot/slam/LoMap.H"
00052 #include "Robots/LoBot/slam/LoSlamParams.H"
00053
00054 #include "Robots/LoBot/config/LoConfigHelpers.H"
00055
00056 #include "Robots/LoBot/thread/LoShutdown.H"
00057 #include "Robots/LoBot/thread/LoUpdateLock.H"
00058 #include "Robots/LoBot/thread/LoPause.H"
00059
00060 #include "Robots/LoBot/misc/LoExcept.H"
00061 #include "Robots/LoBot/misc/LoRegistry.H"
00062 #include "Robots/LoBot/misc/singleton.hh"
00063
00064 #include "Robots/LoBot/util/LoGL.H"
00065 #include "Robots/LoBot/util/LoMath.H"
00066
00067
00068 #ifdef INVT_HAVE_LIBGLU
00069 #include <GL/glu.h>
00070 #endif
00071
00072 #ifdef INVT_HAVE_LIBGL
00073 #include <GL/gl.h>
00074 #endif
00075
00076
00077 #include <iomanip>
00078 #include <sstream>
00079 #include <numeric>
00080 #include <algorithm>
00081 #include <functional>
00082 #include <iterator>
00083 #include <utility>
00084
00085
00086
00087 namespace lobot {
00088
00089
00090
00091 namespace {
00092
00093
00094 template<typename T>
00095 inline T conf(const std::string& key, const T& default_value)
00096 {
00097 return get_conf<T>(LOBE_GOAL, key, default_value) ;
00098 }
00099
00100
00101 template<typename T>
00102 inline std::pair<T, T>
00103 conf(const std::string& key, const std::pair<T, T>& default_value)
00104 {
00105 return get_conf<T>(LOBE_GOAL, key, default_value) ;
00106 }
00107
00108
00109
00110 class Params : public singleton<Params> {
00111
00112
00113
00114
00115
00116
00117 bool m_seek_mode ;
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130 bool m_pause ;
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140 bool m_loop ;
00141
00142
00143
00144
00145
00146 bool m_backtrack ;
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162 int m_vff_window_size ;
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173 std::pair<float, float> m_vff_forces ;
00174
00175
00176
00177
00178
00179
00180
00181
00182 bool m_spin_style_steering ;
00183
00184
00185
00186
00187
00188
00189
00190 int m_update_delay ;
00191
00192
00193
00194 typedef Drawable::Geometry Geom ;
00195 Drawable::Geometry m_geometry ;
00196
00197
00198
00199
00200 bool m_render_goals ;
00201
00202
00203 Params() ;
00204 friend class singleton<Params> ;
00205
00206 public:
00207
00208
00209 static bool seek_mode() {return instance().m_seek_mode ;}
00210 static bool pause() {return instance().m_pause ;}
00211 static bool loop() {return instance().m_loop ;}
00212 static bool backtrack() {return instance().m_backtrack ;}
00213 static bool render_goals() {return instance().m_render_goals ;}
00214 static bool spin_style_steering(){return instance().m_spin_style_steering;}
00215 static int update_delay() {return instance().m_update_delay ;}
00216 static Geom geometry() {return instance().m_geometry ;}
00217 static int vff_window_size() {return instance().m_vff_window_size ;}
00218 static float vff_rep_force() {return instance().m_vff_forces.first ;}
00219 static float vff_att_force() {return instance().m_vff_forces.second ;}
00220
00221 } ;
00222
00223
00224 Params::Params()
00225 : m_seek_mode(conf("actively_seek_goals", false)),
00226 m_pause(conf("pause_at_goal", false)),
00227 m_loop(conf("loop", false)),
00228 m_backtrack(conf("backtrack", false)),
00229 m_vff_forces(conf("vff_forces", std::make_pair(100.0f, 1000.0f))),
00230 m_spin_style_steering(conf("spin_style_steering", false)),
00231 m_update_delay(clamp(conf("update_delay", 1750), 500, 10000)),
00232 m_geometry(conf<std::string>("geometry", "0 0 10 10")),
00233 m_render_goals(conf("render_goals", false))
00234 {
00235 const float R = clamp(robot_conf("size", 400), 150, 1000) ;
00236 const float s = SlamParams::map_cell_size() ;
00237 const int n = round(R/s)/2 ;
00238 m_vff_window_size = clamp(conf("vff_window_size", 3*n/2), n + 1, 4 * n) ;
00239
00240 m_vff_forces.first = clamp(m_vff_forces.first, 1.0f, 1e6f) ;
00241 m_vff_forces.second = clamp(m_vff_forces.second, 1.0f, 1e6f) ;
00242 }
00243
00244 }
00245
00246
00247
00248 Goal::Goal()
00249 : base(Params::update_delay(), LOBE_GOAL, Params::geometry()),
00250 m_goal(-1), m_turn_dir(0)
00251 {
00252 start(LOBE_GOAL) ;
00253 }
00254
00255 Goal::Target::Target(float L, float R, float B, float T)
00256 : m_left(L), m_right(R), m_bottom(B), m_top(T),
00257 m_center_x((L + R)/2), m_center_y((B + T)/2)
00258 {}
00259
00260 void Goal::pre_run()
00261 {
00262 if (! App::robot())
00263 throw behavior_error(MOTOR_SYSTEM_MISSING) ;
00264
00265 Map* map = App::map() ;
00266 if (! map)
00267 throw behavior_error(MAPPING_DISABLED) ;
00268
00269
00270 float L, R, B, T ;
00271 SlamParams::map_extents(&L, &R, &B, &T) ;
00272 std::istringstream goals(conf<std::string>("goals", "")) ;
00273 for(;;)
00274 {
00275 float l, r, b, t ;
00276 goals >> l >> r >> b >> t ;
00277 if (! goals)
00278 break ;
00279 m_goals.push_back(Target(clamp(l, L, R), clamp(r, l, R),
00280 clamp(b, B, T), clamp(t, b, T))) ;
00281 }
00282 if (m_goals.empty())
00283 throw behavior_error(NO_GOALS) ;
00284
00285
00286 m_goal = 0 ;
00287
00288
00289
00290 if (Params::loop() && Params::backtrack())
00291 std::copy(m_goals.rbegin() + 1, m_goals.rend() - 1,
00292 std::back_inserter(m_goals)) ;
00293
00294
00295 const int W = Params::vff_window_size() ;
00296 const float S = SlamParams::map_cell_size() ;
00297 const float F = -Params::vff_rep_force() ;
00298
00299 int x, y ;
00300 float dx, dy ;
00301 m_vff_mask.reserve(sqr(W * 2 + 1)) ;
00302 for (y = W, dy = y * S; y >= -W; --y, dy -= S)
00303 for (x = -W, dx = x * S; x <= W; ++x, dx += S)
00304 {
00305 float d2 = sqr(dx) + sqr(dy) ;
00306 float d = sqrtf(d2) ;
00307 m_vff_mask.push_back(Vector((x == 0) ? 0 : F/d2 * dx/d,
00308 (y == 0) ? 0 : F/d2 * dy/d)) ;
00309 }
00310
00311
00312 if (Params::render_goals())
00313 map->add_hook(RenderHook(
00314 render_goals, reinterpret_cast<unsigned long>(this))) ;
00315 }
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327 void Goal::run()
00328 {
00329 try
00330 {
00331 App::wait_for_init() ;
00332 pre_run() ;
00333
00334 const Map* M = App::map() ;
00335 bool paused_previously = Pause::is_set() ;
00336 while (! Shutdown::signaled())
00337 {
00338 bool paused_now = Pause::is_set() ;
00339 if (! paused_now) {
00340 if (paused_previously)
00341 log("seeking goal", m_goal, m_goals[m_goal], M->current_pose());
00342 action() ;
00343 }
00344 paused_previously = paused_now ;
00345 usleep(m_update_delay) ;
00346 }
00347
00348 post_run() ;
00349 }
00350 catch (uhoh& e)
00351 {
00352 LERROR("behaviour %s encountered an error: %s", name.c_str(), e.what()) ;
00353 return ;
00354 }
00355 }
00356
00357
00358
00359
00360
00361 void Goal::action()
00362 {
00363 const Map* map = App::map() ;
00364 const Pose P = map->current_pose() ;
00365
00366 int turn_dir = 0 ;
00367 Vector Ft, Fr, R ;
00368
00369 const Target goal = m_goals[m_goal] ;
00370 if (goal.at(P.x(), P.y()))
00371 {
00372 log("reached goal", m_goal, goal, P) ;
00373
00374 if (Params::pause())
00375 Pause::set() ;
00376
00377 ++m_goal ;
00378 if (m_goal == static_cast<int>(m_goals.size())) {
00379 if (Params::loop())
00380 m_goal = 0 ;
00381 else
00382 --m_goal ;
00383 }
00384 }
00385 else if (Params::seek_mode())
00386 {
00387
00388
00389
00390
00391 std::vector<unsigned char> vff_window =
00392 map->submap(Params::vff_window_size()) ;
00393
00394
00395
00396
00397 std::transform(vff_window.begin(), vff_window.end(), vff_window.begin(),
00398 std::bind1st(std::minus<unsigned char>(), 255)) ;
00399
00400
00401
00402 Fr = std::inner_product(m_vff_mask.begin(), m_vff_mask.end(),
00403 vff_window.begin(), Vector(0, 0)) ;
00404
00405
00406 Ft = normalized(Vector(goal.x() - P.x(), goal.y() - P.y()))
00407 * Params::vff_att_force() ;
00408
00409
00410 R = Ft + Fr ;
00411
00412
00413
00414 const int T = TurnArbiter::turn_max() ;
00415 const float current_heading =
00416 (P.bearing() < 180) ? P.bearing() : P.bearing() - 360 ;
00417 const int heading_error = round(direction(R) - current_heading) ;
00418 if (Params::spin_style_steering())
00419 {
00420 turn_dir = heading_error ;
00421 SpinArbiter::instance().vote(base::name,
00422 new SpinArbiter::Vote(turn_dir)) ;
00423 }
00424 else
00425 {
00426 turn_dir = clamp(heading_error, -T, T) ;
00427 TurnArbiter::instance().vote(base::name,
00428 new TurnArbiter::Vote(turn_vote_centered_at(turn_dir))) ;
00429 }
00430 }
00431
00432
00433 viz_lock() ;
00434 m_attractive = Ft ;
00435 m_repulsive = Fr ;
00436 m_steering = R ;
00437 m_turn_dir = turn_dir ;
00438 viz_unlock() ;
00439 }
00440
00441
00442 void
00443 Goal::
00444 log(const char* msg, int index, const Goal::Target& goal, const Pose& p) const
00445 {
00446 int n = index + 1 ;
00447 const int N = m_goals.size()/2 + 1 ;
00448 if (Params::loop() && Params::backtrack() && n > N)
00449 n = N - (n - N) ;
00450
00451 Metrics::Log() << std::setw(Metrics::opw()) << std::left
00452 << (std::string(msg) + " #" + to_string(n))
00453 << goal << " from/at" << Metrics::newl()
00454 << dup_string(" ", 6 + Metrics::opw()) << p ;
00455 }
00456
00457
00458
00459 #ifdef INVT_HAVE_LIBGL
00460
00461
00462
00463 static std::string mag(char label, const Vector& v)
00464 {
00465 using namespace std ;
00466
00467 std::ostringstream v_str ;
00468 v_str << label << ": "
00469 << setw(8) << fixed << setprecision(1) << magnitude(v) ;
00470 return v_str.str() ;
00471 }
00472
00473 void Goal::render_me()
00474 {
00475
00476
00477 viz_lock() ;
00478 Vector A = m_attractive ;
00479 Vector R = m_repulsive ;
00480 Vector T = m_steering ;
00481 int turn = m_turn_dir ;
00482 viz_unlock() ;
00483
00484
00485
00486 unit_view_volume() ;
00487 glColor3f(1, 1, 1) ;
00488 glBegin(GL_LINES) ;
00489 glVertex2i(0, -1) ;
00490 glVertex2i(0, 1) ;
00491 glVertex2i(-1, 0) ;
00492 glVertex2i( 1, 0) ;
00493 glEnd() ;
00494
00495
00496 if (is_zero(T.i) && is_zero(T.j))
00497 ;
00498 else
00499 {
00500 glColor3f(0, 1, 0) ;
00501 draw_vector(normalized(A)) ;
00502
00503 glColor3f(1, 0, 0) ;
00504 draw_vector(normalized(R)) ;
00505
00506 glColor3f(0.15f, 0.75f, 0.85f) ;
00507 draw_vector(normalized(T)) ;
00508
00509 glColor3f(1, 1, 1) ;
00510 draw_vector(Vector(0.75f * cos(turn), 0.75f * sin(turn))) ;
00511 }
00512
00513
00514
00515
00516 restore_view_volume() ;
00517 text_view_volume() ;
00518 glColor3f(0, 1, 1) ;
00519 draw_label(3, 12, "Goal") ;
00520
00521 glColor3f(0, 1, 0) ;
00522 draw_label(3, m_geometry.height - 28, mag('A', A).c_str()) ;
00523
00524 glColor3f(1, 0, 0) ;
00525 draw_label(3, m_geometry.height - 16, mag('R', R).c_str()) ;
00526
00527 glColor3f(0.15f, 0.75f, 0.85f) ;
00528 draw_label(3, m_geometry.height - 4, mag('T', T).c_str()) ;
00529 restore_view_volume() ;
00530 }
00531
00532 void Goal::render_goals(unsigned long client_data)
00533 {
00534 (reinterpret_cast<Goal*>(client_data))->render_goals() ;
00535 }
00536
00537 void Goal::render_goals()
00538 {
00539
00540
00541
00542 float L, R, B, T ;
00543 SlamParams::map_extents(&L, &R, &B, &T) ;
00544 setup_view_volume(T, B, L, R) ;
00545
00546
00547 glPushAttrib(GL_POINT_BIT | GL_LINE_BIT) ;
00548 glPointSize(5) ;
00549 glColor3f(0, 0, 1) ;
00550 glBegin(GL_POINTS) ;
00551 std::for_each(m_goals.begin(), m_goals.end(), render_goal) ;
00552 glEnd() ;
00553
00554
00555 glEnable(GL_LINE_STIPPLE) ;
00556 glLineStipple(1, 0xCCCC) ;
00557 glColor3f(1, 0, 0) ;
00558 glBegin(GL_LINE_LOOP) ;
00559 const Target& current = m_goals[m_goal] ;
00560 glVertex2f(current.T(), current.L()) ;
00561 glVertex2f(current.B(), current.L()) ;
00562 glVertex2f(current.B(), current.R()) ;
00563 glVertex2f(current.T(), current.R()) ;
00564 glEnd() ;
00565 glPopAttrib() ;
00566
00567
00568 restore_view_volume() ;
00569 }
00570
00571 void Goal::render_goal(const Goal::Target& t)
00572 {
00573 glVertex2f(t.y(), t.x()) ;
00574 }
00575
00576 #endif
00577
00578
00579
00580 Goal::~Goal(){}
00581
00582
00583
00584 }
00585
00586
00587
00588
00589