00001
00002
00003 import roslib
00004 roslib.load_manifest('rfid_explore_room')
00005 import rospy
00006
00007 import tf
00008 from threading import Thread
00009 import actionlib
00010
00011 from move_base_msgs.msg import MoveBaseGoal, MoveBaseAction
00012 from visualization_msgs.msg import MarkerArray
00013 from visualization_msgs.msg import Marker
00014 from geometry_msgs.msg import Vector3, PoseStamped, Quaternion
00015 from std_msgs.msg import ColorRGBA
00016
00017 from explore_hrl.msg import ExploreAction, ExploreResult, ExploreGoal
00018
00019 import yaml
00020 import numpy as np, math
00021
00022 def retfalse():
00023 return False
00024
00025 class TFthread( Thread ):
00026 def __init__( self, df ):
00027 Thread.__init__( self )
00028 try:
00029 rospy.init_node( 'TFthread' )
00030 except:
00031 pass
00032 self.df = df
00033 self.bc = tf.TransformBroadcaster()
00034 self.should_run = True
00035 self.start()
00036
00037 def publish_transform( self ):
00038 for room in self.df.keys():
00039 self.bc.sendTransform( ( self.df[room]['position']['x'],
00040 self.df[room]['position']['y'],
00041 self.df[room]['position']['z'] ),
00042 ( self.df[room]['orientation']['x'],
00043 self.df[room]['orientation']['y'],
00044 self.df[room]['orientation']['z'],
00045 self.df[room]['orientation']['w'] ),
00046 rospy.Time.now(),
00047 room,
00048 'map' )
00049
00050 def run( self ):
00051 rospy.logout( 'TFthread: Starting ' )
00052 r = rospy.Rate( 10 )
00053 while self.should_run and not rospy.is_shutdown():
00054 self.publish_transform()
00055 try:
00056 r.sleep()
00057 except:
00058 pass
00059 rospy.logout( 'TFthread: Starting ')
00060
00061 def stop( self ):
00062
00063 self.should_run = False
00064 self.join(5)
00065 if (self.isAlive()):
00066 raise RuntimeError('TFthread: Unable to stop thread ' )
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077 def standard_rad(t):
00078 if t > 0:
00079 return ((t + np.pi) % (np.pi * 2)) - np.pi
00080 else:
00081 return ((t - np.pi) % (np.pi * -2)) + np.pi
00082
00083
00084 class RoomExplore( ):
00085 def __init__( self, df, room, start_rad = 1.5 ):
00086 try:
00087 rospy.init_node( 'RoomExplore' )
00088 except:
00089 pass
00090 self.should_run = True
00091 self.frame = '/' + room
00092 self.old_markers = []
00093 self.mid = 1
00094
00095 self.height = df[room]['height']
00096 self.width = df[room]['width']
00097
00098 self.listener = tf.TransformListener()
00099 self.listener.waitForTransform( '/base_link', '/map', rospy.Time(0), timeout = rospy.Duration(100))
00100 self.pub = rospy.Publisher( 'visarr', Marker )
00101
00102 self.setup_poses( radius = start_rad )
00103 print 'Len: ', len(self.poses), ' Publishing.'
00104 self.publish_markers()
00105
00106 self._as = actionlib.SimpleActionServer( '/explore', ExploreAction, execute_cb = self.action_request )
00107 self._as.start()
00108 self.publish_markers()
00109 rospy.logout('Action should be started.')
00110
00111 def action_request( self, goal ):
00112 rospy.logout( 'room_explore: action_request received for radius: \'%2.2f\'' % goal.radius )
00113
00114 def preempt_func():
00115
00116 check = self._as.is_preempt_requested()
00117 if check:
00118 rospy.logout( 'room_explore: action_request preempted!' )
00119 return check
00120
00121 rv = self.begin_explore( goal.radius, preempt_func = preempt_func )
00122 rospy.logout( 'room_explore: action_request received result %d' % int(rv) )
00123
00124 if rv == True:
00125 self._as.set_succeeded( ExploreResult() )
00126
00127
00128 def begin_explore( self, radius, preempt_func = retfalse ):
00129 client = actionlib.SimpleActionClient( 'move_base', MoveBaseAction )
00130 rospy.logout( 'Waiting for move_base server' )
00131 client.wait_for_server()
00132
00133 rospy.logout( 'room_explore: setting radius' )
00134 all_goals = self.setup_poses( radius )
00135 self.publish_markers()
00136 for goal in all_goals:
00137
00138 goal.target_pose.header.stamp = rospy.Time.now()
00139
00140 client.send_goal( goal )
00141
00142 time_last_moving = rospy.Time.now()
00143 goal_time = rospy.Time.now()
00144
00145 new_pose = self.current_robot_position()
00146 ref_pose = self.current_robot_position()
00147
00148 r = rospy.Rate( 5 )
00149 while not rospy.is_shutdown():
00150 state = client.get_state()
00151 states = { 0: 'WAITING FOR GOAL ACK',
00152 1: 'PENDING',
00153 2: 'ACTIVE',
00154 3: 'WAITING FOR RESULT',
00155 4: 'WAITING FOR CANCEL ACK',
00156 5: 'RECALLING',
00157 6: 'PREEMPTING',
00158 7: 'DONE' }
00159
00160
00161
00162
00163 if state == 7 or state == 3:
00164 rospy.logout( 'room_explore: client no longer active' )
00165 print 'State: ', state, ' ', states[state]
00166 time_last_moving = rospy.Time.now()
00167 break
00168
00169 if preempt_func():
00170 rospy.logout( 'room_explore: preempted at a higher level.' )
00171 time_last_moving = rospy.Time.now()
00172 break
00173
00174 new_pose = self.current_robot_position()
00175 dx = new_pose[0] - ref_pose[0]
00176 dy = new_pose[1] - ref_pose[1]
00177 da = new_pose[-1] - ref_pose[-1]
00178
00179 if dx*dx + dy*dy > 0.02 or da*da > math.radians( 5 ):
00180 time_last_moving = rospy.Time.now()
00181 ref_pose = self.current_robot_position()
00182 rospy.logout('WE ARE MOVING')
00183
00184 if rospy.Time.now() - time_last_moving > rospy.Duration( 8 ):
00185 rospy.logout( 'We do not appear to have moved. Aborting current goal.' )
00186 client.cancel_all_goals()
00187 time_last_moving = rospy.Time.now()
00188 break
00189
00190 if rospy.Time.now() - goal_time > rospy.Duration( 30 ):
00191 rospy.logout( 'Goal not achieved after 30 seconds. Aborting.' )
00192 client.cancel_all_goals()
00193 time_last_moving = rospy.Time.now()
00194 break
00195
00196 r.sleep()
00197
00198 client.cancel_all_goals()
00199
00200 if preempt_func():
00201 break
00202
00203 return True
00204
00205
00206 def current_robot_position( self ):
00207 ps = PoseStamped()
00208 ps.header.stamp = rospy.Time(0)
00209 ps.header.frame_id = '/base_link'
00210 ps.pose.orientation.w = 1.0
00211
00212 try:
00213 ps_map = self.listener.transformPose( '/map', ps )
00214 except:
00215 rospy.logout( 'room_explore: Transform failed' )
00216 ps_map = PoseStamped()
00217 ps_map.header.stamp = rospy.Time.now()
00218 ps_map.header.frame_id = '/map'
00219 ps_map.pose.orientation = new_quat
00220
00221 roll, pitch, yaw = tf.transformations.euler_from_quaternion(( ps_map.pose.orientation.x,
00222 ps_map.pose.orientation.y,
00223 ps_map.pose.orientation.z,
00224 ps_map.pose.orientation.w ))
00225
00226 rv = [ ps_map.pose.position.x,
00227 ps_map.pose.position.y,
00228 ps_map.pose.position.z,
00229 roll,
00230 pitch,
00231 yaw ]
00232
00233
00234 return rv
00235
00236
00237 def setup_poses( self, radius ):
00238 self.radius = radius
00239 xdir = np.arange( self.radius / 2.0, self.height + self.radius / 2.0, self.radius )
00240 ydir = np.arange( self.radius / 2.0, self.width + self.radius / 2.0, self.radius )
00241
00242 move_dir = 0.0
00243 self.poses = []
00244 mod = 0
00245 for y in ydir:
00246 if mod == 0:
00247 xord = xdir
00248 else:
00249 xord = xdir[::-1]
00250
00251 for x in xord:
00252 goal = MoveBaseGoal()
00253 goal.target_pose.header.frame_id = self.frame
00254 goal.target_pose.header.stamp = rospy.Time.now()
00255 goal.target_pose.pose.position.x = x
00256 goal.target_pose.pose.position.y = y
00257 quat = tf.transformations.quaternion_from_euler( 0.0, 0.0, move_dir )
00258 goal.target_pose.pose.orientation.x = quat[0]
00259 goal.target_pose.pose.orientation.y = quat[1]
00260 goal.target_pose.pose.orientation.z = quat[2]
00261 goal.target_pose.pose.orientation.w = quat[3]
00262
00263 self.poses.append( goal )
00264 move_dir = standard_rad( move_dir + np.pi )
00265 mod = ( mod + 1 ) % 2
00266 return self.poses
00267
00268 def destroy_old_markers( self ):
00269 for m in self.old_markers:
00270 m.action = m.DELETE
00271 self.pub.publish( m )
00272 self.old_markers = []
00273
00274 def publish_markers( self ):
00275 self.destroy_old_markers()
00276 for i,g in enumerate(self.poses):
00277 self.mid += 1
00278 m = Marker()
00279 m.ns = 'explore_poses'
00280 m.id = self.mid
00281 m.action = m.ADD
00282 m.type = m.ARROW
00283 m.header.frame_id = self.frame
00284 m.header.stamp = rospy.Time.now()
00285 m.scale = Vector3( 0.15, 1.0, 1.0 )
00286 m.color = ColorRGBA( 0.2, 1.0, 0.2, 0.7 )
00287 m.pose = g.target_pose.pose
00288
00289 self.old_markers.append( m )
00290 self.pub.publish( m )
00291
00292 def goals( self ):
00293 return self.poses
00294
00295
00296
00297
00298
00299
00300
00301 if __name__ == '__main__':
00302 import optparse
00303 p = optparse.OptionParser()
00304 p.add_option('--yaml', action='store', type='string', dest='yaml',
00305 help='Room definition file (required)', default='')
00306 p.add_option('--room', action='store', type='string', dest='room',
00307 help='Specific room [default \'hrl\']', default='hrl')
00308 opt, args = p.parse_args()
00309
00310 if opt.yaml == '':
00311 print 'room_explore: YAML FILE REQUIRED.'
00312 else:
00313 print 'Using YAML file: ', opt.yaml
00314
00315 f = open( opt.yaml )
00316 dat = yaml.load( f )
00317 f.close()
00318
00319 TFthread( dat )
00320
00321 re = RoomExplore( dat, opt.room, 1.5 )
00322 rospy.sleep( 4 )
00323 re.publish_markers()
00324
00325 rospy.spin()
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346