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: */