00001
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
00025 self.tfl = tf.TransformListener()
00026
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
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
00058
00059
00060
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
00069
00070
00071 def update_position(self, msg):
00072
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]
00075
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
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
00084
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)
00093 near_ranges = np.extract(np.logical_and(ranges<1, ranges>0.003), ranges)
00094
00095
00096
00097 xs = near_ranges * np.cos(near_angles)
00098 ys = near_ranges * np.sin(near_angles)
00099
00100 self.points = np.vstack((xs,ys))
00101
00102 self.bfp_points = np.vstack((np.add(0.275, xs),ys))
00103
00104 self.bfp_dists = np.sqrt(np.add(np.square(self.bfp_points[0][:]),np.square(self.bfp_points[1][:])))
00105
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
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:
00165 self.ang_thresh = self.ang_thresh_big
00166 self.command.angular.z = 0.0
00167
00168 else:
00169 if self.rot_safe:
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:
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
00182 def avoid_obstacles(self):
00183 if len(self.front[0][:]) > 0:
00184 if min(self.front[0][:]) < self.retreat_thresh:
00185 self.command.linear.x = -0.05
00186 self.command.angular.z = 0.0
00187 print "TOO CLOSE: Back up slowly..."
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
00195 rfobs = self.front[0][np.nonzero(self.front[1]<0)]
00196
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):
00206 if len(self.left[0][:])>0:
00207
00208
00209 left_obs = self.left[:, self.left[1,:]<0.4]
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
00220
00221 right_obs = self.right[:, self.right[1,:]<0.4]
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
00253 print "Sending vel_command: \r\n %s" %self.command
00254 self.vel_out.publish(self.command)
00255
00256
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()