hokuyo_scan.py
Go to the documentation of this file.
00001 #
00002 # Copyright (c) 2009, Georgia Tech Research Corporation
00003 # All rights reserved.
00004 #
00005 # Redistribution and use in source and binary forms, with or without
00006 # modification, are permitted provided that the following conditions are met:
00007 #     * Redistributions of source code must retain the above copyright
00008 #       notice, this list of conditions and the following disclaimer.
00009 #     * Redistributions in binary form must reproduce the above copyright
00010 #       notice, this list of conditions and the following disclaimer in the
00011 #       documentation and/or other materials provided with the distribution.
00012 #     * Neither the name of the Georgia Tech Research Corporation nor the
00013 #       names of its contributors may be used to endorse or promote products
00014 #       derived from this software without specific prior written permission.
00015 #
00016 # THIS SOFTWARE IS PROVIDED BY GEORGIA TECH RESEARCH CORPORATION ''AS IS'' AND
00017 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 # DISCLAIMED. IN NO EVENT SHALL GEORGIA TECH BE LIABLE FOR ANY DIRECT, INDIRECT,
00020 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00021 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00022 # OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00023 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
00024 # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00025 # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 #
00027 
00028 #  \author Advait Jain (Healthcare Robotics Lab, Georgia Tech.)
00029 
00030 import math, numpy as np
00031 import sys, time
00032 
00033 NAME = 'utm_python_listener'
00034 import roslib; roslib.load_manifest('hrl_hokuyo')
00035 import rospy
00036 from sensor_msgs.msg import LaserScan
00037 from threading import RLock
00038 
00039 import hokuyo_processing as hp
00040 import copy
00041 
00042 import numpy as np
00043 
00044 class HokuyoScan():
00045     ''' This class has the data of a laser scan.
00046     '''
00047     def __init__(self,hokuyo_type,angular_res,max_range,min_range,start_angle,end_angle):
00048         ''' hokuyo_type - 'urg', 'utm'
00049             angular_res - angle (radians) between consecutive points in the scan.
00050             min_range, max_range -  in meters
00051             ranges,angles,intensities - 1xn_points numpy matrix.
00052         '''
00053         self.hokuyo_type = hokuyo_type
00054         self.angular_res = angular_res
00055         self.max_range   = max_range
00056         self.min_range   = min_range
00057         self.start_angle = start_angle
00058         self.end_angle   = end_angle
00059         self.n_points    = int((end_angle-start_angle)/angular_res)+1
00060 
00061         self.ranges      = None
00062         self.intensities = None
00063         self.angles = []
00064 
00065         for i in xrange(self.n_points):
00066             self.angles.append(hp.index_to_angle(self,i))
00067         self.angles = np.matrix(self.angles)
00068 
00069 
00070 class Urg():
00071     ''' get a scan from urg using player.
00072     '''
00073     def __init__(self, urg_number,start_angle=None,end_angle=None, host='localhost', port=6665):
00074         ''' host, port - hostname and port of the player server
00075         '''
00076         import player_functions as pf
00077         import playerc as pl
00078 
00079         self.player_client = pf.player_connect(host,port)
00080         self.laser = pl.playerc_laser(self.player_client, urg_number)
00081         if self.laser.subscribe(pl.PLAYERC_OPEN_MODE) != 0:
00082             raise RuntimeError("hokuyo_scan.Urg.__init__: Unable to connect to urg!\n")
00083 
00084         for i in range(10):
00085             self.player_client.read()
00086 
00087         start_angle_fullscan = -math.radians(654./2*0.36)
00088         end_angle_fullscan = math.radians(654./2*0.36)
00089         if start_angle == None or start_angle<start_angle_fullscan:
00090             start_angle_subscan = start_angle_fullscan
00091         else:
00092             start_angle_subscan = start_angle
00093 
00094         if end_angle == None or end_angle>end_angle_fullscan:
00095             end_angle_subscan = end_angle_fullscan
00096         else:
00097             end_angle_subscan = end_angle
00098 
00099         ang_res = math.radians(0.36)
00100         self.start_index_fullscan=(start_angle_subscan-start_angle_fullscan)/ang_res
00101         self.end_index_fullscan=(end_angle_subscan-start_angle_fullscan)/ang_res
00102 
00103         self.hokuyo_scan = HokuyoScan(hokuyo_type = 'urg', angular_res = math.radians(0.36),
00104                                       max_range = 4.0, min_range = 0.2,
00105                                       start_angle=start_angle_subscan,
00106                                       end_angle=end_angle_subscan)
00107 
00108     def get_scan(self, avoid_duplicate=False):
00109         ''' avoid_duplicate - avoids duplicates caused by querying player faster than it
00110                               can get new scans.
00111         '''
00112         curr_ranges = self.hokuyo_scan.ranges
00113         for i in range(10): # I get a new scan by the time i=4
00114             if self.player_client.read() == None:
00115                 raise RuntimeError('hokuyo_scan.Urg.get_scan: player_client.read() returned None.\n')
00116             sub_ranges = np.matrix(self.laser.ranges[self.start_index_fullscan:self.end_index_fullscan+1])
00117             if avoid_duplicate == False or np.any(curr_ranges != sub_ranges):
00118                 # got a fresh scan from player.
00119                 break
00120         self.hokuyo_scan.ranges = sub_ranges
00121         return copy.copy(self.hokuyo_scan)
00122 
00123 
00124 class Utm():
00125     ''' get a scan from a UTM using ROS
00126     '''
00127     def __init__(self, utm_number,start_angle=None,end_angle=None,ros_init_node=True):
00128 
00129         hokuyo_node_name = '/utm%d'%utm_number
00130 #        max_ang = rospy.get_param(hokuyo_node_name+'/max_ang')
00131 #        min_ang = rospy.get_param(hokuyo_node_name+'/min_ang')
00132 #        start_angle_fullscan = min_ang
00133 #        end_angle_fullscan = max_ang
00134 #        print 'max_angle:', math.degrees(max_ang)
00135 #        print 'min_angle:', math.degrees(min_ang)
00136 
00137         max_ang_degrees = rospy.get_param(hokuyo_node_name+'/max_ang_degrees')
00138         min_ang_degrees = rospy.get_param(hokuyo_node_name+'/min_ang_degrees')
00139         start_angle_fullscan = math.radians(min_ang_degrees)
00140         end_angle_fullscan = math.radians(max_ang_degrees)
00141 
00142         # This is actually determined by the ROS node params and not the UTM.
00143 #        start_angle_fullscan = -math.radians(1080./2*0.25) #270deg
00144 #        end_angle_fullscan = math.radians(1080./2*0.25)
00145 #        start_angle_fullscan = -math.radians(720./2*0.25)  #180deg
00146 #        end_angle_fullscan = math.radians(720./2*0.25)
00147 #        start_angle_fullscan = -math.radians(559./2*0.25)   #140deg
00148 #        end_angle_fullscan = math.radians(559./2*0.25)
00149 
00150         if start_angle == None or start_angle<start_angle_fullscan:
00151             start_angle_subscan = start_angle_fullscan
00152         else:
00153             start_angle_subscan = start_angle
00154 
00155         if end_angle == None or end_angle>end_angle_fullscan:
00156             end_angle_subscan = end_angle_fullscan
00157         else:
00158             end_angle_subscan = end_angle
00159 
00160         ang_res = math.radians(0.25)
00161         self.start_index_fullscan=int(round((start_angle_subscan-start_angle_fullscan)/ang_res))
00162         self.end_index_fullscan=int(round((end_angle_subscan-start_angle_fullscan)/ang_res))
00163 
00164         self.hokuyo_scan = HokuyoScan(hokuyo_type = 'utm', angular_res = math.radians(0.25),
00165                                       max_range = 10.0, min_range = 0.1,
00166                                       start_angle=start_angle_subscan,
00167                                       end_angle=end_angle_subscan)
00168 
00169         self.lock = RLock()
00170         self.lock_init = RLock()
00171         self.connected_to_ros = False
00172 
00173         self.ranges,self.intensities = None,None
00174 
00175         if ros_init_node:
00176             try:
00177                 print 'Utm: init ros node.'
00178                 rospy.init_node(NAME, anonymous=True)
00179             except rospy.ROSException, e:
00180                 print 'Utm: rospy already initialized. Got message', e
00181                 pass
00182 
00183         rospy.Subscriber("utm%d_scan"%(utm_number), LaserScan,
00184                          self.callback, queue_size = 1)
00185 
00186     def callback(self, scan):
00187         self.lock.acquire()
00188         self.connected_to_ros = True
00189         self.ranges = np.matrix(scan.ranges[self.start_index_fullscan:self.end_index_fullscan+1])
00190         self.intensities = np.matrix(scan.intensities[self.start_index_fullscan:self.end_index_fullscan+1])
00191         self.lock.release()
00192 
00193     def get_scan(self, avoid_duplicate=False):
00194         while self.connected_to_ros == False:
00195             pass
00196         while not rospy.is_shutdown():
00197             self.lock.acquire()
00198             if avoid_duplicate == False or np.any(self.hokuyo_scan.ranges!=self.ranges):
00199                 # got a fresh scan from ROS
00200                 self.hokuyo_scan.ranges = copy.copy(self.ranges)
00201                 self.hokuyo_scan.intensities = copy.copy(self.intensities)
00202                 self.lock.release()
00203                 break
00204             self.lock.release()
00205             time.sleep(0.001)
00206 
00207         return copy.copy(self.hokuyo_scan)
00208 
00209 
00210 class Hokuyo():
00211     ''' common class for getting scans from both urg and utm.
00212     '''
00213 
00214     def __init__(self, hokuyo_type, hokuyo_number, start_angle=None,
00215                  end_angle=None, flip=False, ros_init_node=True):
00216         ''' hokuyo_type - 'urg', 'utm'
00217                         - 'utm' requires ros revision 2536
00218                                          ros-kg revision 5612
00219             hokuyo_number - 0,1,2 ...
00220             start_angle, end_angle - unoccluded part of the scan. (radians)
00221             flip - whether to flip the scans (hokuyo upside-down)
00222         '''
00223         self.hokuyo_type = hokuyo_type
00224         self.flip = flip
00225 
00226         if hokuyo_type == 'urg':
00227             self.hokuyo = Urg(hokuyo_number,start_angle,end_angle)
00228         elif hokuyo_type == 'utm':
00229             self.hokuyo = Utm(hokuyo_number,start_angle,end_angle,ros_init_node=ros_init_node)
00230         else:
00231             raise RuntimeError('hokuyo_scan.Hokuyo.__init__: Unknown hokuyo type: %s\n'%(hokuyo_type))
00232 
00233     def get_scan(self, avoid_duplicate=False, avg=1, remove_graze=True):
00234         ''' avoid_duplicate - prevent duplicate scans which will happen if get_scan is
00235             called at a rate faster than the scanning rate of the hokuyo.
00236             avoid_duplicate == True, get_scan will block till new scan is received.
00237             (~.2s for urg and 0.05s for utm)
00238         '''
00239         l = []
00240         l2 = []
00241         for i in range(avg):
00242             hscan = self.hokuyo.get_scan(avoid_duplicate)
00243             l.append(hscan.ranges)
00244             l2.append(hscan.intensities)
00245 
00246         ranges_mat = np.row_stack(l)
00247         ranges_mat[np.where(ranges_mat==0)] = -1000. # make zero pointvery negative
00248         ranges_avg = (ranges_mat.sum(0)/avg)
00249         if self.flip:
00250             ranges_avg = np.fliplr(ranges_avg)
00251         hscan.ranges = ranges_avg
00252     
00253         intensities_mat = np.row_stack(l2)
00254         if self.hokuyo_type == 'utm':
00255             hscan.intensities = (intensities_mat.sum(0)/avg)
00256 
00257         if remove_graze:
00258             if self.hokuyo_type=='utm':
00259                 hp.remove_graze_effect_scan(hscan)
00260             else:
00261                 print 'hokuyo_scan.Hokuyo.get_scan: hokuyo type is urg, but remove_graze is True'
00262 
00263         return hscan
00264 
00265 
00266 
00267 if __name__ == '__main__':
00268     import pylab as pl
00269 
00270 #    h = Hokuyo('urg', 0)
00271     h = Hokuyo('utm', 0, flip=True)
00272     print 'getting first scan'
00273     scan1 = h.get_scan(avoid_duplicate=True)
00274 #    hp.get_xy_map(scan1)
00275     t_list = []
00276     for i in range(200):
00277         t0 = time.time()
00278         scan2 = h.get_scan(avoid_duplicate=True,avg=1,remove_graze=False)
00279 #        scan = h.get_scan(avoid_duplicate=False)
00280         t1 = time.time()
00281         print t1-t0, scan1==scan2
00282         t_list.append(t1-t0)
00283         scan1=scan2
00284     print scan1.ranges.shape
00285     print scan1.angles.shape
00286 
00287 #    t_mat = np.matrix(t_list)
00288 #    print '#################################################'
00289 #    print 'mean time between scans:', t_mat.mean()
00290 #    print 'standard deviation:', np.std(t_mat)
00291 
00292     pl.plot(t_list)
00293     pl.show()
00294 
00295 
00296 
00297 
00298 
00299 
00300 


hrl_hokuyo
Author(s): Advait Jain, Advisor: Prof. Charlie Kemp, Lab: Healthcare Robotics Lab at Georgia Tech
autogenerated on Wed Nov 27 2013 11:55:51