00001 /** 00002 \file Robots/LoBot/io/LoRobot.H 00003 \brief Abstract interface for the robot's sensorimotor system. 00004 00005 This file defines an abstract base class that provides a high-level 00006 API for moving and steering the robot. This class also provides a 00007 Sensor object that holds the current values of the robot's sensors. 00008 Communication with the robot platform is achieved over a serial port. 00009 00010 Different derived classes, by implementing the inner workings of this 00011 API, can be used to command different robot platforms and keep track 00012 of their sensors (e.g., a hacked R/C car or a Roomba). 00013 */ 00014 00015 // //////////////////////////////////////////////////////////////////// // 00016 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00017 // University of Southern California (USC) and the iLab at USC. // 00018 // See http://iLab.usc.edu for information about this project. // 00019 // //////////////////////////////////////////////////////////////////// // 00020 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00021 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00022 // in Visual Environments, and Applications'' by Christof Koch and // 00023 // Laurent Itti, California Institute of Technology, 2001 (patent // 00024 // pending; application number 09/912,225 filed July 23, 2001; see // 00025 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00026 // //////////////////////////////////////////////////////////////////// // 00027 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00028 // // 00029 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00030 // redistribute it and/or modify it under the terms of the GNU General // 00031 // Public License as published by the Free Software Foundation; either // 00032 // version 2 of the License, or (at your option) any later version. // 00033 // // 00034 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00035 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00036 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00037 // PURPOSE. See the GNU General Public License for more details. // 00038 // // 00039 // You should have received a copy of the GNU General Public License // 00040 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00041 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00042 // Boston, MA 02111-1307 USA. // 00043 // //////////////////////////////////////////////////////////////////// // 00044 // 00045 // Primary maintainer for this file: mviswana usc edu 00046 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/io/LoRobot.H $ 00047 // $Id: LoRobot.H 13782 2010-08-12 18:21:14Z mviswana $ 00048 // 00049 00050 #ifndef LOBOT_ROBOT_DOT_H 00051 #define LOBOT_ROBOT_DOT_H 00052 00053 //------------------------------ HEADERS -------------------------------- 00054 00055 // lobot headers 00056 #include "Robots/LoBot/io/LoSerial.H" 00057 #include "Robots/LoBot/thread/LoMutex.H" 00058 #include "Robots/LoBot/util/LoBits.H" 00059 00060 // INVT model manager stuff 00061 #include "Component/ModelManager.H" 00062 00063 // Standard C++ headers 00064 #include <vector> 00065 #include <utility> 00066 00067 //----------------------------- NAMESPACE ------------------------------- 00068 00069 namespace lobot { 00070 00071 //------------------------- CLASS DEFINITION ---------------------------- 00072 00073 /** 00074 \class lobot::Robot 00075 \brief High-level API for driving and steering the robot and keeping 00076 track of its sensors. 00077 00078 The Robolocust controller may run on different kinds of robots (e.g., 00079 a hacked R/C car or a Roomba). All these robots are expected to be 00080 driven and queried for their sensors using a common interface as 00081 specified by this abstract base class. Derived classes will implement 00082 the actual innards of the interface for the different robots they are 00083 written for. These derived classes will be instantiated using a 00084 polymorphic factory and a config file setting. 00085 */ 00086 class Robot { 00087 protected: 00088 /// The low-level serial device interface. 00089 /// 00090 /// DEVNOTE: We need to qualify the Serial class name with the 00091 /// namespace because LoSerial.H may use either libserial's SerialPort 00092 /// class or INVT's Serial class. If it is using INVT's serial 00093 /// support, then that class name will clash with the Robolocust 00094 /// Serial class encapsulating serial communications. 00095 lobot::Serial m_serial ; 00096 00097 public: 00098 /// Client modules interact with the physical robot platform via an 00099 /// instance of this (the Robot) class, which provides a common API 00100 /// for controlling the robot's motors and for reading its current 00101 /// sensor values. 00102 /// 00103 /// The robot's sensors are encapsulated using the Sensors inner class 00104 /// defined below. So as to maintain a common interface for all 00105 /// different robot platforms, this inner class needs to include 00106 /// fields for all the different sensors across all platforms. Sensors 00107 /// not relevant to the platform currently in use will be zeroed out. 00108 /// Clients should check the current platform before using those 00109 /// fields. 00110 /// 00111 /// For example, if the Roomba platform is being used, then the PWM 00112 /// and RPM sensor fields will not be relevant. Similarly, if the 00113 /// hacked R/C car is being used, then the cliff and wheel drop 00114 /// sensors will not make any sense. 00115 /// 00116 /// Thus, clients should determine which robot platform is being used 00117 /// before reading and using the sensor values stored in this class. 00118 /// This can be done by looking up the "platform" setting in the 00119 /// "robot" section of the lobot config file. Alternatively, we can 00120 /// write separate behaviours for different platforms and configure 00121 /// lobot to start the right set of behaviours depending on the robot 00122 /// platform being used. 00123 /// 00124 /// DEVNOTE: This inner class is a do-it-all interface and represents 00125 /// a design choke point. Every time lobot is extended to support 00126 /// another robot platform, this beast here will have to be hacked to 00127 /// include yet more fields to hold the sensor values for the new 00128 /// platform. 00129 /// 00130 /// Another way to implement this functionality might have been to 00131 /// implement a SensorBase class here and have every class derived 00132 /// from lobot::Robot provide its own Sensor class/struct containing 00133 /// only the relevant sensor fields. But because each robot platform 00134 /// can be quite different from every other, the SensorBase class 00135 /// defined here would be practically useless as a uniting interface 00136 /// and clients would have to use dynamic casts and/or RTTI to get the 00137 /// right type depending on the robot platform in use. 00138 /// 00139 /// The approach outlined above does not seem to be any more palatable 00140 /// than having this do-it-all class here. In fact, from clients' 00141 /// perspectives, this do-it-all interface may actually be nicer than 00142 /// having to know different types and cast as required. 00143 /// 00144 /// One other possibility is to not really have a statically typed 00145 /// class at all. Instead, we could use a "sensors database" that maps 00146 /// sensor names to values with both keys and values being strings 00147 /// (like the lobot configuration database). The Sensors API 00148 /// implemented here would then simply be map look-ups with return 00149 /// values being converted from strings to ints, floats, chars, 00150 /// whatever using a bunch of template functions (again, much as is 00151 /// done in the lobot configuration database). 00152 /// 00153 /// This way, clients would get a uniform interface to any robot's 00154 /// sensors. And the sensors interface defined here would simply be a 00155 /// key-value database that wouldn't need to be hacked each time the 00156 /// system is extended to support a new robot platform. Furthermore, 00157 /// each lobot::Robot derived class will have the ability/freedom to 00158 /// define any kind of sensor type without having to worry about 00159 /// conforming to some predetermined set of sensor types that can 00160 /// exist. 00161 /// 00162 /// Unfortunately, at this time (circa mid-Jan 2010), the "right" way 00163 /// to do it as described above will take more time than is available. 00164 /// Moreover, since development focus has now shifted to the Roomba 00165 /// (with the hacked R/C car platform being abandoned due to far too 00166 /// many hardware instabilities), the do-it-all approach is deemed an 00167 /// acceptable compromise. Eventually, when we get around to seriously 00168 /// adding support in this robot control framework for different 00169 /// platforms, the key-value database approach would be the way to go. 00170 class Sensors { 00171 /// Since this class is used to keep track of the "current" sensor 00172 /// values and many things happen asynchronously in the lobot 00173 /// controller, it is useful to know when the sensor readings were 00174 /// made. 00175 long long m_time_stamp ; 00176 00177 /// Regardless of the robot platform, all classes derived from 00178 /// lobot::Robot will have to compute and update the current speed 00179 /// and heading because the speed and turn arbiters and behaviours 00180 /// all work in terms of those "fundamental" values. 00181 /// 00182 /// NOTE: The robot platform may not actually have sensors that 00183 /// directly report the current speed and heading. However, since 00184 /// all robot platforms are required to compute and update these 00185 /// values, it makes sense to have these fields in this class. 00186 /// Thus, conceptually, clients can work as if each supported robot 00187 /// platform has speed and heading sensors regardless of whether 00188 /// such things physically exist or not. 00189 float m_speed, m_heading ; 00190 00191 /// The current values of the low-level motor duty cycles. These 00192 /// PWM values are sent to and received from the Propeller I/O 00193 /// board. 00194 /// 00195 /// As can be told by mention of the Propeller: these sensors are 00196 /// related to the hacked R/C car platform. 00197 int m_motor_pwm, m_servo_pwm ; 00198 00199 /// The RPM sensor's value. This sensor is also applicable only to 00200 /// the hacked R/C car platform. 00201 float m_rpm ; 00202 00203 /// The Roomba's bump and wheel drop sensors. 00204 /// 00205 /// NOTE: The front bump sensors are built into the iRobot Create 00206 /// platform. lobot, however, sports an additional bumper assembly 00207 /// on its rear. 00208 int m_bump, m_wheel_drops ; 00209 enum { // bit masks for above fields 00210 BUMP_REAR_LEFT = 8, 00211 BUMP_REAR_RIGHT = 4, 00212 BUMP_LEFT = 2, 00213 BUMP_RIGHT = 1, 00214 00215 WHEEL_DROP_LEFT = 4, 00216 WHEEL_DROP_RIGHT = 2, 00217 WHEEL_DROP_CASTER = 1, 00218 } ; 00219 00220 /// The Roomba's wall sensors and signal strength. 00221 int m_walls, m_wall_signal ; 00222 enum { // bit masks for above fields 00223 VIRTUAL_WALL = 2, 00224 WALL = 1, 00225 } ; 00226 00227 /// The Roomba's cliff sensors and signal strengths. 00228 int m_cliff, m_cliff_signals[4] ; 00229 enum { // bit masks and indices for above fields 00230 CLIFF_LEFT = 8, 00231 CLIFF_RIGHT = 4, 00232 CLIFF_FRONT_LEFT = 2, 00233 CLIFF_FRONT_RIGHT = 1, 00234 00235 LEFT_SIGNAL = 0, 00236 RIGHT_SIGNAL, 00237 FRONT_LEFT_SIGNAL, 00238 FRONT_RIGHT_SIGNAL, 00239 } ; 00240 00241 /// The Roomba's infrared byte, distance and angle measurements, 00242 /// and battery charge. 00243 int m_infrared, m_distance, m_angle, m_battery_charge ; 00244 00245 /// Flag indicating whether the encoder info returned by Roomba 00246 /// contains result from most recent SPIN (i.e., in-place turn) 00247 /// command. 00248 bool m_spin_flag ; 00249 00250 /// The Roomba's most recently requested drive speed and turn 00251 /// radius. 00252 int m_requested_speed, m_requested_radius ; 00253 00254 /// Private default constructor because we only want the Robot 00255 /// class to be able to instantiate the Sensors class. 00256 Sensors() ; 00257 friend class Robot ; 00258 00259 public: 00260 /// Public copy constructor; it is okay for client modules to make 00261 /// copies of the sensor data (but only the Robot class can create 00262 /// an instance from scratch). 00263 Sensors(const Sensors&) ; 00264 00265 /// Accessors for the different sensor values. 00266 //@{ 00267 long long time_stamp() const {return m_time_stamp ;} 00268 float speed() const {return m_speed ;} 00269 float heading() const {return m_heading ;} 00270 00271 int motor_pwm() const {return m_motor_pwm ;} 00272 int servo_pwm() const {return m_servo_pwm ;} 00273 float rpm() const {return m_rpm ;} 00274 00275 bool bump_left() const {return m_bump & BUMP_LEFT ;} 00276 bool bump_right() const {return m_bump & BUMP_RIGHT ;} 00277 bool bump_both() const {return bump_left() && bump_right() ;} 00278 bool bump_front() const {return bump_left() || bump_right() ;} 00279 bool bump_rear_left() const {return m_bump & BUMP_REAR_LEFT ;} 00280 bool bump_rear_right() const {return m_bump & BUMP_REAR_RIGHT ;} 00281 bool bump_rear_both() const { 00282 return bump_rear_left() && bump_rear_right() ; 00283 } 00284 bool bump_rear() const {return bump_rear_left() || bump_rear_right() ;} 00285 bool bump() const {return bump_front() || bump_rear() ;} 00286 00287 bool wheel_drop_left() const{return m_wheel_drops & WHEEL_DROP_LEFT ;} 00288 bool wheel_drop_right() const{return m_wheel_drops & WHEEL_DROP_RIGHT ;} 00289 bool wheel_drop_caster() const{return m_wheel_drops & WHEEL_DROP_CASTER;} 00290 bool wheel_drop_all() const{ 00291 return wheel_drop_left() && wheel_drop_right() && wheel_drop_caster(); 00292 } 00293 bool wheel_drop() const { 00294 return wheel_drop_left() || wheel_drop_right() || wheel_drop_caster(); 00295 } 00296 00297 bool wall() const {return m_walls & WALL ;} 00298 bool virtual_wall() const {return m_walls & VIRTUAL_WALL ;} 00299 int wall_signal() const {return m_wall_signal ;} 00300 bool wall(int threshold) const { 00301 return wall() && wall_signal() >= threshold ; 00302 } 00303 00304 bool cliff_left() const {return m_cliff & CLIFF_LEFT ;} 00305 bool cliff_right() const {return m_cliff & CLIFF_RIGHT ;} 00306 bool cliff_front_left() const {return m_cliff & CLIFF_FRONT_LEFT ;} 00307 bool cliff_front_right() const {return m_cliff & CLIFF_FRONT_RIGHT ;} 00308 bool cliff_all() const { 00309 return cliff_left() && cliff_right() 00310 && cliff_front_left() && cliff_front_right() ; 00311 } 00312 bool cliff() const { 00313 return cliff_left() || cliff_right() 00314 || cliff_front_left() || cliff_front_right() ; 00315 } 00316 int cliff_signal_left() const {return m_cliff_signals[LEFT_SIGNAL] ;} 00317 int cliff_signal_right() const {return m_cliff_signals[RIGHT_SIGNAL] ;} 00318 int cliff_signal_front_left() const { 00319 return m_cliff_signals[FRONT_LEFT_SIGNAL] ; 00320 } 00321 int cliff_signal_front_right() const { 00322 return m_cliff_signals[FRONT_RIGHT_SIGNAL] ; 00323 } 00324 inline bool cliff(int threshold) const ; 00325 00326 int infrared() const {return m_infrared ;} 00327 int distance() const {return m_distance ;} 00328 int angle() const {return m_angle ;} 00329 bool spin() const {return m_spin_flag;} 00330 00331 int battery_charge() const {return m_battery_charge ;} 00332 int requested_speed() const {return m_requested_speed ;} 00333 int requested_radius() const {return m_requested_radius ;} 00334 //@} 00335 } ; 00336 00337 protected: 00338 /// The robot's current sensor values are all maintained in an 00339 /// instance of the Sensors inner class defined above. Derived classes 00340 /// are expected to update this object and client modules may retrieve 00341 /// a reference to it to examine the robot's current state. 00342 Sensors m_sensors ; 00343 00344 /// Protected API for setting sensor values because only derived 00345 /// classes (i.e., concrete robot platforms) should be allowed to 00346 /// update the robot's sensor state. 00347 //@{ 00348 void time_stamp(long long ts) {m_sensors.m_time_stamp = ts ;} 00349 00350 void speed(float s) {m_sensors.m_speed = s ;} 00351 void heading(float h) {m_sensors.m_heading = h ;} 00352 00353 void motor_pwm(int p) {m_sensors.m_motor_pwm = p ;} 00354 void servo_pwm(int p) {m_sensors.m_servo_pwm = p ;} 00355 void rpm(float r) {m_sensors.m_rpm = r ;} 00356 00357 void bump_left(bool b) { 00358 m_sensors.m_bump = set_bit(m_sensors.m_bump, Sensors::BUMP_LEFT, b) ; 00359 } 00360 void bump_right(bool b) { 00361 m_sensors.m_bump = set_bit(m_sensors.m_bump, Sensors::BUMP_RIGHT, b) ; 00362 } 00363 void bump_rear_left(bool b) { 00364 m_sensors.m_bump = set_bit(m_sensors.m_bump, Sensors::BUMP_REAR_LEFT, b); 00365 } 00366 void bump_rear_right(bool b) { 00367 m_sensors.m_bump = set_bit(m_sensors.m_bump, Sensors::BUMP_REAR_RIGHT,b); 00368 } 00369 00370 void wheel_drop_left(bool b) { 00371 m_sensors.m_wheel_drops = 00372 set_bit(m_sensors.m_wheel_drops, Sensors::WHEEL_DROP_LEFT, b) ; 00373 } 00374 void wheel_drop_right(bool b) { 00375 m_sensors.m_wheel_drops = 00376 set_bit(m_sensors.m_wheel_drops, Sensors::WHEEL_DROP_RIGHT, b) ; 00377 } 00378 void wheel_drop_caster(bool b) { 00379 m_sensors.m_wheel_drops = 00380 set_bit(m_sensors.m_wheel_drops, Sensors::WHEEL_DROP_CASTER, b) ; 00381 } 00382 00383 void wall(bool b) { 00384 m_sensors.m_walls = set_bit(m_sensors.m_walls, Sensors::WALL, b) ; 00385 } 00386 void virtual_wall(bool b) { 00387 m_sensors.m_walls = set_bit(m_sensors.m_walls, Sensors::VIRTUAL_WALL, b); 00388 } 00389 void wall_signal(int s) {m_sensors.m_wall_signal = s ;} 00390 00391 void cliff_left(bool b) { 00392 m_sensors.m_cliff = set_bit(m_sensors.m_cliff, Sensors::CLIFF_LEFT, b) ; 00393 } 00394 void cliff_right(bool b) { 00395 m_sensors.m_cliff = set_bit(m_sensors.m_cliff, Sensors::CLIFF_RIGHT, b) ; 00396 } 00397 void cliff_front_left(bool b) { 00398 m_sensors.m_cliff = 00399 set_bit(m_sensors.m_cliff, Sensors::CLIFF_FRONT_LEFT, b) ; 00400 } 00401 void cliff_front_right(bool b) { 00402 m_sensors.m_cliff = 00403 set_bit(m_sensors.m_cliff, Sensors::CLIFF_FRONT_RIGHT, b) ; 00404 } 00405 00406 void cliff_left_signal (int s) { 00407 m_sensors.m_cliff_signals[Sensors::LEFT_SIGNAL] = s ; 00408 } 00409 void cliff_right_signal(int s) { 00410 m_sensors.m_cliff_signals[Sensors::RIGHT_SIGNAL] = s ; 00411 } 00412 void cliff_front_left_signal (int s) { 00413 m_sensors.m_cliff_signals[Sensors::FRONT_LEFT_SIGNAL] = s ; 00414 } 00415 void cliff_front_right_signal(int s) { 00416 m_sensors.m_cliff_signals[Sensors::FRONT_RIGHT_SIGNAL] = s ; 00417 } 00418 00419 void infrared(int i) {m_sensors.m_infrared = i ;} 00420 void distance(int d) {m_sensors.m_distance = d ;} 00421 void angle(int a) {m_sensors.m_angle = a ;} 00422 void spin_flag(bool f) {m_sensors.m_spin_flag = f ;} 00423 00424 void battery_charge(int c) {m_sensors.m_battery_charge = c ;} 00425 void requested_speed (int s) {m_sensors.m_requested_speed = s ;} 00426 void requested_radius(int r) {m_sensors.m_requested_radius = r ;} 00427 //@} 00428 00429 public: 00430 /// Usually, when a behaviour or other client module wants to know the 00431 /// current sensor state, it can simply query the robot interface 00432 /// object (via lobot::App) for the desired data. However, in certain 00433 /// situations, a behaviour might want to be informed about low-level 00434 /// sensor updates as soon as they come in. For example, if a 00435 /// behaviour is performing odometry-based localization, it cannot 00436 /// afford to miss low-level sensor updates by querying in its action 00437 /// method because it could well get incorrect odometric info by the 00438 /// time the behaviour's main loop's next iteration kicks in. 00439 /// 00440 /// The robot interface object, therefore, maintains a list of 00441 /// callback functions, which it calls one-by-one right after the main 00442 /// thread updates the robot's sensor state. These types define the 00443 /// sensor hook functions. 00444 /// 00445 /// NOTE: The sensor hooks are executed in the context of the main 00446 /// thread. So, clients should take appropriate measures to protect 00447 /// any shared data structures that are used in the hook functions. 00448 /// Furthermore, to avoid delaying the main thread, clients should 00449 /// keep the processing within these hook functions to a minimum. 00450 //@{ 00451 typedef void (*SensorUpdateCB)(const Sensors&, unsigned long client_data) ; 00452 typedef std::pair<SensorUpdateCB, unsigned long> SensorHook ; 00453 //@} 00454 00455 private: 00456 /// This data structure holds the hook functions. 00457 std::vector<SensorHook> m_sensor_hooks ; 00458 00459 /// Because the list of sensor hooks can be accessed in multiple 00460 /// threads, we need a mutex to synchronize simultaneous accesses. 00461 Mutex m_sensor_hooks_mutex ; 00462 00463 public: 00464 /// Client modules can retrieve the current sensor values by using 00465 /// this API. 00466 const Sensors& sensors() const {return m_sensors ;} 00467 00468 /// Retrieving the robot's current speed and heading. 00469 //@{ 00470 float current_speed() const {return m_sensors.speed() ;} 00471 float current_heading() const {return m_sensors.heading() ;} 00472 //@} 00473 00474 /// Adding a sensor hook so as to be informed about low-level sensor 00475 /// updates as soon as they happen. 00476 void add_hook(const SensorHook&) ; 00477 00478 protected: 00479 /// A protected constructor because motor classes are instantiated via 00480 /// a factory and a config file setting rather than directly by client 00481 /// modules. 00482 Robot(const ModelManager&, const std::string& device, int baud_rate) ; 00483 00484 public: 00485 /// Clients must issue drive commands using both a speed expressed in 00486 /// m/s and a PWM value. 00487 /// 00488 /// The reason we require clients to supply both is because some robot 00489 /// platforms will support a speed command whereas others only provide 00490 /// for PWM commands. Robot platforms that support both can choose one 00491 /// type of command over the other based on config file settings, 00492 /// sensor readings, etc. Either ways, this decision is up to 00493 /// individual derived classes. 00494 /// 00495 /// DEVNOTE: Since this method will change the internal state of the 00496 /// motor system (which is shared by many behaviours/modules), clients 00497 /// should protect calls to it using lobot::UpdateLock. 00498 virtual void drive(float speed, int pwm) = 0 ; 00499 00500 /// Command the robot to steer towards the specified direction 00501 /// (expressed in degrees). Zero degrees is for driving straight 00502 /// ahead; positive (ccw) angles are for heading left and negative 00503 /// (cw) angles for heading right. 00504 /// 00505 /// DEVNOTE: Since this method will change the internal state of the 00506 /// motor system (which is shared by many behaviours/modules), clients 00507 /// should protect calls to it using lobot::UpdateLock. 00508 virtual void turn(float direction) = 0 ; 00509 00510 /// Command the robot to spin in-place by the specified angle 00511 /// (expressed in degrees). Positive angles result in counterclockwise 00512 /// in-place turns and negative angles in clockwise in-place turns. 00513 /// 00514 /// DEVNOTE: Since this method will change the internal state of the 00515 /// motor system (which is shared by many behaviours/modules), clients 00516 /// should protect calls to it using lobot::UpdateLock. 00517 virtual void spin(float angle) = 0 ; 00518 00519 /// This method is meant to be called by the Robolocust main thread as 00520 /// part of the sensorimotor update loop. It should not be called by 00521 /// any other modules. The idea here is that the main thread updates 00522 /// all the sensors and motor systems while all other behaviours and 00523 /// modules simply read the latest measurements or motor states. 00524 /// 00525 /// DEVNOTE: Since this method will change the internal state of the 00526 /// motor system (which is shared by many behaviours/modules), clients 00527 /// should protect calls to it using lobot::UpdateLock. 00528 void update() ; 00529 00530 private: 00531 /// All concrete robot interface objects must define this method for 00532 /// updating the low-level sensors. This method is invoked by 00533 /// lobot::Robot::update(). Once this method is done, the base class 00534 /// will trigger the sensor hooks. 00535 /// 00536 /// The base class expects this method to return a flag indicating 00537 /// whether or not sensors were actually updated and, thus, whether 00538 /// or not the sensor hooks need to be triggered. If there truly is a 00539 /// new sensor packet sent by the low-level controller, this method 00540 /// should return true; false otherwise. 00541 /// 00542 /// NOTE: It is crucial that derived classes encapsulating concrete 00543 /// robot platforms correctly handle the return value of this 00544 /// function. Otherwise, it is possible for client sensor hooks to be 00545 /// called multiple times with the same packet, which can lead to odd 00546 /// behaviour in client modules (e.g., a localization module may end 00547 /// up applying the same odometry over and over again, resulting in a 00548 /// horrendously mislocalized robot). 00549 virtual bool update_sensors() = 0 ; 00550 00551 public: 00552 /// Query the motor subsystem to see if the robot is currently moving 00553 /// or stationary. 00554 /// 00555 /// NOTE: Derived classes may override this method if they wish to 00556 /// implement it in a different way from the default, which is to 00557 /// simply check if the speed is zero. 00558 virtual bool stopped() const ; 00559 00560 /// A convenience function for stopping the robot and straightening 00561 /// its wheels. 00562 /// 00563 /// NOTE: The default implementation of this function simply issues 00564 /// drive and turn commands with zero as the parameters. However, 00565 /// derived classes may want to override this implementation if their 00566 /// particular robot platforms provide different or better ways to 00567 /// turn the motor system off. 00568 virtual void off() ; 00569 00570 /// Clean-up. 00571 virtual ~Robot() ; 00572 } ; 00573 00574 //---------------------- INLINE MEMBER FUNCTIONS ------------------------ 00575 00576 // Return true if a cliff is detected and that cliff's signal strength 00577 // exceeds the supplied threshold. 00578 inline bool Robot::Sensors::cliff(int threshold) const 00579 { 00580 return (cliff_left() && cliff_signal_left() >= threshold) 00581 || (cliff_right() && cliff_signal_right() >= threshold) 00582 || (cliff_front_left() && cliff_signal_front_left() >= threshold) 00583 || (cliff_front_right() && cliff_signal_front_right() >= threshold) ; 00584 } 00585 00586 //----------------------------------------------------------------------- 00587 00588 } // end of namespace encapsulating this file's definitions 00589 00590 #endif 00591 00592 /* So things look consistent in everyone's emacs... */ 00593 /* Local Variables: */ 00594 /* indent-tabs-mode: nil */ 00595 /* End: */