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