path_marker_2.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 """
00004 Copyright (c) 2014, Robotnik Automation
00005 All rights reserved.
00006 
00007 Redistribution and use in source and binary forms, with or without
00008 modification, are permitted provided that the following conditions are met:
00009 
00010     * Redistributions of source code must retain the above copyright
00011       notice, this list of conditions and the following disclaimer.
00012     * Redistributions in binary form must reproduce the above copyright
00013       notice, this list of conditions and the following disclaimer in the
00014       documentation and/or other materials provided with the distribution.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00017 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00018 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00019 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00020 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00021 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00022 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00023 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00024 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00025 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00026 POSSIBILITY OF SUCH DAMAGE.
00027 """
00028 
00029 import roslib; roslib.load_manifest("interactive_markers")
00030 import rospy, rospkg
00031 import copy
00032 import os
00033 
00034 from interactive_markers.interactive_marker_server import *
00035 from visualization_msgs.msg import InteractiveMarker, Marker, InteractiveMarkerControl
00036 from interactive_markers.menu_handler import *
00037 
00038 import actionlib
00039 from geometry_msgs.msg import Pose2D
00040 from planner_msgs.msg import goal, GoToGoal, GoToAction
00041 from std_srvs.srv import Empty
00042 
00043 # Client based on ActionServer to send goals to the purepursuit node
00044 class PurepursuitClient():
00045         
00046         def __init__(self, planner_name):
00047                 self.planner_name = planner_name
00048                 # Creates the SimpleActionClient, passing the type of the action
00049                 # (GoTo) to the constructor.
00050                 self.client = actionlib.SimpleActionClient(planner_name, GoToAction)
00051 
00052         ## @brief Sends the goal to 
00053         ## @return 0 if OK, -1 if no server, -2 if it's tracking a goal at the moment
00054         def goTo(self, goal_list):
00055                 # Waits until the action server has started up and started
00056                 # listening for goals.
00057                 if self.client.wait_for_server(timeout = rospy.Duration(3.0) ):
00058                         #if self.getState() != GoalStatus.LOST:
00059                         #       rospy.loginfo('PurepursuitClient: planner is tracking a goal')
00060                         #       return -2
00061                                 
00062                         g = GoToGoal(target = goal_list)
00063                         rospy.loginfo('PurepursuitClient: Sendig %d waypoints'%(len(goal_list)))
00064                         self.client.send_goal(g)
00065                         return 0
00066                 else:
00067                         rospy.logerr('PurepursuitClient: Error waiting for server')
00068                         return -1
00069         
00070         ## @brief cancel the current goal
00071         def cancel(self):               
00072                 rospy.loginfo('PurepursuitClient: cancelling the goal')
00073                 self.client.cancel_goal()
00074         
00075         ## @brief Get the state information for this goal
00076     ##
00077     ## Possible States Are: PENDING, ACTIVE, RECALLED, REJECTED,
00078     ## PREEMPTED, ABORTED, SUCCEEDED, LOST.
00079     ##
00080     ## @return The goal's state. Returns LOST if this
00081     ## SimpleActionClient isn't tracking a goal.
00082         def getState(self):
00083                 return self.client.get_state()
00084         
00085         ## @brief Returns ret if OK, otherwise -1
00086         def getResult(self):
00087                 ret = self.client.get_result()
00088                 if not ret:
00089                         return -1
00090                 
00091                 else:
00092                         return ret
00093 
00094 ## @brief Class to manage  the creation of a Waypoint base on InteractiveMarker
00095 class PointPath(InteractiveMarker):
00096         
00097         def __init__(self, frame_id, name, description, is_manager = False, speed = 0.2):
00098                 InteractiveMarker.__init__(self)
00099                 
00100                 self.header.frame_id = frame_id
00101                 self.name = name
00102                 self.description = description
00103                 self.speed = speed
00104                 self.marker = Marker()
00105                 self.marker.type = Marker.CYLINDER
00106                 self.marker.scale.x = 0.1
00107                 self.marker.scale.y = 0.1
00108                 self.marker.scale.z = 0.4
00109                 self.marker.pose.position.z = 0.20
00110                 if is_manager:
00111                         self.marker.color.r = 0.8
00112                         self.marker.color.g = 0.0
00113                         self.marker.color.b = 0.0
00114                         self.marker.color.a = 0.5
00115                 else:
00116                         self.marker.color.r = 0.0
00117                         self.marker.color.g = 0.8
00118                         self.marker.color.b = 0.0
00119                         self.marker.color.a = 0.5
00120                         
00121                 self.marker_control = InteractiveMarkerControl()
00122                 self.marker_control.always_visible = True
00123                 self.marker_control.orientation.w = 1
00124                 self.marker_control.orientation.x = 0
00125                 self.marker_control.orientation.y = 1
00126                 self.marker_control.orientation.z = 0
00127                 self.marker_control.markers.append( self.marker )
00128                 self.marker_control.interaction_mode = InteractiveMarkerControl.MOVE_PLANE
00129                 
00130                 self.controls.append( self.marker_control )
00131                 
00132         ## @brief method called every time that an interaction is received      
00133         def processFeedback(self, feedback):
00134                 #p = feedback.pose.position
00135                 self.pose = feedback.pose
00136                 #print feedback.marker_name + " is now at " + str(p.x) + ", " + str(p.y) + ", " + str(p.z)
00137                 
00138 
00139 ## @brief Manages the creation of waypoints and how to send them to Purepursuit
00140 class PointPathManager(InteractiveMarkerServer):
00141         
00142         def __init__(self, name, frame_id, planner):
00143                 InteractiveMarkerServer.__init__(self, name)
00144                 self.list_of_points = []
00145                 self.frame_id = frame_id
00146                 self.counter_points = 0
00147                 
00148                 # Menu handler to create a menu
00149                 self.menu_handler = MenuHandler()
00150                 h_first_entry = self.menu_handler.insert( "Waypoints" )
00151                 #entry = self.menu_handler.insert( "Create New", parent=h_first_entry, callback=self.newPointCB)
00152                 entry_new = self.menu_handler.insert( "Create New", parent=h_first_entry)
00153                 entry = self.menu_handler.insert( "Delete last", parent=h_first_entry, callback=self.deletePointCB );
00154                 entry = self.menu_handler.insert( "Delete all", parent=h_first_entry, callback=self.deleteAllPointsCB );
00155                 entry = self.menu_handler.insert( "Save", parent=h_first_entry, callback=self.savePointsCB );
00156                 entry = self.menu_handler.insert( "Load", parent=h_first_entry, callback=self.loadPointsCB );
00157                 entry = self.menu_handler.insert( "0.2 m/s", parent=entry_new, callback=self.newPointCB_02)
00158                 entry = self.menu_handler.insert( "0.4 m/s", parent=entry_new, callback=self.newPointCB_04)
00159                 entry = self.menu_handler.insert( "0.6 m/s", parent=entry_new, callback=self.newPointCB_06)
00160                 h_second_entry = self.menu_handler.insert( "Path" )
00161                 entry = self.menu_handler.insert( "Go", parent=h_second_entry, callback=self.startRouteCB)      # Send the path from the first point to the last one
00162                 entry = self.menu_handler.insert( "Stop", parent=h_second_entry, callback=self.stopRouteCB)     # Stops the current path 
00163                 entry = self.menu_handler.insert( "Go back", parent=h_second_entry, callback=self.reverseRouteCB) # Sends the path from the last point to the first one
00164                 
00165                 # Creates the first point
00166                 #self.list_of_points.append(PointPath(frame_id, 'p1', 'p1'))
00167                 self.initial_point = PointPath(frame_id, 'PointManager', 'PointManager', True)
00168                 self.insert(self.initial_point, self.initial_point.processFeedback)
00169                 
00170                 self.menu_handler.apply( self, self.initial_point.name )
00171                 self.applyChanges()
00172                 
00173                 self.planner_client = PurepursuitClient(planner)
00174                 
00175                 # Locates and loads the UI file into the widget
00176                 rp = rospkg.RosPack()           
00177                 # loads a ui file for the dialog
00178                 self.points_file_path = os.path.join(rp.get_path('purepursuit_planner'), 'scripts', 'waypoints.txt')
00179                 
00180                 #rospy.Timer(rospy.Duration(5), self.createNewPoint)
00181                 self._go_service = rospy.Service('%s/go'%rospy.get_name(), Empty, self.goService)
00182                 self._go_back_service = rospy.Service('%s/go_back'%rospy.get_name(), Empty, self.goBackService)
00183                 self._cancel_service = rospy.Service('%s/cancel'%rospy.get_name(), Empty, self.cancelService)
00184                 
00185         
00186         ## @brief Creates a new PointPath and save it a list
00187         def createNewPoint(self, speed = 0.2):
00188                                         
00189                 ##print 'Creating new point %d'%(self.counter_points)
00190                 new_point = PointPath(self.frame_id, 'p%d'%(self.counter_points), 'p%d->%.1f'%(self.counter_points, speed), speed = speed)
00191                 #new_point = PointPath(self.frame_id, '1', '1')
00192                 
00193                 if len(self.list_of_points) > 1:
00194                         new_point.pose.position.x = self.list_of_points[self.counter_points-1].pose.position.x
00195                         new_point.pose.position.y = self.list_of_points[self.counter_points-1].pose.position.y
00196                 elif len(self.list_of_points) == 1:
00197                         new_point.pose.position.x = self.list_of_points[0].pose.position.x
00198                         new_point.pose.position.y = self.list_of_points[0].pose.position.y
00199         
00200                 new_point.pose.position.x = new_point.pose.position.x  + 1.0
00201                         
00202                 
00203                 #print 'Creating new point at position %.2lf, %.2lf, %.2lf'%(new_point.pose.position.x, new_point.pose.position.y, new_point.pose.position.z)
00204                 
00205                 self.list_of_points.append(new_point)
00206                 self.insert(new_point, new_point.processFeedback)
00207                 self.menu_handler.apply( self, 'p%d'%(self.counter_points) )
00208                 self.applyChanges()
00209                 self.counter_points = self.counter_points + 1
00210                 
00211                 #for i in self.list_of_points:
00212                 #       print 'Point %s: %.2lf, %.2lf, %.2lf'%(i.name, i.pose.position.x, i.pose.position.y, i.pose.position.z)
00213                         
00214                 return
00215         
00216         ## @brief Callback called to create a new poing 
00217         def newPointCB(self, feedback):
00218                 #print 'newPointCB'
00219                 self.createNewPoint()
00220         ## @brief Callback called to create a new poing 
00221         def newPointCB_02(self, feedback):
00222                 #print 'newPointCB'
00223                 self.createNewPoint(0.2)
00224         ## @brief Callback called to create a new poing 
00225         def newPointCB_04(self, feedback):
00226                 #print 'newPointCB'
00227                 self.createNewPoint(0.4)
00228         ## @brief Callback called to create a new poing 
00229         def newPointCB_06(self, feedback):
00230                 #print 'newPointCB'
00231                 self.createNewPoint(0.6)
00232                 
00233         ## @brief Callback called to create a new poing 
00234         def deletePointCB(self, feedback):
00235                 if self.counter_points > 0:
00236                          p = self.list_of_points.pop()
00237                          self.counter_points = self.counter_points - 1
00238                          self.erase(p.name)
00239                          self.applyChanges()
00240                          
00241                  #print 'deletePointCB' 
00242         
00243         ## @brief Function called to delete all the waypoints
00244         def deleteAllPoints(self):
00245                 for i in range(len(self.list_of_points)):
00246                         p = self.list_of_points.pop()
00247                         self.counter_points = self.counter_points - 1
00248                         self.erase(p.name)
00249                          
00250                 self.applyChanges()
00251                 
00252         ## @brief Callback called to delete all the waypoints
00253         def deleteAllPointsCB(self, feedback):
00254                 self.deleteAllPoints()
00255         
00256         ## @brief Callback called to save the current points
00257         def savePointsCB(self, feedback):
00258                 
00259                 try:
00260                         file_points = open(self.points_file_path, 'w')
00261                 except IOError, e:
00262                         rospy.logerr( 'agvs_path_marker::savePointsCB: File %s not found: %s'%(self.points_file_path, e))
00263                         return
00264                 
00265                 for i in self.list_of_points:
00266                         # line format = 'p1;p1->0.4;0.5;5.2;0.4' (ID, description, x, y, speed)
00267                         line = '%s;%s;%.3f;%.3f;%.3f\n'%(i.name, i.description, i.pose.position.x, i.pose.position.y, i.speed)
00268                         file_points.write(line) 
00269                 
00270                 rospy.loginfo('agvs_path_marker:savePointsCB: saved %d points'%(len(self.list_of_points)))
00271                 file_points.close()
00272                 
00273                 
00274         ## @brief Callback called to load previous saved points
00275         def loadPointsCB(self, feedback):
00276                 # Deletes all the loaded points
00277                 if len(self.list_of_points) > 0:
00278                         self.deleteAllPoints()
00279                 
00280                 try:
00281                         file_points = open(self.points_file_path, 'r')
00282                 except IOError, e:
00283                         rospy.logerr( 'agvs_path_marker::loadPointsCB: File %s not found: %s'%(self.points_file_path, e))
00284                         return
00285                 
00286                 num_of_loaded_points = 0
00287                 # Reads and extracts the information of every line
00288                 line = file_points.readline().replace('\n', '')
00289                 while line != '':
00290                         # line format = 'p1;p1->0.4;0.5;5.2;0.4'
00291                         a = line.split(';')
00292                         # a = ['p1', 'p1->0.4', '0.5', '0.4', '0.4'] // [ ID, DESCRIPTION, X, Y, SPEED]
00293                         if len(a) == 5:
00294                                 
00295                                 new_point = PointPath(self.frame_id, a[0], a[1], speed = float(a[4]))
00296                                 new_point.pose.position.x = float(a[2])
00297                                 new_point.pose.position.y = float(a[3])
00298                                 
00299                                 rospy.loginfo('agvs_path_marker::loadPointsCB: Loading point %s at position %.2lf, %.2lf. speed =  %.2lf'%(a[0], new_point.pose.position.x, new_point.pose.position.y, new_point.speed))
00300                                 
00301                                 self.list_of_points.append(new_point)
00302                                 self.insert(new_point, new_point.processFeedback)
00303                                 self.menu_handler.apply( self, a[0])
00304                                 self.applyChanges()
00305                                 self.counter_points = self.counter_points + 1
00306                                 num_of_loaded_points = num_of_loaded_points + 1
00307                         else:
00308                                 rospy.logerr('agvs_path_marker::loadPointsCB: Error processing line %s'%(line))         
00309                                 
00310                         
00311                         line = file_points.readline().replace('\n', '')
00312                 
00313                 file_points.close()
00314                 
00315                 rospy.loginfo('agvs_path_marker::loadPointsCB: Loaded %d points'%(num_of_loaded_points))        
00316                 
00317                 
00318         ## @brief Starts the route
00319         def startRouteCB(self, feedback):
00320                 goals = self.convertListOfPointPathIntoGoal()
00321                 print 'goals: %s'%(goals)
00322                 self.planner_client.goTo(goals)
00323                 return
00324         
00325         ## @brief Starts the route on the inverse direction
00326         def reverseRouteCB(self, feedback):
00327                 goals = self.convertListOfPointPathIntoGoal(inverse = True)
00328                 #print 'goals: %s'%(goals)
00329                 self.planner_client.goTo(goals)
00330                 return
00331                 
00332         ## @brief Stops the current route if it's started
00333         def stopRouteCB(self, feedback):
00334                 self.planner_client.cancel()
00335                 return
00336         
00337         ## @brief Starts the route (inverse order of waypoints)
00338         def convertListOfPointPathIntoGoal(self, inverse = False):
00339                 converted_list = []
00340                 if inverse:
00341                         for i in reversed(self.list_of_points):
00342                                 converted_list.append(goal(pose = Pose2D(i.pose.position.x, i.pose.position.y, 0.0), speed = i.speed)) # For now speed constant
00343                 else:
00344                         for i in self.list_of_points:
00345                                 #print 'convertListOfPointPathIntoGoal: %.2lf, %.2lf'%(i.pose.position.x, i.pose.position.y)
00346                                 converted_list.append(goal(pose = Pose2D(i.pose.position.x, i.pose.position.y, 0.0), speed = i.speed)) # For now speed constant
00347                 
00348                 return converted_list
00349         
00350         ## @brief Fake service to emulate the event start route
00351         def goService(self, param):
00352                 rospy.loginfo('%s::goService'%(rospy.get_name()))
00353                 
00354                 self.startRouteCB(None)
00355                 
00356                 return []
00357         
00358         ## @brief Fake service to emulate the event reverse route
00359         def goBackService(self, param):
00360                 rospy.loginfo('%s::goBackService'%(rospy.get_name()))
00361                 
00362                 self.reverseRouteCB(None)
00363                 
00364                 return []
00365                 
00366         ## @brief Fake service to emulate the event cancel route
00367         def cancelService(self, param):
00368                 rospy.loginfo('%s::cancelService'%(rospy.get_name()))
00369                 self.stopRouteCB(None)
00370                 
00371                 return []
00372                 
00373                 
00374 if __name__=="__main__":
00375         rospy.init_node("agvs_path_marker2")
00376         
00377         _name = rospy.get_name().replace('/','')
00378         
00379         arg_defaults = {
00380           'frame_id': '/map',
00381           'planner': 'purepursuit_planner'
00382         }
00383         
00384         args = {}
00385         
00386         for name in arg_defaults:
00387                 try:
00388                         if rospy.search_param(name): 
00389                                 args[name] = rospy.get_param('%s/%s'%(_name, name)) # Adding the name of the node, because the para has the namespace of the node
00390                         else:
00391                                 args[name] = arg_defaults[name]
00392                         #print name
00393                 except rospy.ROSException, e:
00394                         rospy.logerror('%s: %s'%(e, _name))
00395         
00396         server = PointPathManager(_name, frame_id = args['frame_id'], planner = args['planner'])
00397         
00398         rospy.spin()
00399 


purepursuit_planner
Author(s): Román Navarro
autogenerated on Thu Aug 27 2015 12:08:42