LoRobot.H

Go to the documentation of this file.
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: */
Generated on Sun May 8 08:05:54 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3