seeker.py
Go to the documentation of this file.
00001 #!/usr/bin/python
00002 
00003 import roslib; roslib.load_manifest('assistive_teleop')
00004 import rospy
00005 import math
00006 import decimal
00007 import numpy as np
00008 import tf
00009 from tf import transformations as tft
00010 from geometry_msgs.msg import PoseWithCovarianceStamped, PointStamped, Twist, Point32, PoseStamped
00011 from sensor_msgs.msg import LaserScan, PointCloud
00012 from std_msgs.msg import String
00013 import costmap_services.python_client as costmap
00014 
00015 class Follower:
00016 
00017     def __init__(self):
00018         rospy.init_node('relative_servoing')
00019         rospy.Subscriber('robot_pose_ekf/odom_combined', PoseWithCovarianceStamped, self.update_position) 
00020         rospy.Subscriber('/base_scan', LaserScan, self.update_base_laser)
00021         rospy.Subscriber('/goal', PoseStamped, self.update_goal)
00022         self.vel_out = rospy.Publisher('base_controller/command', Twist)
00023         self.rate_test = rospy.Publisher('rate_test', String)
00024         #self.cs = costmap.CostmapServices( accum = 3 )
00025         self.tfl = tf.TransformListener()
00026         #self.driver = rospy.Publisher('/base_controller/command', Twist)
00027         self.left_out = rospy.Publisher('/left_points', PointCloud)
00028         self.right_out = rospy.Publisher('/right_points', PointCloud)
00029         self.front_out = rospy.Publisher('/front_points', PointCloud)
00030         #Initialize variables, so as not to spew errors before seeing a goal
00031         self.command = Twist()
00032         self.goal_received = False
00033         self.goal_present = False
00034         self.bfp_goal = PoseStamped()
00035         self.odom_goal = PoseStamped()
00036         self.x_max = 0.5
00037         self.x_min = 0.05
00038         self.y_man = 0.3
00039         self.y_min = 0.05
00040         self.z_max = 0.5
00041         self.z_min = 0.05
00042         self.ang_goal = 0.0
00043         self.ang_thresh_small = 0.01
00044         self.ang_thresh_big = 0.04
00045         self.ang_thresh = self.ang_thresh_big
00046         self.retreat_thresh = 0.3
00047         self.curr_pos = PoseWithCovarianceStamped()
00048         self.dist_thresh = 0.4
00049         self.left = [[],[]]
00050         self.right = [[],[]]
00051         self.front = [[],[]]
00052 
00053     def update_goal(self, msg):
00054         self.goal_received = True
00055         msg.header.stamp = rospy.Time.now()
00056                 
00057         #if not msg.header.frame_id == '/base_footprint' or msg.header.frame_id == 'base_footprint'
00058         #    self.tfl.waitForTransform(msg.header.frame_id, '/base_footprint', msg.header.stamp, rospy.Duration(0.5))
00059         #    msg = self.tfl.transformPose('/base_footprint', msg)
00060         #self.ang_to_goal = 
00061 
00062         self.tfl.waitForTransform(msg.header.frame_id, '/base_footprint', msg.header.stamp, rospy.Duration(0.5))
00063         self.bfp_goal = self.tfl.transformPose('/base_footprint', msg)
00064         self.tfl.waitForTransform(msg.header.frame_id, 'odom_combined', msg.header.stamp, rospy.Duration(0.5))
00065         self.odom_goal = self.tfl.transformPose('/odom_combined', msg)
00066         
00067         ang_to_goal = math.atan2(self.bfp_goal.pose.position.y, self.bfp_goal.pose.position.x)
00068         self.ang_goal = self.curr_ang[2] + ang_to_goal #The desired angular position (the current angle in odom, plus the robot-relative change to face goal)
00069         #print "New Goal: \r\n %s" %self.bfp_goal
00070 
00071     def update_position(self, msg):
00072         #self.curr_pose = msg.pose.pose
00073         self.curr_ang = tft.euler_from_quaternion([msg.pose.pose.orientation.x, msg.pose.pose.orientation.y, msg.pose.pose.orientation.z, msg.pose.pose.orientation.w])
00074         self.ang_diff = np.unwrap([0, self.ang_goal - self.curr_ang[2]])[1] # Normalized via unwrap relative to 0; (keeps between -pi/pi)
00075         #print "Ang Diff: %s" %self.ang_diff
00076 
00077         self.dist_to_goal = math.sqrt((self.odom_goal.pose.position.x-msg.pose.pose.position.x)**2 + (self.odom_goal.pose.position.y-msg.pose.pose.position.y)**2)
00078         #print "Dist to goal: %s" %self.dist_to_goal
00079 
00080         if self.goal_received:
00081             if self.dist_to_goal < self.dist_thresh and abs(self.ang_diff) < self.ang_thresh:
00082                 self.goal_present = False
00083                 #self.goal_received = False
00084                 #print "Achieved Goal!"
00085             else:
00086                 self.goal_present = True
00087 
00088     def update_base_laser(self, msg):
00089         max_angle = msg.angle_max
00090         ranges = np.array(msg.ranges)
00091         angles = np.arange(msg.angle_min, msg.angle_max, msg.angle_increment)
00092         near_angles = np.extract(np.logical_and(ranges<1, ranges>0.003), angles)#Filter out noise (<0.003), distant points(>1m), leaves nearby, relevant obstacles
00093         near_ranges = np.extract(np.logical_and(ranges<1, ranges>0.003), ranges)
00094         #print "Min in Ranges: %s" %min(ranges)
00095        
00096         #if len(near_ranges) > 0:
00097         xs = near_ranges * np.cos(near_angles)
00098         ys = near_ranges * np.sin(near_angles)
00099         #print "xs: %s" %xs
00100         self.points = np.vstack((xs,ys))
00101         #print "Points: %s" %points
00102         self.bfp_points = np.vstack((np.add(0.275, xs),ys))
00103         #print "bfp Points: %s" %bfp_points
00104         self.bfp_dists = np.sqrt(np.add(np.square(self.bfp_points[0][:]),np.square(self.bfp_points[1][:])))
00105         #print min(self.bfp_dists)
00106         if len(self.bfp_dists) >0:
00107             if min(self.bfp_dists) > 0.5:
00108                 self.rot_safe = True
00109             else:
00110                 self.rot_safe = False
00111         else:
00112             self.rot_safe = True
00113         
00114         self.left = np.vstack((xs[np.nonzero(ys>0.35)[0]], ys[np.nonzero(ys>0.35)[0]]))
00115         self.right = np.vstack((xs[np.nonzero(ys<-0.35)[0]], ys[np.nonzero(ys<-0.35)[0]]))
00116         self.front = np.vstack((np.extract(np.logical_and(ys<0.35,ys>-0.35),xs), np.extract(np.logical_and(ys<0.35, ys>-0.35),ys)))
00117 
00118         front_dist = (self.front[:][0]**2+self.front[:][1]**2)**(1/2)
00119 
00120         ##Testing and Visualization:###
00121         if len(self.left[:][0]) > 0:
00122             leftScan  = PointCloud()
00123             leftScan.header.frame_id = '/base_laser_link'
00124             leftScan.header.stamp = rospy.Time.now()
00125         
00126             for i in range(len(self.left[0][:])):
00127                 pt = Point32()
00128                 pt.x = self.left[0][i]
00129                 pt.y = self.left[1][i]
00130                 pt.z = 0
00131                 leftScan.points.append(pt)
00132             
00133             self.left_out.publish(leftScan)
00134 
00135         if len(self.right[:][0]) > 0:
00136             rightScan = PointCloud()
00137             rightScan.header.frame_id = '/base_laser_link'
00138             rightScan.header.stamp = rospy.Time.now()
00139 
00140             for i in range(len(self.right[:][0])):
00141                 pt = Point32()
00142                 pt.x = self.right[0][i]
00143                 pt.y = self.right[1][i]
00144                 pt.z = 0
00145                 rightScan.points.append(pt)
00146             
00147             self.right_out.publish(rightScan)
00148 
00149         if len(self.front[:][0]) > 0:
00150             frontScan = PointCloud()
00151             frontScan.header.frame_id = '/base_laser_link'
00152             frontScan.header.stamp = rospy.Time.now()
00153             
00154             for i in range(len(self.front[:][0])):
00155                 pt = Point32()
00156                 pt.x = self.front[0][i]
00157                 pt.y = self.front[1][i]
00158                 pt.z = 0
00159                 frontScan.points.append(pt)
00160             
00161             self.front_out.publish(frontScan)
00162 
00163     def set_rot(self):
00164         if abs(self.ang_diff) < self.ang_thresh: #Fully oriented, relax constraint to avoid osscilation
00165             self.ang_thresh = self.ang_thresh_big
00166             self.command.angular.z = 0.0
00167 
00168         else: # Not fully oriented, continue until pointed within small constraint
00169             if self.rot_safe: # Check for obstacles in the narrow rotation radius
00170                 self.command.angular.z = np.sign(self.ang_diff)*np.clip(abs(0.35*self.ang_diff), 0.1, 0.5)
00171                 self.ang_thresh = self.ang_thresh_small
00172             else:
00173                 print "Cannot Rotate, obstacles nearby"
00174 
00175     def set_trans(self):
00176         if abs(self.ang_diff) < math.pi/20 and self.dist_to_goal > self.dist_thresh: #Facing the right direction and not there yet, so start moving.
00177             self.command.linear.x = np.clip(self.dist_to_goal*0.125, 0.15, 0.3)
00178         else:
00179             self.command.linear.x = 0.0
00180 
00181         ##Determine obstacle avoidance rotation to avoid obstacles in front of robot#
00182     def avoid_obstacles(self):
00183         if len(self.front[0][:]) > 0:
00184             if min(self.front[0][:]) < self.retreat_thresh: #0.225:  #0.5 (round-up on corner-to-corner radius of robot) - 0.275 (x diff from base laser link to base footprint)
00185                 self.command.linear.x = -0.05
00186                 self.command.angular.z = 0.0
00187                 print "TOO CLOSE: Back up slowly..." # This should probably be avoided...
00188                 self.retreat_thresh = 0.4
00189             elif min(self.front[0][:]) < 0.6: 
00190                 self.retreat_thresh = 0.3
00191                 print "Turning Away from obstacles in front"
00192                 self.command.linear.x = 0.0
00193                 lfobs = self.front[0][np.nonzero(self.front[1]>0)]
00194                 #print "lfobs: %s" %lfobs
00195                 rfobs = self.front[0][np.nonzero(self.front[1]<0)]
00196                 #print "rfobs: %s" %rfobs
00197                 weight = np.reciprocal(np.sum(np.reciprocal(rfobs)) - np.sum(np.reciprocal(lfobs)))
00198                 if weight > 0:
00199                     self.command.angular.z = 0.1 
00200                 else:
00201                     self.command.angular.z = -0.1
00202             else:
00203                 self.retreat_thresh = 0.3
00204 
00205     def left_clear(self): # Base Laser cannot see obstacles beside the back edge of the robot, which could cause problems, especially just after passing through doorways...
00206         if len(self.left[0][:])>0:
00207             #Find points directly to the right or left of the robot (not in front or behind)
00208             # x<0.1 (not in front), x>-0.8 (not behind)
00209             left_obs = self.left[:, self.left[1,:]<0.4] #points too close.
00210             if len(left_obs[0][:])>0:
00211                 left_obs = left_obs[:, np.logical_and(left_obs[0,:]<0.15, left_obs[0,:]>-0.25)]
00212                 if len(left_obs[:][0])>0:
00213                     print "Obstacle immediately to the left, don't turn that direction"
00214                     if self.command.angular.z > 0:
00215                         self.command.angular.z = 0
00216 
00217     def right_clear(self):
00218         if len(self.right[0][:])>0:
00219             #Find points directly to the right or left of the robot (not in front or behind)
00220             # x<0.1 (not in front), x>-0.8 (not behind)
00221             right_obs = self.right[:, self.right[1,:]<0.4] #points too close.
00222             if len(right_obs[0][:])>0:
00223                 right_obs = right_obs[:, np.logical_and(right_obs[0,:]<0.15, right_obs[0,:]>-0.25)]
00224                 if len(right_obs[:][0])>0:
00225                     print "Obstacle immediately to the right, don't turn that direction"
00226                     if self.command.angular.z < 0:
00227                         self.command.angular.z = 0
00228 
00229     def check_costmap(self):
00230         if self.cs.scoreTraj_PosHyst( self.command.linear.x, self.command.linear.y, self.command.linear.z ) != -1.0:
00231             return True
00232         else:
00233             return False
00234 
00235     def run(self):
00236         if self.goal_present:
00237             self.set_trans()
00238             print "linear %s" %self.command.linear.x
00239             if self.command.linear.x == 0: 
00240                 self.set_rot()
00241                 self.vel_out.publish(self.command)
00242                 return 
00243             else:
00244                 self.set_rot()
00245             if self.command.angular.z == 0 and self.command.linear.x == 0:
00246                 print "Can't rot, so move foreward"
00247                 self.commad.linear.x = 0.1
00248             self.avoid_obstacles()
00249             
00250             self.left_clear()
00251             self.right_clear()
00252           #  if check_costmap():
00253             print "Sending vel_command: \r\n %s" %self.command
00254             self.vel_out.publish(self.command)
00255           #  else:
00256             #    print "COSTMAP SENSES COLLISION, NOT MOVING"
00257         else:
00258             pass
00259 
00260 if __name__ == '__main__':
00261     Follower = Follower()
00262     r = rospy.Rate(10)
00263     while not rospy.is_shutdown():
00264         Follower.run()
00265         r.sleep()


assistive_teleop
Author(s): Phillip M. Grice, Advisor: Prof. Charlie Kemp, Lab: The Healthcare Robotoics Lab at Georgia Tech.
autogenerated on Wed Nov 27 2013 11:35:34