global_path_follower.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 """
00004 on any new /initialpose, do full rotation, then delay (to hone in amcl)
00005 
00006 follow something ~15th pose in global path for all moves (about 0.3m away?)
00007     -maximum path length seems to be about 35*5 (45*5 max) for 2-3 meter path
00008     -(longer if more turns -- go for 15th or 20th pose, or max if less, should be OK)
00009 
00010 ignore local path, except for determining if at goal or not
00011         if no recent local path, must be at goal: followpath = False, goalpose = true
00012 
00013 requires dwa_base_controller, global path updated continuously as bot moves
00014 
00015 """
00016 
00017 
00018 import rospy, tf
00019 import oculusprimesocket
00020 from nav_msgs.msg import Odometry
00021 import math
00022 from nav_msgs.msg import Path
00023 from geometry_msgs.msg import PoseWithCovarianceStamped
00024 from actionlib_msgs.msg import GoalStatusArray
00025 from move_base_msgs.msg import MoveBaseActionGoal
00026 
00027 listentime = 0.6 # 0.6 # allows odom + amcl to catch up
00028 nextmove = 0
00029 odomx = 0
00030 odomy = 0
00031 odomth = 0
00032 targetx = 0     
00033 targety = 0
00034 targetth = 0
00035 followpath = False
00036 pathid = None
00037 goalth = 0 
00038 initialturn = False
00039 waitonaboutface = 0
00040 minturn = math.radians(8) # (was 6) -- 0.21 minimum for pwm 255
00041 minlinear = 0.08 # was 0.05
00042 maxlinear = 0.5
00043 lastpath = 0  # refers to localpath
00044 goalpose = False
00045 goalseek = False
00046 meterspersec = 0.33 # linear speed  TODO: get from java
00047 degperms = 0.0857 # turnspeed    TODO: get from java
00048 tfth = 0
00049 globalpathposenum = 20 # just right
00050 listener = None
00051 
00052 
00053 def pathCallback(data): # local path
00054         global goalpose, lastpath
00055         
00056         lastpath = rospy.get_time()
00057         goalpose = False
00058         
00059 def globalPathCallback(data):
00060         global targetx, targety, targetth , followpath, pathid
00061         
00062         n = len(data.poses)
00063         if n < 5:
00064                 return
00065                 
00066         if n-1 < globalpathposenum:
00067                 p = data.poses[n-1] 
00068         else:
00069                 p = data.poses[globalpathposenum]
00070         
00071         targetx = p.pose.position.x
00072         targety = p.pose.position.y
00073         quaternion = ( p.pose.orientation.x, p.pose.orientation.y,
00074         p.pose.orientation.z, p.pose.orientation.w )
00075         targetth = tf.transformations.euler_from_quaternion(quaternion)[2]
00076         
00077         followpath = True
00078         pathid = data.header.seq
00079 
00080 def odomCallback(data):
00081         global odomx, odomy, odomth
00082         odomx = data.pose.pose.position.x
00083         odomy = data.pose.pose.position.y
00084         quaternion = ( data.pose.pose.orientation.x, data.pose.pose.orientation.y,
00085         data.pose.pose.orientation.z, data.pose.pose.orientation.w )
00086         odomth = tf.transformations.euler_from_quaternion(quaternion)[2]
00087         
00088         # determine direction (angle) on map
00089         global tfth, listener    
00090         try:
00091                 (trans,rot) = listener.lookupTransform('/map', '/odom', rospy.Time(0))
00092                 quaternion = (rot[0], rot[1], rot[2], rot[3])
00093                 tfth = tf.transformations.euler_from_quaternion(quaternion)[2]
00094         except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException):
00095                 pass    
00096 
00097 def intialPoseCallback(data):
00098         if data.pose.pose.position.x == 0 and data.pose.pose.position.y == 0:
00099                 return
00100         # do full rotation on pose estimate, to hone-in amcl (if not docked)
00101         rospy.sleep(0.5) # let amcl settle
00102         oculusprimesocket.clearIncoming()  # why?
00103         oculusprimesocket.sendString("right 360")
00104         oculusprimesocket.waitForReplySearch("<state> direction stop")
00105 
00106         
00107 def goalCallback(d):
00108         global goalth, goalpose, lastpath, initialturn, followpath, nextmove
00109 
00110         # to prevent immediately rotating wrongly towards new goal direction 
00111         lastpath = rospy.get_time()
00112         goalpose = False
00113 
00114         # set goal angle
00115         data = d.goal.target_pose
00116         quaternion = ( data.pose.orientation.x, data.pose.orientation.y,
00117         data.pose.orientation.z, data.pose.orientation.w )
00118         goalth = tf.transformations.euler_from_quaternion(quaternion)[2]
00119         initialturn = True
00120         followpath = False
00121         nextmove = lastpath + 2 # sometimes globalpath still points at previoius goal
00122         
00123 def goalStatusCallback(data):
00124         global goalseek
00125         goalseek = False
00126         if len(data.status_list) == 0:
00127                 return
00128         status = data.status_list[len(data.status_list)-1] # get latest status
00129         if status.status == 1:
00130                 goalseek = True
00131 
00132 def move(ox, oy, oth, tx, ty, tth, gth):
00133         global followpath, goalpose, tfth, pathid, initialturn, waitonaboutface
00134         global odomx, odomy, odomth
00135 
00136         currentpathid = pathid
00137 
00138         # determine xy deltas for move
00139         distance = 0
00140         if followpath:
00141                 dx = tx - ox
00142                 dy = ty - oy    
00143                 distance = math.sqrt( pow(dx,2) + pow(dy,2) )
00144         
00145         goalrotate = False
00146         if distance > 0:
00147                 th = math.acos(dx/distance)
00148                 if dy <0:
00149                         th = -th
00150         elif goalpose:
00151                 th = gth - tfth
00152                 goalrotate = True
00153         else:
00154                 th = tth
00155         
00156         # determine angle delta for move
00157         dth = th - oth
00158         if dth > math.pi:
00159                 dth = -math.pi*2 + dth
00160         elif dth < -math.pi:
00161                 dth = math.pi*2 + dth
00162                 
00163         # force minimums        
00164         if distance > 0 and distance < minlinear:
00165                 distance = minlinear
00166                 
00167         if distance > maxlinear:
00168                 distance = maxlinear
00169 
00170         # supposed to reduce zig zagging  (was 0.3)
00171         if dth < minturn*0.5 and dth > -minturn*0.5:
00172                 dth = 0
00173         elif dth >= minturn*0.5 and dth < minturn:
00174                 dth = minturn
00175         elif dth <= -minturn*0.5 and dth > -minturn:
00176                 dth = -minturn
00177 
00178         oculusprimesocket.clearIncoming()
00179 
00180         # if turning more than 120 deg, inch forward, make sure not transient obstacle (like door transfer)
00181         if abs(dth) > 2.0944 and not goalrotate and not initialturn and waitonaboutface < 1: 
00182                 oculusprimesocket.sendString("forward 0.25")
00183                 oculusprimesocket.waitForReplySearch("<state> direction stop")
00184                 waitonaboutface += 1 # only do this once
00185                 rospy.sleep(1)
00186                 return
00187                 
00188         waitonaboutface = 0
00189 
00190         if not pathid == currentpathid:
00191                 return
00192 
00193         if dth > 0:
00194                 oculusprimesocket.sendString("left " + str(int(math.degrees(dth))) ) 
00195                 oculusprimesocket.waitForReplySearch("<state> direction stop")
00196         elif dth < 0:
00197                 oculusprimesocket.sendString("right " +str(int(math.degrees(-dth))) )
00198                 oculusprimesocket.waitForReplySearch("<state> direction stop")
00199 
00200         if distance > 0:
00201                 oculusprimesocket.sendString("forward "+str(distance))
00202                 rospy.sleep(distance/meterspersec)
00203                 initialturn = False
00204 
00205         # if goalrotate:
00206                 # rospy.sleep(1) 
00207                 
00208                         
00209 def cleanup():
00210         # oculusprimesocket.sendString("move stop")
00211         # oculusprimesocket.sendString("state delete navigationenabled")
00212         oculusprimesocket.sendString("log global_path_follower.py disconnecting")   
00213 
00214 
00215 # MAIN
00216 
00217 # rospy.init_node('dwa_base_controller', anonymous=False)
00218 rospy.init_node('global_path_follower', anonymous=False)
00219 listener = tf.TransformListener()
00220 oculusprimesocket.connect()
00221 rospy.on_shutdown(cleanup)
00222 
00223 rospy.Subscriber("odom", Odometry, odomCallback)
00224 rospy.Subscriber("move_base/DWAPlannerROS/local_plan", Path, pathCallback)
00225 rospy.Subscriber("move_base/goal", MoveBaseActionGoal, goalCallback)
00226 rospy.Subscriber("move_base/status", GoalStatusArray, goalStatusCallback)
00227 rospy.Subscriber("move_base/DWAPlannerROS/global_plan", Path, globalPathCallback)
00228 rospy.Subscriber("initialpose", PoseWithCovarianceStamped, intialPoseCallback)
00229 
00230 oculusprimesocket.sendString("log global_path_follower.py connected") 
00231 # oculusprimesocket.sendString("state odomturndpms "+str(degperms))  # degrees per ms 
00232 # oculusprimesocket.sendString("state odomturnpwm 100")  # approx starting point smooth floor
00233 # oculusprimesocket.sendString("state odomlinearmpms "+str(meterspersec/1000)) 
00234 # oculusprimesocket.sendString("state odomlinearpwm 150")  # approx starting point
00235 
00236 # oculusprimesocket.sendString("speed "+str(linearspeed) )
00237 
00238 while not rospy.is_shutdown():
00239         t = rospy.get_time()
00240         
00241         if t >= nextmove:
00242                 # nextmove = t + listentime
00243                 if goalseek and (followpath or goalpose): 
00244                         move(odomx, odomy, odomth, targetx, targety, targetth, goalth) # blocking
00245                         nextmove = rospy.get_time() + listentime
00246                         followpath = False
00247         
00248         if t - lastpath > 3:
00249                 goalpose = True
00250         
00251         rospy.sleep(0.01)
00252         


oculusprime
Author(s): Colin Adamson
autogenerated on Sat Jun 8 2019 20:04:29