LoRoombaCM.H

Go to the documentation of this file.
00001 /**
00002    \file  Robots/LoBot/io/LoRoombaCM.H
00003    \brief Interface for driving the iRobot's Create/Roomba via its
00004    Command Module (hence the CM in the class name).
00005 
00006    This file defines a class that implements the sensorimotor interface
00007    defined in LoRobot.H for the Create/Roomba.
00008 */
00009 
00010 // //////////////////////////////////////////////////////////////////// //
00011 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00012 // University of Southern California (USC) and the iLab at USC.         //
00013 // See http://iLab.usc.edu for information about this project.          //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00016 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00017 // in Visual Environments, and Applications'' by Christof Koch and      //
00018 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00019 // pending; application number 09/912,225 filed July 23, 2001; see      //
00020 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00021 // //////////////////////////////////////////////////////////////////// //
00022 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00023 //                                                                      //
00024 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00025 // redistribute it and/or modify it under the terms of the GNU General  //
00026 // Public License as published by the Free Software Foundation; either  //
00027 // version 2 of the License, or (at your option) any later version.     //
00028 //                                                                      //
00029 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00030 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00031 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00032 // PURPOSE.  See the GNU General Public License for more details.       //
00033 //                                                                      //
00034 // You should have received a copy of the GNU General Public License    //
00035 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00036 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00037 // Boston, MA 02111-1307 USA.                                           //
00038 // //////////////////////////////////////////////////////////////////// //
00039 //
00040 // Primary maintainer for this file: mviswana usc edu
00041 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/io/LoRoombaCM.H $
00042 // $Id: LoRoombaCM.H 13770 2010-08-08 06:49:50Z mviswana $
00043 //
00044 
00045 #ifndef LOBOT_ROOMBA_CM_DOT_H
00046 #define LOBOT_ROOMBA_CM_DOT_H
00047 
00048 //------------------------------ HEADERS --------------------------------
00049 
00050 // lobot headers
00051 #include "Robots/LoBot/io/LoRobot.H"
00052 #include "Robots/LoBot/io/LoSerial.H"
00053 
00054 #include "Robots/LoBot/thread/LoMutex.H"
00055 #include "Robots/LoBot/thread/LoThread.H"
00056 
00057 #include "Robots/LoBot/misc/factory.hh"
00058 #include "Robots/LoBot/misc/wma.hh"
00059 
00060 #include "Robots/LoBot/irccm/LoCMInterface.h" // iface to low-level controller
00061 
00062 // INVT model manager stuff
00063 #include "Component/ModelManager.H"
00064 
00065 // Standard C++ headers
00066 #include <string>
00067 #include <queue>
00068 #include <memory>
00069 
00070 //----------------------------- NAMESPACE -------------------------------
00071 
00072 namespace lobot {
00073 
00074 //------------------------- CLASS DEFINITION ----------------------------
00075 
00076 /**
00077    \class lobot::RoombaCM
00078    \brief High-level API for driving and steering the Roomba and
00079    retrieving its sensor data.
00080 
00081    This class sends the drive and turn commands used by the Robolocust
00082    speed and turn arbiters to the Roomba over a serial port. It expects
00083    that the other end of the serial port is connected to an iRobot Create
00084    Command Module (hence the "CM" moniker in this class's name) running
00085    the low-level Robolocust control program, which listens for high-level
00086    motor commands to come in and then executes them in terms of the motor
00087    primitives actually supported by the Roomba.
00088 
00089    In addition to sending motor control commands, this class also
00090    retrieves the Roomba's sensor data.
00091 */
00092 class RoombaCM : public Robot {
00093    // Handy type to have around in a derived class
00094    typedef Robot base ;
00095 
00096    // Boilerplate code to make the generic factory design pattern work
00097    friend  class subfactory<RoombaCM, base, ModelManager> ;
00098    typedef register_factory<RoombaCM, base, ModelManager> my_factory ;
00099    static  my_factory register_me ;
00100 
00101    /// We update the robot's current speed by querying the Create/Roomba
00102    /// for the distance traveled since the last update and then dividing
00103    /// that distance by the time since the last update. Obviously, for
00104    /// this to work properly, we will need to store the time stamp of
00105    /// the most recent sensor packet update. This data member does just
00106    /// that.
00107    long long m_prev_time_stamp ;
00108 
00109    /// For the most part, gauging the robot's current speed by dividing
00110    /// the distance traveled since last update by time elapsed since
00111    /// last update works surprisingly well. However, there is still a
00112    /// fair amount of noisiness to the computed speed values. We use a
00113    /// low-pass filter to stabilize these computations.
00114    wma<float> m_speed_filter ;
00115 
00116    /// Private constructor because the interface object for a robot's
00117    /// motor subsystem is created using a factory.
00118    ///
00119    /// DEVNOTE: We need an INVT ModelManager because INVT's serial
00120    /// communications class requires it.
00121    RoombaCM(const ModelManager&) ;
00122 
00123    /// Clients must issue drive commands using both a speed expressed in
00124    /// m/s and a PWM value. The Roomba doesn't require or use the PWM
00125    /// value. However, as other robot classes do, it is part of the
00126    /// interface.
00127    void drive(float speed, int pwm = 0) ;
00128 
00129    /// Command the robot to turn towards the specified direction
00130    /// (expressed in degrees). Zero degrees is for driving straight
00131    /// ahead; positive (ccw) angles are for heading left and negative
00132    /// (cw) angles for heading right.
00133    void turn(float direction) ;
00134 
00135    /// Command the robot to spin in-place by the specified angle
00136    /// (expressed in degrees). Positive angles result in ccw in-place
00137    /// turns while negative angles are for cw in-place turns.
00138    void spin(float angle) ;
00139 
00140    /// Shut off the robot's drive motors.
00141    void off() ;
00142 
00143    /// Get the current speed, heading and other sensor values supported
00144    /// by the robot platform.
00145    bool update_sensors() ;
00146 
00147    /// Send a high-level command plus its parameter to the low-level
00148    /// control program running on the Command Module. (This function
00149    /// actually buffers the command with the Comm thread.)
00150    void send_roomba(int cmd, int param = 0) ;
00151 
00152    /// The interface to the low-level control program running on the
00153    /// iRobot Create/Roomba's Command Module works as follows: it first
00154    /// sends a READY acknowledgement over its USB port and then waits for
00155    /// a response. The higher layers of the Robolocust controller (viz.,
00156    /// this class's instance) must then send back the command it wants
00157    /// the robot to execute.
00158    ///
00159    /// Each such command consists of four bytes. The first byte is the
00160    /// motor command or sensor query ID. The next two bytes are the
00161    /// parameter for the command (e.g., drive forward at 100 mm/s). The
00162    /// last byte is a checksum: basically, just a parity byte computed by
00163    /// XOR-ing the other three bytes.
00164    ///
00165    /// If the low-level controller doesn't get back its 4-byte response
00166    /// to its ACK_READY message within some predefined timeout limit
00167    /// (compiled into the low-level program; usually, in the order of one
00168    /// to two seconds), it will assume that the higher layers are dead
00169    /// and stop the robot (until it hears from the high level again).
00170    ///
00171    /// We need this somewhat convoluted architecture because the Command
00172    /// Module's ATmega168 microcontroller only has one USART that can
00173    /// either talk to the USB port or to the robot's internal serial
00174    /// port. Therefore, we have to keep switching the USART between the
00175    /// two destinations and must ensure that the high-level portions of
00176    /// lobot's controller don't send commands when the USART is busy
00177    /// talking to the robot.
00178    ///
00179    /// Consequently, we have the Command Module's control program
00180    /// initiate communication with the higher layers by sending a READY
00181    /// message and waiting for a response. That way, we can be sure the
00182    /// low level is listening to the high level and that commands don't
00183    /// get lost somehow.
00184    ///
00185    /// Naturally, to make this work, the high level must run a dedicated
00186    /// thread for listening to incoming READY messages and responding to
00187    /// them appropriately. The following inner class implements this
00188    /// thread. It queues commands to be sent to the robot and sends the
00189    /// next pending command each time it gets an ACK_READY from the
00190    /// low-level control program.
00191    class Comm : private Thread {
00192       /// Each command sent to the low-level controller consists of four
00193       /// bytes. The first byte is the command code, the next two bytes
00194       /// are for a parameter, and the last byte is a parity byte
00195       /// checksum. This structure holds these four bytes together.
00196       ///
00197       /// DEVNOTE: Instead of hard-coding the size of the char array used
00198       /// to hold the byte sequence making up a high-level command, we
00199       /// prefer the use of the LOBOT_CMD_SIZE enum defined in
00200       /// irccm/LoCMInterface.h (just in case this ever changes in the
00201       /// future, e.g., command + params + time stamp + checksum).
00202    public:
00203       struct Cmd {
00204          char bytes[LOBOT_CMD_SIZE] ;
00205 
00206          Cmd(int cmd = 0, int param = 0) ;
00207          Cmd(const Cmd&) ;
00208       } ;
00209 
00210       /// The Comm thread is responsible for queueing commands to be sent
00211       /// to the lower levels of the robot's controller and waiting for
00212       /// the low-level control program to request the next such command
00213       /// in the queue.
00214       ///
00215       /// This data structure implements the above-mentioned command
00216       /// queue.
00217       //@{
00218    private:
00219       typedef std::queue<Cmd> CmdQueue ;
00220       CmdQueue m_commands ;
00221       //@}
00222 
00223       /// The Comm thread's command queue will be accessed by the Comm
00224       /// thread itself as well as by the arbiters and (possibly) the
00225       /// main thread. Therefore, we need to protect simultaneous
00226       /// accesses to it.
00227       Mutex m_cmd_mutex ;
00228 
00229       /// The sensor data is received from the low-level control program
00230       /// in a series of bytes. This structure holds these bytes together
00231       /// in the incoming sensor data buffer (see typedef below).
00232       ///
00233       /// DEVNOTE: The number of sensor data bytes sent, viz.,
00234       /// LOBOT_SENSORS_SIZE, is defined in irccm/LoCMInterface.h.
00235    public:
00236       struct Sensors {
00237          char bytes[LOBOT_SENSORS_SIZE] ;
00238          long long time_stamp ;
00239 
00240          Sensors() ;
00241          Sensors(const char sensor_data[]) ;
00242          Sensors(const Sensors&) ;
00243          Sensors& operator=(const Sensors&) ;
00244       } ;
00245 
00246       /// Just like the outgoing commands, the incoming sensor data must
00247       /// also be buffered. This data structure takes care of buffering
00248       /// the incoming sensor data.
00249       //@{
00250    private:
00251       typedef std::queue<Sensors> SensorQueue ;
00252       SensorQueue m_sensors ;
00253       //@}
00254 
00255       /// The sensor data buffer can be accessed by the main thread
00256       /// (during its update cycle) and by the Comm thread (when it
00257       /// receives sensor data from the low level). Thus, we need to
00258       /// properly synchronize accesses to the buffer.
00259       Mutex m_sensors_mutex ;
00260 
00261       /// In order to actually send and receive data to/from the iRobot
00262       /// Create Command Module, we will need a serial port for the
00263       /// requisite I/O operations.
00264       lobot::Serial* m_serial ;
00265 
00266    public:
00267       /// Initialization
00268       Comm(lobot::Serial*) ;
00269 
00270       /// The motor commands issued by the Robolocust arbiters will first
00271       /// be buffered by the Comm thread with this API.
00272       void buffer(int cmd, int param = 0) ;
00273 
00274       /// During its update cycle, the main thread can retrieve the
00275       /// Create robot's sensor data with this API. This function will
00276       /// return false if there is no sensor data available; true
00277       /// otherwise. Thus, the caller should check the return value
00278       /// before attempting to use the sensor data returned via the
00279       /// function's pass-by-reference parameter.
00280       bool sensors(Sensors*) ;
00281 
00282    private:
00283       /// This method sends the next pending command from the Comm
00284       /// thread's command buffer to the low-level Command Module control
00285       /// program for further processing by the Create robot.
00286       void send_cmd() ;
00287 
00288       /// This method receives the Create/Roomba sensor data sent by the
00289       /// low-level control program running on the Command Module.
00290       void recv_sensors() ;
00291 
00292       /// This method implements the Comm thread's main loop, wherein it
00293       /// listens to the Command Module's serial connection for ACK
00294       /// messages from the low-level control program and responds as
00295       /// required.
00296       void run() ;
00297 
00298    public:
00299       /// Clean-up
00300       ~Comm() ;
00301    } ;// end of inner Comm class
00302 
00303    /// The interface between the higher layers and the low-level portions
00304    /// of the Robolocust controller (when it is running on an iRobot
00305    /// Create/Roomba) need to go through an instance of the Comm thread
00306    /// class defined above.
00307    std::auto_ptr<Comm> m_comm ;
00308 
00309    /// Clean-up.
00310   ~RoombaCM() ;
00311 } ;
00312 
00313 //-----------------------------------------------------------------------
00314 
00315 } // end of namespace encapsulating this file's definitions
00316 
00317 #endif
00318 
00319 /* So things look consistent in everyone's emacs... */
00320 /* Local Variables: */
00321 /* indent-tabs-mode: nil */
00322 /* End: */
Generated on Sun May 8 08:41:30 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3