00001
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
00044 class PurepursuitClient():
00045
00046 def __init__(self, planner_name):
00047 self.planner_name = planner_name
00048
00049
00050 self.client = actionlib.SimpleActionClient(planner_name, GoToAction)
00051
00052
00053
00054 def goTo(self, goal_list):
00055
00056
00057 if self.client.wait_for_server(timeout = rospy.Duration(3.0) ):
00058
00059
00060
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
00071 def cancel(self):
00072 rospy.loginfo('PurepursuitClient: cancelling the goal')
00073 self.client.cancel_goal()
00074
00075
00076
00077
00078
00079
00080
00081
00082 def getState(self):
00083 return self.client.get_state()
00084
00085
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
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
00133 def processFeedback(self, feedback):
00134
00135 self.pose = feedback.pose
00136
00137
00138
00139
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
00149 self.menu_handler = MenuHandler()
00150 h_first_entry = self.menu_handler.insert( "Waypoints" )
00151
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)
00162 entry = self.menu_handler.insert( "Stop", parent=h_second_entry, callback=self.stopRouteCB)
00163 entry = self.menu_handler.insert( "Go back", parent=h_second_entry, callback=self.reverseRouteCB)
00164
00165
00166
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
00176 rp = rospkg.RosPack()
00177
00178 self.points_file_path = os.path.join(rp.get_path('purepursuit_planner'), 'scripts', 'waypoints.txt')
00179
00180
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
00187 def createNewPoint(self, speed = 0.2):
00188
00189
00190 new_point = PointPath(self.frame_id, 'p%d'%(self.counter_points), 'p%d->%.1f'%(self.counter_points, speed), speed = speed)
00191
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
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
00212
00213
00214 return
00215
00216
00217 def newPointCB(self, feedback):
00218
00219 self.createNewPoint()
00220
00221 def newPointCB_02(self, feedback):
00222
00223 self.createNewPoint(0.2)
00224
00225 def newPointCB_04(self, feedback):
00226
00227 self.createNewPoint(0.4)
00228
00229 def newPointCB_06(self, feedback):
00230
00231 self.createNewPoint(0.6)
00232
00233
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
00242
00243
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
00253 def deleteAllPointsCB(self, feedback):
00254 self.deleteAllPoints()
00255
00256
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
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
00275 def loadPointsCB(self, feedback):
00276
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
00288 line = file_points.readline().replace('\n', '')
00289 while line != '':
00290
00291 a = line.split(';')
00292
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
00319 def startRouteCB(self, feedback):
00320 goals = self.convertListOfPointPathIntoGoal()
00321 print 'goals: %s'%(goals)
00322 self.planner_client.goTo(goals)
00323 return
00324
00325
00326 def reverseRouteCB(self, feedback):
00327 goals = self.convertListOfPointPathIntoGoal(inverse = True)
00328
00329 self.planner_client.goTo(goals)
00330 return
00331
00332
00333 def stopRouteCB(self, feedback):
00334 self.planner_client.cancel()
00335 return
00336
00337
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))
00343 else:
00344 for i in self.list_of_points:
00345
00346 converted_list.append(goal(pose = Pose2D(i.pose.position.x, i.pose.position.y, 0.0), speed = i.speed))
00347
00348 return converted_list
00349
00350
00351 def goService(self, param):
00352 rospy.loginfo('%s::goService'%(rospy.get_name()))
00353
00354 self.startRouteCB(None)
00355
00356 return []
00357
00358
00359 def goBackService(self, param):
00360 rospy.loginfo('%s::goBackService'%(rospy.get_name()))
00361
00362 self.reverseRouteCB(None)
00363
00364 return []
00365
00366
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))
00390 else:
00391 args[name] = arg_defaults[name]
00392
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