LoSensors.c

Go to the documentation of this file.
00001 /**
00002    \file  Robots/LoBot/irccm/LoSensors.c
00003    \brief Sensors API for Robolocust iRobot Create Command Module control
00004    program.
00005 
00006    This file defines the functions that implement the sensor retrieval
00007    API for the low-level Robolocust control program meant to be run on
00008    the iRobot Create's Command Module.
00009 */
00010 
00011 /*
00012  ************************************************************************
00013  * The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   *
00014  * by the University of Southern California (USC) and the iLab at USC.  *
00015  * See http://iLab.usc.edu for information about this project.          *
00016  *                                                                      *
00017  * Major portions of the iLab Neuromorphic Vision Toolkit are protected *
00018  * under the U.S. patent ``Computation of Intrinsic Perceptual Saliency *
00019  * in Visual Environments, and Applications'' by Christof Koch and      *
00020  * Laurent Itti, California Institute of Technology, 2001 (patent       *
00021  * pending; application number 09/912,225 filed July 23, 2001; see      *
00022  * http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     *
00023  ************************************************************************
00024  * This file is part of the iLab Neuromorphic Vision C++ Toolkit.       *
00025  *                                                                      *
00026  * The iLab Neuromorphic Vision C++ Toolkit is free software; you can   *
00027  * redistribute it and/or modify it under the terms of the GNU General  *
00028  * Public License as published by the Free Software Foundation; either  *
00029  * version 2 of the License, or (at your option) any later version.     *
00030  *                                                                      *
00031  * The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  *
00032  * that it will be useful, but WITHOUT ANY WARRANTY; without even the   *
00033  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      *
00034  * PURPOSE.  See the GNU General Public License for more details.       *
00035  *                                                                      *
00036  * You should have received a copy of the GNU General Public License    *
00037  * along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   *
00038  * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   *
00039  * Boston, MA 02111-1307 USA.                                           *
00040  ************************************************************************
00041 */
00042 
00043 /*
00044    Primary maintainer for this file: mviswana usc edu
00045    $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/irccm/LoSensors.c $
00046    $Id: LoSensors.c 13798 2010-08-18 19:43:24Z mviswana $
00047 */
00048 
00049 /*------------------------------ HEADERS ------------------------------*/
00050 
00051 // lobot headers
00052 #include "LoSensors.h"
00053 #include "LoIO.h"
00054 #include "LoTimer.h"
00055 #include "LoUtils.h"
00056 #include "LoCMInterface.h"
00057 #include "LoOpenInterface.h"
00058 
00059 // avr-libc headers
00060 #include <avr/io.h>
00061 
00062 /*----------------------------- CONSTANTS -----------------------------*/
00063 
00064 enum {
00065    // lobot's rear bump sensors consist of a pair of Sharp GP2D15 IR
00066    // proximity detectors connected to the Command Module's cargo bay
00067    // ePort's digital I/O lines 1 and 2. These, in turn, connect to the
00068    // ATmega168's C register (bits 4 and 0 respectively).
00069    //
00070    // These bit masks are used to specify the PINC bits for checking the
00071    // bump sensor states.
00072    LOBOT_BUMP_RL_PIN = 0x10, // rear left  connected to C4
00073    LOBOT_BUMP_RR_PIN = 0x01, // rear right connected to C0
00074 
00075    // Instead of adding a new sensor data byte for the rear bumpers, we
00076    // simply use bits 5 and 6 of the bumps + wheel drops sensor data byte
00077    // (which are not used by the Open Interface).
00078    LOBOT_BUMP_RL_POS = 6, // rear left  bump sensor's bit position
00079    LOBOT_BUMP_RR_POS = 5, // rear right bump sensor's bit position
00080 
00081    // To debounce the rear bumpers, we expect to see a continuous logic
00082    // low for at least the following amount of time (in ms).
00083    LOBOT_REAR_BUMP_DEBOUNCE_THRESHOLD = 15,
00084 } ;
00085 
00086 /*------------------------------ GLOBALS ------------------------------*/
00087 
00088 // We cannot retrieve the sensor data from the Create and directly send
00089 // it off to the high level because the Command Module has a single USART
00090 // that must be switched between talking to the robot's internal serial
00091 // port and the Command Module's (external) USB port. Thus, when the
00092 // high-level sends the command to retrieve sensor data, we store/buffer
00093 // the data locally after getting it from the robot (via the Open
00094 // Interface).
00095 //
00096 // Then, when the main loop of this low-level control program switches
00097 // the USART to talk to the Robolocust computer, it will see if there is
00098 // sensor data pending that needs to be sent to the high level. If so, it
00099 // will perform the necessary sensor data send operation.
00100 //
00101 // The following variable is used to keep track of whether sensor data is
00102 // pending or not.
00103 static char g_sensors_pending ;
00104 
00105 // The sensor data returned by the Create robot is buffered in this array
00106 // prior to transmission to the high level.
00107 static char g_sensors[LOBOT_SENSORS_SIZE] ;
00108 
00109 // Due to motor/encoder errors, the actual amount of rotation in response
00110 // to the SPIN command may be a little more or less than the requested
00111 // amount. Furthermore, the robot may experience a slight translation in
00112 // addition to the rotation. To ensure that the high-level controller
00113 // does not miss out on any low-level motion updates, we have to add the
00114 // actual amount of rotation and any unintended translation to the next
00115 // sensor packet that will be sent to the high-level controller.
00116 //
00117 // These two variables temporarily record the values of the rotation and
00118 // translation resulting from the SPIN command. They will be added to the
00119 // encoder data for the next sensor packet.
00120 static int g_pending_distance ;
00121 static int g_pending_rotation ;
00122 
00123 // On start-up, the rear bump sensors, a pair of Sharp GP2D15 IR
00124 // proximity detectors, are ignored to prevent the robot from reacting to
00125 // the user's hands as soon as the Command Module on/off switch is
00126 // activated or when the user is trying to place the robot at some
00127 // specific starting point before an experiment/run.
00128 //
00129 // This flag keeps track of whether the rear bumpers are enabled or not.
00130 // The high-level controller can turn these two sensors on/off by using
00131 // the appropriate commands.
00132 static volatile char g_rear_bumps_enabled ;
00133 
00134 // This flag indicates whether or not the robot should respond to rear
00135 // bump events by spinning in-place and moving up a little or by simply
00136 // stopping. The default behaviour is to just stop the robot. However,
00137 // the high-level controller can instruct the low-level controller to
00138 // spin and move the robot by passing 1 as the parameter to the
00139 // LOBOT_CMD_ENABLE_REAR_BUMPS command.
00140 static char g_rear_bumps_spin ;
00141 
00142 // To debounce the rear proximity detectors, we use the following
00143 // variables to count how many times the sensors are active in 1ms
00144 // increments. If the count for a sensor exceeds the debounce threshold,
00145 // only then is that detector considered active.
00146 static volatile unsigned char g_rlb_count ; // rlb = rear left  bump
00147 static volatile unsigned char g_rrb_count ; // rrb = rear right bump
00148 
00149 /*-------------------------- INITIALIZATION ---------------------------*/
00150 
00151 // Forward declaration
00152 static void debounce_rear_bumps(void) ;
00153 
00154 // Setup 1ms timer callback to perform debouncing asynchronously w.r.t.
00155 // the main "thread." Otherwise, the main thread can get tied up in a
00156 // reasonably long busy wait just to debounce the rear bumpers and
00157 // potentially miss other important sensory input.
00158 void lo_init_sensors(void)
00159 {
00160    lo_add_timer1_cb(debounce_rear_bumps) ;
00161 }
00162 
00163 // Enable/disable the two rear bump sensors
00164 void lo_enable_rear_bumps(int param)
00165 {
00166    g_rear_bumps_enabled = 1 ;
00167    g_rear_bumps_spin = lo_lobyte(param) ;
00168 }
00169 
00170 void lo_disable_rear_bumps(int unused)
00171 {
00172    g_rear_bumps_enabled = 0 ;
00173    g_rlb_count = g_rrb_count = 0 ;
00174 }
00175 
00176 void lo_toggle_rear_bumps(void)
00177 {
00178    g_rear_bumps_enabled = ! g_rear_bumps_enabled ;
00179    g_rlb_count = g_rrb_count = 0 ;
00180 }
00181 
00182 // Enable/disable spin-and-move action for rear bump events
00183 void lo_toggle_rear_bumps_spin(void)
00184 {
00185    g_rear_bumps_spin = ! g_rear_bumps_spin ;
00186 }
00187 
00188 /*---------------------- RETRIEVING SENSOR DATA -----------------------*/
00189 
00190 // Debouncing logic for the rear bump sensors: in 1ms increments, we
00191 // check if the pins to which these sensors are connected report a logic
00192 // high. If so, we increment the corresponding count variable for that
00193 // sensor. If not, we reset the count to zero.
00194 //
00195 // Thus, when the main thread retrieves the counts, it will know
00196 // immediately whether or not the rear bumpers were active for at least
00197 // the last T milliseconds (where T is the debounce threshold).
00198 //
00199 // NOTE: It is possible for the main thread to check the counts when they
00200 // are, say, halfway to the debounce threshold and then check again after
00201 // several milliseconds. In the mean time, the 1ms timer might well have
00202 // bumped the count past the threshold and, depending on the situation or
00203 // stray noise, reset the counter. Thus, when the main thread checks
00204 // next, it can potentially miss a crucial rear obstacle. Even worse,
00205 // this could actually go on for a good, long time.
00206 //
00207 // The best way to avoid the situation described above would be to
00208 // implement the debouncing using a Schmitt trigger rather than a simple
00209 // count threshold. Nonetheless, in practice, this straightforward
00210 // debouncing logic works fine.
00211 static void debounce_rear_bumps(void)
00212 {
00213    if (g_rear_bumps_enabled)
00214    {
00215       if (PINC & LOBOT_BUMP_RL_PIN) // rear left proximity detector active
00216          ++g_rlb_count ;
00217       else if (g_rlb_count > 0)
00218          g_rlb_count = 0 ;
00219 
00220       if (PINC & LOBOT_BUMP_RR_PIN) // rear right proximity detector active
00221          ++g_rrb_count ;
00222       else if (g_rrb_count > 0)
00223          g_rrb_count = 0 ;
00224    }
00225 }
00226 
00227 // Retrieve all the built-in sensors plus lobot's custom sensor states
00228 void lo_sensors(void)
00229 {
00230    // Send sensor query to the Create robot to return all sensor packets
00231    lo_tx(LOBOT_OI_CMD_SENSORS) ;
00232    lo_tx(LOBOT_OI_SENSOR_GROUP_6) ;
00233 
00234    // Retrieve sensor data from Create robot, waiting a maximum of 50ms
00235    // to get the data. Taking longer than 50ms to retrieve sensor data is
00236    // probably indicative of a temporary serial communication glitch with
00237    // the Create robot. We shouldn't keep waiting for the data as that
00238    // can hold up the robot in case the high level has detected a
00239    // problematic situation and issued appropriate commands to handle it.
00240    lo_rx(g_sensors, LOBOT_OI_SENSOR_SIZE_GROUP_6, 50) ;
00241 
00242    // Set the sensors pending flag, so that the low-level control
00243    // program's main loop can send the sensor data out to the high level.
00244    // But don't indicate to the main loop that sensor data is pending in
00245    // case the Create robot timed out and failed to respond to the above
00246    // sensor query.
00247    g_sensors_pending = ! lo_io_error() ;
00248 
00249    // When the high-level controller sends a SPIN command, the drive
00250    // module will mark the actual amount spun and any additional
00251    // translational motion as pending for the next SENSORS
00252    // acknowledgement. We need to add those amounts to the encoder data
00253    // returned by the above Open Interface exchange with the Create so
00254    // that the high-level doesn't miss any low-level motion updates and
00255    // end up getting mislocalized or experience some other related
00256    // problem.
00257    g_sensors[LOBOT_SENSORS_SPIN_FLAG] =
00258       g_sensors_pending && (g_pending_distance || g_pending_rotation) ;
00259    if (g_sensors[LOBOT_SENSORS_SPIN_FLAG]) {
00260       lo_update_odometry(g_pending_distance, g_pending_rotation) ;
00261       g_pending_distance = 0 ;
00262       g_pending_rotation = 0 ;
00263    }
00264 
00265    // Check the rear bump/proximity sensors connected to the Command
00266    // Module's cargo bay ePort.
00267    //
00268    // NOTE: Instead of adding a new byte of sensor data for the rear bump
00269    // sensors, we simply stuff these two bit flags into bits 5 and 6 of
00270    // the wheel drops + bumps sensor data byte.
00271    if (g_rlb_count >= LOBOT_REAR_BUMP_DEBOUNCE_THRESHOLD) {
00272       g_sensors[LOBOT_SENSORS_BUMPS] |= (1 << LOBOT_BUMP_RL_POS) ;
00273       g_rlb_count = 0 ;
00274    }
00275    if (g_rrb_count >= LOBOT_REAR_BUMP_DEBOUNCE_THRESHOLD) {
00276       g_sensors[LOBOT_SENSORS_BUMPS] |= (1 << LOBOT_BUMP_RR_POS) ;
00277       g_rrb_count = 0 ;
00278    }
00279 }
00280 
00281 // Return a sensor byte given its index.
00282 char lo_get_sensor(unsigned char index)
00283 {
00284    return g_sensors[index] ;
00285 }
00286 
00287 /*----------------------- UPDATING SENSOR DATA ------------------------*/
00288 
00289 // Update odometry information stored in pending sensor packet (e.g., in
00290 // response to bumps/cliffs action).
00291 void lo_update_odometry(int distance, int angle)
00292 {
00293    if (g_sensors_pending)
00294    {
00295       distance += lo_make_word(g_sensors[LOBOT_SENSORS_DISTANCE_HI],
00296                                g_sensors[LOBOT_SENSORS_DISTANCE_LO]) ;
00297       g_sensors[LOBOT_SENSORS_DISTANCE_HI] = lo_hibyte(distance) ;
00298       g_sensors[LOBOT_SENSORS_DISTANCE_LO] = lo_lobyte(distance) ;
00299 
00300       angle += lo_make_word(g_sensors[LOBOT_SENSORS_ANGLE_HI],
00301                             g_sensors[LOBOT_SENSORS_ANGLE_LO]) ;
00302       g_sensors[LOBOT_SENSORS_ANGLE_HI] = lo_hibyte(angle) ;
00303       g_sensors[LOBOT_SENSORS_ANGLE_LO] = lo_lobyte(angle) ;
00304    }
00305 }
00306 
00307 // Update odometry information for next sensor packet
00308 void lo_update_pending_odometry(int distance, int angle)
00309 {
00310    g_pending_distance += distance ;
00311    g_pending_rotation += angle ;
00312 }
00313 
00314 /*------------------------ SENSOR DATA STATE --------------------------*/
00315 
00316 // Check if sensor data is pending so that main loop will send out the
00317 // data the next time it switches to talking to the high level via the
00318 // Command Module's USB port.
00319 char lo_sensors_pending(void)
00320 {
00321    return g_sensors_pending ;
00322 }
00323 
00324 // Check if rear bump action should be spin-and-move or just a plain stop
00325 char lo_rear_bumps_spin(void)
00326 {
00327    return g_rear_bumps_spin ;
00328 }
00329 
00330 /*------------------------ SENDING SENSOR DATA ------------------------*/
00331 
00332 // Send pending sensor data to the high level
00333 void lo_send_sensors(void)
00334 {
00335    lo_tx(LOBOT_ACK_SENSORS) ;
00336    for (unsigned char i = 0; i < LOBOT_SENSORS_SIZE; ++i)
00337       lo_tx(g_sensors[i]) ;
00338 
00339    // Sensor data is no longer pending after it has been sent to the high
00340    // level.
00341    g_sensors_pending = 0 ;
00342 }
Generated on Sun May 8 08:41:30 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3