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/LoLGMDExtricateTTI.H"
00046 #include "Robots/LoBot/control/LoMetrics.H"
00047 #include "Robots/LoBot/control/LoTurnArbiter.H"
00048 #include "Robots/LoBot/control/LoSpinArbiter.H"
00049 #include "Robots/LoBot/control/LoSpeedArbiter.H"
00050
00051 #include "Robots/LoBot/LoApp.H"
00052 #include "Robots/LoBot/slam/LoMap.H"
00053 #include "Robots/LoBot/config/LoConfigHelpers.H"
00054 #include "Robots/LoBot/thread/LoUpdateLock.H"
00055
00056 #include "Robots/LoBot/misc/LoExcept.H"
00057 #include "Robots/LoBot/misc/LoRegistry.H"
00058 #include "Robots/LoBot/misc/singleton.hh"
00059
00060 #include "Robots/LoBot/util/LoGL.H"
00061 #include "Robots/LoBot/util/LoMath.H"
00062
00063
00064 #ifdef INVT_HAVE_LIBGL
00065 #include <GL/gl.h>
00066 #endif
00067
00068
00069 #include <iomanip>
00070 #include <sstream>
00071 #include <algorithm>
00072 #include <limits>
00073
00074
00075
00076 namespace lobot {
00077
00078
00079
00080 namespace {
00081
00082
00083 template<typename T>
00084 inline T conf(const std::string& key, const T& default_value)
00085 {
00086 return get_conf<T>(LOBE_LGMD_EXTRICATE_TTI, key, default_value) ;
00087 }
00088
00089
00090
00091 class Params : public singleton<Params> {
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104 float m_threshold ;
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 int m_count ;
00116
00117
00118
00119
00120
00121
00122
00123
00124 float m_att_amp, m_rep_amp ;
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 float m_interference_threshold ;
00150
00151
00152
00153
00154
00155 float m_extricate_speed ;
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 int m_extricate_pwm ;
00166
00167
00168
00169
00170
00171
00172
00173
00174 bool m_spin_style_steering ;
00175
00176
00177
00178
00179 bool m_log_tti_predictions ;
00180
00181
00182
00183
00184
00185
00186
00187 int m_update_delay ;
00188
00189
00190
00191 typedef Drawable::Geometry Geom ;
00192 Drawable::Geometry m_geometry ;
00193
00194
00195 Params() ;
00196
00197
00198 friend class singleton<Params> ;
00199
00200 public:
00201
00202
00203 static float threshold() {return instance().m_threshold ;}
00204 static int count() {return instance().m_count ;}
00205 static float att_amp() {return instance().m_att_amp ;}
00206 static float rep_amp() {return instance().m_rep_amp ;}
00207 static float extricate_speed() {return instance().m_extricate_speed ;}
00208 static int extricate_pwm() {return instance().m_extricate_pwm ;}
00209 static bool spin_style_steering(){return instance().m_spin_style_steering;}
00210 static bool log_tti_predictions(){return instance().m_log_tti_predictions;}
00211 static int update_delay() {return instance().m_update_delay ;}
00212 static Geom geometry() {return instance().m_geometry ;}
00213 static float interference_threshold() {
00214 return instance().m_interference_threshold ;
00215 }
00216
00217 } ;
00218
00219
00220 Params::Params()
00221 : m_threshold(clamp(conf("threshold", 300.0f), 50.0f, 1000.0f)),
00222 m_count(clamp(conf("count", 3), 1, 180)),
00223 m_att_amp(conf("attractive_amplifier", 1.0f)),
00224 m_rep_amp(conf("repulsive_amplifier", 1.0f)),
00225 m_interference_threshold(conf("interference_threshold", 0.1f)),
00226 m_extricate_speed(clamp(conf("extricate_speed", 0.15f), 0.1f, 0.75f)),
00227 m_extricate_pwm(clamp(conf("extricate_pwm", 25), 10, 50)),
00228 m_spin_style_steering(conf("spin_style_steering", false)),
00229 m_log_tti_predictions(conf("log_tti_predictions", false)),
00230 m_update_delay(clamp(conf("update_delay", 150), 1, 1000)),
00231 m_geometry(conf<std::string>("geometry", "0 0 -1 -1"))
00232 {}
00233
00234 }
00235
00236
00237
00238 LGMDExtricateTTI::LGMDExtricateTTI()
00239 : base(Params::update_delay(), LOBE_LGMD_EXTRICATE_TTI, Params::geometry())
00240 {
00241 start(LOBE_LGMD_EXTRICATE_TTI) ;
00242 }
00243
00244 LGMDExtricateTTI::Command::Command()
00245 : drive(0), turn(0)
00246 {}
00247
00248
00249
00250
00251
00252 void LGMDExtricateTTI::pre_run()
00253 {
00254 if (! App::robot())
00255 throw behavior_error(MOTOR_SYSTEM_MISSING) ;
00256
00257 const App::LocustModels& L = App::locusts() ;
00258 const int N = L.size() ;
00259 m_tti.reserve(N) ;
00260 for (int i = 0; i < N; ++i)
00261 m_tti.push_back(new TTIEstimator(L[i])) ;
00262 }
00263
00264
00265
00266 static void log_tti_predictions(float speed, const TTIEstimator* E)
00267 {
00268 using std::setw ; using std::left ; using std::right ;
00269 using std::fixed ; using std::setprecision ;
00270
00271 Metrics::Log log ;
00272 log << setw(Metrics::opw()) << left << LOBE_LGMD_EXTRICATE_TTI
00273 << "TTI estimator info:" << Metrics::newl() ;
00274
00275 log << " current robot speed = " << fixed << setprecision(3)
00276 << speed << " m/s" << Metrics::newl();
00277
00278 log << " locust direction = " << fixed << setprecision(0)
00279 << E->locust_direction() << " degrees" << Metrics::newl() ;
00280 log << " LGMD spike rate = " << fixed << setprecision(0)
00281 << E->lgmd() << " Hz" << Metrics::newl() ;
00282
00283 log << " actual time-to-impact = "
00284 << fixed << setprecision(1) << setw(4) << right
00285 << E->actual_tti() << " seconds"<< Metrics::newl() ;
00286 log << "predicted time-to-impact = "
00287 << fixed << setprecision(1) << setw(4) << right
00288 << E->predicted_tti()<<" seconds"<< Metrics::newl() ;
00289
00290 log << " actual distance = "
00291 << fixed << setprecision(0) << setw(4) << right
00292 << E->actual_distance() << " mm" << Metrics::newl() ;
00293 log << " predicted distance = "
00294 << fixed << setprecision(0) << setw(4) << right
00295 << E->predicted_distance()<< " mm" << Metrics::newl() ;
00296
00297 log << " prediction confidence = " << fixed << setprecision(1)
00298 << E->confidence() * 100 << "%" ;
00299 }
00300
00301
00302
00303
00304
00305
00306
00307 void LGMDExtricateTTI::action()
00308 {
00309
00310
00311
00312 const int N = m_tti.size() ;
00313 UpdateLock::begin_read() ;
00314 for (int i = 0; i < N; ++i)
00315 m_tti[i]->copy_lgmd() ;
00316
00317 float speed = App::robot()->current_speed() ;
00318 float heading = App::robot()->current_heading() ;
00319 UpdateLock::end_read() ;
00320
00321
00322 if (speed < Params::interference_threshold()) {
00323 record_viz() ;
00324 return ;
00325 }
00326
00327
00328
00329 Vector velocity(speed * cos(heading), speed * sin(heading)) ;
00330 int count = 0 ;
00331 for (int i = 0; i < N; ++i)
00332 {
00333 TTIEstimator* estimator = m_tti[i] ;
00334 estimator->update() ;
00335 estimator->compute_distance(velocity) ;
00336 float D = estimator->distance() ;
00337 if (D > 0 && D <= Params::threshold())
00338 ++count ;
00339 if (Params::log_tti_predictions())
00340 log_tti_predictions(speed, estimator) ;
00341 }
00342
00343
00344
00345 Command C ;
00346 Vector A, R, F ;
00347 if (count >= Params::count())
00348 {
00349
00350 for (int i = 0; i < N; ++i)
00351 {
00352 const TTIEstimator* estimator = m_tti[i] ;
00353 float distance = estimator->distance() ;
00354 if (distance < 0)
00355 continue ;
00356 float e = distance - Params::threshold() ;
00357 if (e < 0)
00358 R += (Params::rep_amp() * e) * estimator->direction() ;
00359 else
00360 A += (Params::att_amp() * e) * estimator->direction() ;
00361 }
00362 F = A + R ;
00363
00364
00365 const int T = random(TurnArbiter::turn_step(), TurnArbiter::turn_max()) ;
00366 switch (quadrant(direction(F)))
00367 {
00368 case 1:
00369 C.drive = 1 ; C.turn = T ;
00370 break ;
00371 case 2:
00372 C.drive = -1 ; C.turn = -T ;
00373 break ;
00374 case 3:
00375 C.drive = -1 ; C.turn = T ;
00376 break ;
00377 case 4:
00378 C.drive = 1 ; C.turn = -T ;
00379 break ;
00380 default:
00381 throw misc_error(LOGIC_ERROR) ;
00382 }
00383
00384 if (Params::spin_style_steering())
00385 SpinArbiter::instance().vote(base::name,
00386 new SpinArbiter::Vote(C.turn)) ;
00387 else
00388 {
00389 SpeedArbiter::instance().vote(base::name,
00390 new SpeedArbiter::Vote(C.drive * Params::extricate_speed(),
00391 C.drive * Params::extricate_pwm())) ;
00392 TurnArbiter::instance().vote(base::name,
00393 new TurnArbiter::Vote(turn_vote_centered_at(C.turn))) ;
00394 }
00395
00396 Metrics::Log log ;
00397 log << std::setw(Metrics::opw()) << std::left << base::name ;
00398 Map* M = App::map() ;
00399 if (M)
00400 log << M->current_pose() ;
00401 }
00402 record_viz(A, R, F, C) ;
00403 }
00404
00405
00406 void
00407 LGMDExtricateTTI::
00408 record_viz(const Vector& att, const Vector& rep, const Vector& tot,
00409 const LGMDExtricateTTI::Command& cmd)
00410 {
00411 viz_lock() ;
00412 m_attractive = att ;
00413 m_repulsive = rep ;
00414 m_total_force = tot ;
00415 m_cmd = cmd ;
00416 viz_unlock() ;
00417 }
00418
00419
00420
00421 #ifdef INVT_HAVE_LIBGL
00422
00423
00424
00425 static std::string mag(char label, const Vector& v)
00426 {
00427 using namespace std ;
00428
00429 std::ostringstream v_str ;
00430 v_str << label << ": " << fixed << setprecision(1) << magnitude(v) ;
00431 return v_str.str() ;
00432 }
00433
00434
00435
00436 void LGMDExtricateTTI::render_me()
00437 {
00438
00439
00440 const int N = m_tti.size() ;
00441
00442 typedef std::pair<Vector, float> DDP ;
00443 std::vector<DDP> ddp ;
00444 ddp.reserve(N) ;
00445 float normalizer = std::numeric_limits<float>::min() ;
00446
00447 viz_lock() ;
00448 Command C = m_cmd ;
00449 Vector A = m_attractive ;
00450 Vector R = m_repulsive ;
00451 Vector T = m_total_force ;
00452
00453 for (int i = 0; i < N; ++i) {
00454 ddp.push_back(DDP(m_tti[i]->direction(), m_tti[i]->distance())) ;
00455 if (normalizer < m_tti[i]->distance())
00456 normalizer = m_tti[i]->distance() ;
00457 }
00458 viz_unlock() ;
00459 normalizer = 1/normalizer ;
00460
00461
00462
00463 unit_view_volume() ;
00464 glColor3f(1, 1, 1) ;
00465 glBegin(GL_LINES) ;
00466 glVertex2i(0, -1) ;
00467 glVertex2i(0, 1) ;
00468 glVertex2i(-1, 0) ;
00469 glVertex2i( 1, 0) ;
00470 glEnd() ;
00471
00472
00473 if (C.drive == 0 && C.turn == 0)
00474 ;
00475 else
00476 {
00477
00478 glBegin(GL_LINES) ;
00479 for (int i = 0; i < N; ++i)
00480 {
00481 if (ddp[i].second < 0)
00482 continue ;
00483 Vector d = (normalizer * ddp[i].second) * ddp[i].first ;
00484 if (ddp[i].second > Params::threshold())
00485 glColor3f(0, 0.8f, 0.2f) ;
00486 else
00487 glColor3f(0.8f, 0, 0.2f) ;
00488 glVertex2i(0, 0) ;
00489 glVertex2f(d.i, d.j) ;
00490 }
00491 glEnd() ;
00492
00493
00494 glColor3f(0, 1, 0) ;
00495 draw_vector(normalized(A)) ;
00496
00497 glColor3f(1, 0, 0) ;
00498 draw_vector(normalized(R)) ;
00499
00500 glColor3f(0.15f, 0.75f, 0.85f) ;
00501 draw_vector(normalized(T)) ;
00502
00503
00504 glColor3f(1, 1, 1) ;
00505 draw_vector(Vector(0.75f * C.drive * cos(C.turn), 0.75f * sin(C.turn))) ;
00506 }
00507
00508
00509
00510 restore_view_volume() ;
00511 text_view_volume() ;
00512 glColor3f(0, 1, 1) ;
00513 draw_label(3, 12, "LGMD Ext. TTI") ;
00514
00515 glColor3f(0, 1, 0) ;
00516 draw_label(3, m_geometry.height - 28, mag('A', A).c_str()) ;
00517
00518 glColor3f(1, 0, 0) ;
00519 draw_label(3, m_geometry.height - 16, mag('R', R).c_str()) ;
00520
00521 glColor3f(0.15f, 0.75f, 0.85f) ;
00522 draw_label(3, m_geometry.height - 4, mag('T', T).c_str()) ;
00523 restore_view_volume() ;
00524 }
00525
00526 #endif
00527
00528
00529
00530 LGMDExtricateTTI::~LGMDExtricateTTI()
00531 {
00532 purge_container(m_tti) ;
00533 }
00534
00535
00536
00537 }
00538
00539
00540
00541
00542