00001 /** 00002 \file Robots/LoBot/irccm/LoRemote.c 00003 \brief Implementation of the low-level remote control module. 00004 */ 00005 00006 /* 00007 ************************************************************************ 00008 * The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 * 00009 * by the University of Southern California (USC) and the iLab at USC. * 00010 * See http://iLab.usc.edu for information about this project. * 00011 * * 00012 * Major portions of the iLab Neuromorphic Vision Toolkit are protected * 00013 * under the U.S. patent ``Computation of Intrinsic Perceptual Saliency * 00014 * in Visual Environments, and Applications'' by Christof Koch and * 00015 * Laurent Itti, California Institute of Technology, 2001 (patent * 00016 * pending; application number 09/912,225 filed July 23, 2001; see * 00017 * http://pair.uspto.gov/cgi-bin/final/home.pl for current status). * 00018 ************************************************************************ 00019 * This file is part of the iLab Neuromorphic Vision C++ Toolkit. * 00020 * * 00021 * The iLab Neuromorphic Vision C++ Toolkit is free software; you can * 00022 * redistribute it and/or modify it under the terms of the GNU General * 00023 * Public License as published by the Free Software Foundation; either * 00024 * version 2 of the License, or (at your option) any later version. * 00025 * * 00026 * The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope * 00027 * that it will be useful, but WITHOUT ANY WARRANTY; without even the * 00028 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * 00029 * PURPOSE. See the GNU General Public License for more details. * 00030 * * 00031 * You should have received a copy of the GNU General Public License * 00032 * along with the iLab Neuromorphic Vision C++ Toolkit; if not, write * 00033 * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * 00034 * Boston, MA 02111-1307 USA. * 00035 ************************************************************************ 00036 */ 00037 00038 /* 00039 Primary maintainer for this file: mviswana usc edu 00040 $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/irccm/LoRemote.c $ 00041 $Id: LoRemote.c 13768 2010-08-07 23:41:41Z mviswana $ 00042 */ 00043 00044 /*------------------------------ HEADERS ------------------------------*/ 00045 00046 // lobot headers 00047 #include "LoDrive.h" 00048 #include "LoSensors.h" 00049 #include "LoIO.h" 00050 #include "LoTimer.h" 00051 #include "LoCMInterface.h" 00052 #include "LoOpenInterface.h" 00053 00054 /*----------------------------- CONSTANTS -----------------------------*/ 00055 00056 // The remote control module works by checking the robot's sensors to see 00057 // if a remote control command has been sent. If so, it transitions to 00058 // the REMOTE_CONTROL state and executes the specified command. While in 00059 // the REMOTE_CONTROL state, if no more remote control commands come in 00060 // within the predefined timeout, the module releases the motors and 00061 // returns to the AUTONOMOUS state. 00062 // 00063 // This enumeration defines symbolic constants for the above-mentioned 00064 // two states. 00065 enum { 00066 AUTONOMOUS, 00067 REMOTE_CONTROL, 00068 } ; 00069 00070 // Some parameters for this module 00071 enum { 00072 LOBOT_REMOTE_DRIVE_SPEED = 250, 00073 LOBOT_REMOTE_TURN_SPEED = 100, 00074 00075 LOBOT_REMOTE_TIMEOUT = 1500, 00076 00077 LOBOT_POWER_DEBOUNCE = 5, 00078 } ; 00079 00080 /*------------------------------ GLOBALS ------------------------------*/ 00081 00082 // This variable is used to keep track of the current state of the remote 00083 // control module. 00084 static char g_state ; 00085 00086 // As mentioned earlier, the remote control module works by keeping track 00087 // of how long it has been since the most recent remote control command 00088 // was received and reverting to normal autonomous operation on timeout. 00089 // This variable is used to time-stamp the remote control commands. 00090 static unsigned long g_time ; 00091 00092 // A data buffer for keeping track of pending ACK_REMOTE messages. The 00093 // first byte of this buffer is used to store the ACK_REMOTE message 00094 // itself; the remaining bytes are for the actual data that is sent with 00095 // the acknowledgement. 00096 static char g_remote[LOBOT_REMOTE_SIZE + 1] ; 00097 00098 // To help debounce the 'P' button press and ensure that user really does 00099 // want to quit the lobot controller and dock the robot, we use a counter 00100 // and return true for the "quit event" only if the counter has reached 00101 // its minimum threshold (viz., LOBOT_POWER_DEBOUNCE). 00102 static char g_power_count ; 00103 00104 /*------------------------- LOW-LEVEL ACTIONS -------------------------*/ 00105 00106 // This helper function returns true if the specified IR byte corresponds 00107 // to a supported remote control command; false otherwise. 00108 static char supported_cmd(char c) 00109 { 00110 switch (c) 00111 { 00112 case LOBOT_OI_REMOTE_LEFT: 00113 case LOBOT_OI_REMOTE_RIGHT: 00114 case LOBOT_OI_REMOTE_PAUSE: 00115 case LOBOT_OI_REMOTE_CLEAN: 00116 case LOBOT_OI_REMOTE_FORWARD: 00117 case LOBOT_OI_REMOTE_POWER: 00118 case LOBOT_OI_REMOTE_SPOT: 00119 case LOBOT_OI_REMOTE_MAX: 00120 return 1 ; 00121 default: 00122 return 0 ; 00123 } 00124 } 00125 00126 // Helper function to respond to each of the remote control commands 00127 static void execute(char ir_cmd) 00128 { 00129 switch (ir_cmd) 00130 { 00131 case LOBOT_OI_REMOTE_FORWARD: 00132 lo_drive(LOBOT_REMOTE_DRIVE_SPEED, LOBOT_OI_DRIVE_STRAIGHT, 1) ; 00133 break ; 00134 case LOBOT_OI_REMOTE_CLEAN: // use clean button for driving backwards 00135 lo_drive(-LOBOT_REMOTE_DRIVE_SPEED, LOBOT_OI_DRIVE_STRAIGHT, 1) ; 00136 break ; 00137 case LOBOT_OI_REMOTE_PAUSE: 00138 lo_stop_immediate() ; 00139 break ; 00140 case LOBOT_OI_REMOTE_LEFT: 00141 lo_drive(LOBOT_REMOTE_TURN_SPEED, LOBOT_OI_TURN_INPLACE_CCW, 0) ; 00142 break ; 00143 case LOBOT_OI_REMOTE_RIGHT: 00144 lo_drive(LOBOT_REMOTE_TURN_SPEED, LOBOT_OI_TURN_INPLACE_CW, 0) ; 00145 break ; 00146 case LOBOT_OI_REMOTE_SPOT: 00147 lo_toggle_rear_bumps() ; 00148 break ; 00149 case LOBOT_OI_REMOTE_MAX: 00150 lo_toggle_rear_bumps_spin() ; 00151 break ; 00152 case LOBOT_OI_REMOTE_POWER: 00153 ++g_power_count ; 00154 return ; // important: no ACK_REMOTE when 'P' button is pressed 00155 } 00156 00157 // Every time we execute a remote control command, we mark an 00158 // acknowledgement as pending. 00159 g_remote[0] = LOBOT_ACK_REMOTE ; 00160 g_remote[1] = ir_cmd ; 00161 } 00162 00163 // The remote control module works by maintaining an internal state. When 00164 // the user presses a supported remote control button, it transitions to 00165 // the REMOTE_CONTROL state and takes over the robot's motors. When it 00166 // times out waiting for a remote control command, it reverts to the 00167 // AUTONOMOUS state and relinquishes the robot's motors so that normal 00168 // operation may continue. 00169 // 00170 // DEVNOTE: This function does not check to see if sensor data is 00171 // available before retrieving the infrared byte from the LoSensors 00172 // module. The main program should take care of that, i.e., check that 00173 // sensor data is actually available before calling this function. We do 00174 // it like this because there are other low-level sensor reaction modules 00175 // and all of them would have to keep checking the same flag over and 00176 // over again. Much nicer if the main program checks the sensor data 00177 // availability flag once and then calls all the sensor reaction 00178 // functions one-by-one. 00179 void lo_remote(void) 00180 { 00181 char ir = lo_get_sensor(LOBOT_SENSORS_INFRARED_BYTE) ; 00182 switch (g_state) 00183 { 00184 case AUTONOMOUS: 00185 if (supported_cmd(ir)) 00186 { 00187 execute(ir) ; 00188 g_state = REMOTE_CONTROL ; 00189 g_time = lo_ticks() ; 00190 } 00191 break ; 00192 case REMOTE_CONTROL: 00193 if (lo_ticks() - g_time <= LOBOT_REMOTE_TIMEOUT) 00194 { 00195 if (supported_cmd(ir)) 00196 { 00197 execute(ir) ; 00198 g_time = lo_ticks() ; 00199 } 00200 } 00201 else 00202 { 00203 g_state = AUTONOMOUS ; 00204 g_time = 0 ; 00205 g_power_count = 0 ; 00206 } 00207 break ; 00208 } 00209 } 00210 00211 /*------------------ REMOTE CONTROL ACKNOWLEDGEMENTS ------------------*/ 00212 00213 // When the low level responds to remote control commands, it lets the 00214 // high level know. This function checks if a ACK_REMOTE message is 00215 // pending or not. 00216 char lo_remote_pending(void) 00217 { 00218 return g_remote[0] == LOBOT_ACK_REMOTE ; 00219 } 00220 00221 // Send pending remote control acknowledgement to the high level 00222 void lo_send_remote(void) 00223 { 00224 for (unsigned char i = 0; i < LOBOT_REMOTE_SIZE + 1; ++i) 00225 lo_tx(g_remote[i]) ; 00226 00227 // Sensor data no longer pending after being sent to high level 00228 g_remote[0] = 0 ; 00229 } 00230 00231 /*------------------- REMOTE CONTROL STATE QUERIES --------------------*/ 00232 00233 // Check if the user is remote controlling the robot or whether it is 00234 // operating autonomously. 00235 char lo_is_remote_control(void) 00236 { 00237 return g_state == REMOTE_CONTROL ; 00238 } 00239 00240 // Returns true if the Roomba Remote's 'P' button has been pressed; 00241 // false otherwise. 00242 char lo_remote_quit(void) 00243 { 00244 return g_power_count >= LOBOT_POWER_DEBOUNCE ; 00245 }