LoRCCar.H

Go to the documentation of this file.
00001 /**
00002    \file  Robots/LoBot/io/LoRCCar.H
00003    \brief Interface object for driving the robot built on top of a hacked
00004    R/C car and retrieving its sensor values.
00005 
00006    This file defines a class that implements the motor driving interface
00007    for lobot as built on top of the hacked R/C car. This robot uses a
00008    mini-ITX computer running Debian as the computing platform and a
00009    Propeller I/O board connected to the computer via a USB serial
00010    connection for sending drive and turn commands to the robot's motors.
00011    Drive commands are sent to a Sabertooth motor driver and turn commands
00012    to a steering servo.
00013 
00014    Additionally, the robot is equipped with a Hall effect sensor mounted
00015    on its right wheel, which is used to gauge the robot's speed. This
00016    object also takes care of retrieving the RPM value returned by this
00017    sensor and converting that to a speed reading.
00018 */
00019 
00020 // //////////////////////////////////////////////////////////////////// //
00021 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00022 // University of Southern California (USC) and the iLab at USC.         //
00023 // See http://iLab.usc.edu for information about this project.          //
00024 // //////////////////////////////////////////////////////////////////// //
00025 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00026 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00027 // in Visual Environments, and Applications'' by Christof Koch and      //
00028 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00029 // pending; application number 09/912,225 filed July 23, 2001; see      //
00030 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00031 // //////////////////////////////////////////////////////////////////// //
00032 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00033 //                                                                      //
00034 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00035 // redistribute it and/or modify it under the terms of the GNU General  //
00036 // Public License as published by the Free Software Foundation; either  //
00037 // version 2 of the License, or (at your option) any later version.     //
00038 //                                                                      //
00039 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00040 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00041 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00042 // PURPOSE.  See the GNU General Public License for more details.       //
00043 //                                                                      //
00044 // You should have received a copy of the GNU General Public License    //
00045 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00046 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00047 // Boston, MA 02111-1307 USA.                                           //
00048 // //////////////////////////////////////////////////////////////////// //
00049 //
00050 // Primary maintainer for this file: mviswana usc edu
00051 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/io/LoRCCar.H $
00052 // $Id: LoRCCar.H 13770 2010-08-08 06:49:50Z mviswana $
00053 //
00054 
00055 #ifndef LOBOT_RC_CAR_DOT_H
00056 #define LOBOT_RC_CAR_DOT_H
00057 
00058 //------------------------------ HEADERS --------------------------------
00059 
00060 // lobot headers
00061 #include "Robots/LoBot/io/LoRobot.H"
00062 
00063 #include "Robots/LoBot/misc/LoPID.H"
00064 #include "Robots/LoBot/misc/factory.hh"
00065 #include "Robots/LoBot/misc/singleton.hh"
00066 #include "Robots/LoBot/misc/wma.hh"
00067 #include "Robots/LoBot/util/triple.hh"
00068 
00069 // INVT model manager stuff
00070 #include "Component/ModelManager.H"
00071 
00072 // Standard C++ headers
00073 #include <string>
00074 
00075 //----------------------------- NAMESPACE -------------------------------
00076 
00077 namespace lobot {
00078 
00079 //------------------------- CLASS DEFINITION ----------------------------
00080 
00081 /**
00082    \class lobot::RCCar
00083    \brief High-level API for driving and steering the R/C car based
00084    robot and retrieving the value of its RPM sensor.
00085 
00086    The robot's motors are controlled by a motor driver that is in turn
00087    controlled by a Propeller-based I/O board. This board connects to the
00088    Robolocust computer (the mini-ITX Debian box) over a USB port. The
00089    lobot::RCcar class implements the motor API defined by lobot::Robot by
00090    sending off all the drive and turn commands to the Propeller.
00091 
00092    Additionally, the Propeller board also interfaces with a Hall effect
00093    sensor and computes the RPM of the robot's front right wheel.
00094 */
00095 class RCCar : public Robot {
00096    // Handy type to have around in a derived class
00097    typedef Robot base ;
00098 
00099    // Boilerplate code to make the generic factory design pattern work
00100    friend  class subfactory<RCCar, base, ModelManager> ;
00101    typedef register_factory<RCCar, base, ModelManager> my_factory ;
00102    static  my_factory register_me ;
00103 
00104    /// The hacked R/C car's motor subsytem uses a PID controller to
00105    /// achieve the speed specified by its clients.
00106    PID<float> m_speed_pid ;
00107 
00108    /// The speed PID controller doesn't work as well as it could due to
00109    /// the input speed commands being excessively noisy. Since these
00110    /// inputs are computed on the basis of the RPM sensor readings, we
00111    /// need to clean those up. We do so with a weighted moving average
00112    /// (which acts as a kind of low pass filter).
00113    wma<float> m_rpm_filter ;
00114 
00115    /// Private constructor because the interface object for a robot's
00116    /// motor subsystem is created using a factory.
00117    ///
00118    /// Generally, the Robolocust project prefers the libserial C++
00119    /// library for serial communications to the serial support provided
00120    /// by INVT. However, in case libserial is not available, we fall back
00121    /// to INVT, which is why the constructor needs the application's INVT
00122    /// ModelManager (because INVT's Serial class requires it).
00123    RCCar(const ModelManager&) ;
00124 
00125    /// Clients must issue drive commands using both a speed expressed in
00126    /// m/s and a PWM value. A flag in the config file specifies which one
00127    /// is actually used.
00128    ///
00129    /// The reason we do this is because drive commands based on speeds
00130    /// rely on the RPM sensor attached to the front right wheel of the
00131    /// robot. This sensor is extremely noisy and quite unreliable.
00132    /// Therefore, we allow users to bypass the RPM sensor altogether if
00133    /// they so wish and work directly in terms of motor PWM values.
00134    /// Consequently, the public interface to the motor drive commands
00135    /// require client modules to supply both parameters. Then,
00136    /// internally, the lobot::Motor class uses the bypass_rpm_sensor flag
00137    /// to decide which parameter to actually use.
00138    void drive(float speed, int pwm) ;
00139 
00140    /// Command the motors to drive at the specified speed (expressed in
00141    /// m/s). Positive speeds indicate forward motion, negative speeds are
00142    /// for reversing and zero indicates coming to a full stop.
00143    void drive(float speed) ;
00144 
00145    /// Command the motors to drive at the specified motor PWM value.
00146    /// Positive quantities indicate forward motion, negative ones are for
00147    /// reversing and zero indicates coming to a full stop.
00148    void drive(int pwm) ;
00149 
00150    /// Command the motors to turn towards the specified direction
00151    /// (expressed in degrees). Zero degrees is for driving straight
00152    /// ahead; positive (ccw) angles are for heading left and negative
00153    /// (cw) angles for heading right.
00154    void turn(float direction) ;
00155 
00156    /// Command the robot to spin in-place by the specified angle
00157    /// (expressed in degrees). Positive angles result in ccw in-place
00158    /// turns while negative angles are for cw in-place turns.
00159    void spin(float angle) ;
00160 
00161    /// Stop robot and straighten wheels.
00162    void off() ;
00163 
00164    /// Get the current speed and heading.
00165    bool update_sensors() ;
00166 
00167    /// Check if the robot is moving or stationary.
00168    bool stopped() const ;
00169 
00170    /// Low-level motor commands.
00171    //@{
00172    enum {
00173       // Motor commands
00174       FORWARD  = 100,
00175       REVERSE  = 101,
00176       STOP     = 102,
00177       LEFT     = 110,
00178       RIGHT    = 111,
00179       STRAIGHT = 112,
00180       OFF      = 120,
00181 
00182       // Propeller status commands
00183       GET_MOTOR_DIR = 130,
00184       GET_MOTOR_PWM = 131,
00185       GET_SERVO_DIR = 132,
00186       GET_SERVO_PWM = 133,
00187       GET_RPM       = 134,
00188    } ;
00189    void send_propeller(int cmd) ;
00190    void send_propeller(int cmd, int param) ;
00191    int  recv_propeller(int cmd, int n = 1) ;
00192    //@}
00193 
00194    /// Clean-up.
00195   ~RCCar() ;
00196 
00197    /// This inner class encapsulates various parameters that can be used
00198    /// to tweak different aspects of the motor interface.
00199    class Params : public singleton<Params> {
00200       /// The robot's motors are controlled by sending commands over a
00201       /// serial port. This setting specifies the serial port device that
00202       /// should be used.
00203       std::string m_device ;
00204 
00205       /// This setting specifies the serial port communication rate.
00206       int m_baud_rate ;
00207 
00208       /// The robot's turn arbiter issues steering commands in terms of
00209       /// turn angles. The low-level motor interface needs to convert
00210       /// these directions into appropriate steering servo PWM values. In
00211       /// order to effect the transformation from turn angle to servo
00212       /// PWM, we need to know the max angle the turn arbiter will issue.
00213       int m_turn_max ;
00214 
00215       /// The diameter of the robot's wheels. This is used to compute the
00216       /// current speed at which the robot is moving.
00217       ///
00218       /// This parameter is expected to be specified in millimeters.
00219       float m_wheel_diameter ;
00220 
00221       /// To convert RPM values to speeds, we multiply the RPM by pi
00222       /// times the wheel diameter and divide by 60 to get the resulting
00223       /// speed in millimeters per second. Dividing by 1000 gives us m/s.
00224       ///
00225       /// This parameter is used to keep track of the above calculation.
00226       /// It is not a configuration setting meant for end-user tweaking.
00227       /// Rather, it is a handy precomputed factor kept around to avoid
00228       /// repeating the same calculation over and over.
00229       float m_rpm_speed_factor ;
00230 
00231       /// The higher layers of the Robolocust controller specify drive
00232       /// commands in terms of a speed expressed in m/s. The low-level
00233       /// motor system, however, needs to be commanded in terms of a PWM
00234       /// duty cycle. To convert speed commands to appropriate PWM
00235       /// values, we first convert the target speed set by some
00236       /// high-level behaviour/module into RPM and then just multiply the
00237       /// result with some suitable conversion factor.
00238       ///
00239       /// For maximum flexibility, we let users specify an appropriate
00240       /// conversion factor.
00241       float m_rpm_pwm_factor ;
00242 
00243       /// Since the RPM sensor is quite noisy, we need to filter its
00244       /// readings. We do so using a weighted moving average (a sort of
00245       /// low pass filter). This setting specifies the number of previous
00246       /// readings that should be considered for computing the
00247       /// above-mentioned weighted moving average.
00248       ///
00249       /// NOTE: Although inadvisable, the RPM filter can be turned off by
00250       /// setting this config value to one.
00251       int m_rpm_filter_size ;
00252 
00253       /// Despite the filteration applied to it, the RPM sensor can still
00254       /// return extremely bogus readings! Sometimes, we may simply want
00255       /// to turn that dang thing off and not bother with it at all. If
00256       /// this flag is set, the motor system will be commanded in terms
00257       /// of PWM values instead of drive velocities expressed in m/s.
00258       bool m_bypass_rpm_sensor ;
00259 
00260       /// The motor subsystem uses a PID controller to achieve and
00261       /// maintain the target speed commanded by high-level behaviours
00262       /// and modules. This setting specifies the PID gains for the speed
00263       /// controller.
00264       triple<float, float, float> m_speed_gains ;
00265 
00266       /// This parameter converts steering directions sent by the turn
00267       /// arbiter to corresponding PWM values to be sent to the steering
00268       /// servo (and vice versa).
00269       float m_steering_pwm_factor ;
00270 
00271       /// Private constructor because this is a singleton.
00272       Params() ;
00273 
00274       // Boilerplate code to make generic singleton design pattern work
00275       friend class singleton<Params> ;
00276 
00277    public:
00278       /// Accessing the various parameters.
00279       //@{
00280       static const std::string& device() {return instance().m_device ;}
00281       static int   baud_rate()        {return instance().m_baud_rate ;}
00282       static int   turn_max()         {return instance().m_turn_max ;}
00283       static float wheel_diameter()   {return instance().m_wheel_diameter ;}
00284       static float rpm_speed_factor() {return instance().m_rpm_speed_factor ;}
00285       static float rpm_pwm_factor()   {return instance().m_rpm_pwm_factor ;}
00286       static bool  bypass_rpm_sensor(){return instance().m_bypass_rpm_sensor ;}
00287       static int   rpm_filter_size()  {return instance().m_rpm_filter_size ;}
00288       static const triple<float, float, float>& speed_gains() {
00289          return instance().m_speed_gains ;
00290       }
00291       static float steering_pwm_factor() {
00292          return instance().m_steering_pwm_factor ;
00293       }
00294       //@}
00295 
00296       /// Clean-up.
00297       ~Params() ;
00298    } ;
00299 } ;
00300 
00301 //-----------------------------------------------------------------------
00302 
00303 } // end of namespace encapsulating this file's definitions
00304 
00305 #endif
00306 
00307 /* So things look consistent in everyone's emacs... */
00308 /* Local Variables: */
00309 /* indent-tabs-mode: nil */
00310 /* End: */
Generated on Sun May 8 08:41:30 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3