simple_script_server.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #
00003 # Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
00004 #
00005 # Licensed under the Apache License, Version 2.0 (the "License");
00006 # you may not use this file except in compliance with the License.
00007 # You may obtain a copy of the License at
00008 #
00009 #       http://www.apache.org/licenses/LICENSE-2.0
00010 #
00011 # Unless required by applicable law or agreed to in writing, software
00012 # distributed under the License is distributed on an "AS IS" BASIS,
00013 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014 # See the License for the specific language governing permissions and
00015 # limitations under the License.
00016 
00017 
00018 import time
00019 import datetime
00020 import os
00021 import sys
00022 import types
00023 import thread
00024 import commands
00025 import math
00026 import threading
00027 
00028 # graph includes
00029 import pygraphviz as pgv
00030 
00031 # ROS imports
00032 import rospy
00033 import actionlib
00034 
00035 # msg imports
00036 from std_msgs.msg import String,ColorRGBA
00037 from std_srvs.srv import Trigger
00038 from sensor_msgs.msg import JointState
00039 from geometry_msgs.msg import *
00040 from trajectory_msgs.msg import *
00041 from move_base_msgs.msg import *
00042 from control_msgs.msg import *
00043 from tf.transformations import *
00044 
00045 # care-o-bot includes
00046 from cob_actions.msg import SetStringAction, SetStringGoal
00047 from cob_sound.msg import *
00048 from cob_script_server.msg import *
00049 from cob_light.msg import LightMode, LightModes, SetLightModeGoal, SetLightModeAction
00050 from cob_mimic.msg import SetMimicGoal, SetMimicAction
00051 from actionlib.msg import TestAction, TestGoal
00052 from actionlib import GoalStatus
00053 
00054 graph=""
00055 graph_wait_list=[]
00056 ah_counter = 0
00057 graph = pgv.AGraph()
00058 graph.node_attr['shape']='box'
00059 last_node = "Start"
00060 
00061 ## Script class from which all script inherit.
00062 #
00063 # Implements basic functionalities for all scripts.
00064 class script():
00065         def __init__(self):
00066                 # use filename as nodename
00067                 filename = os.path.basename(sys.argv[0])
00068                 self.basename, extension = os.path.splitext(filename)
00069                 rospy.init_node(self.basename)
00070                 self.graph_pub = rospy.Publisher("/script_server/graph", String, queue_size=1)
00071 
00072         ## Dummy function for initialization
00073         def Initialize(self):
00074                 pass
00075 
00076         ## Dummy function for main run function
00077         def Run(self):
00078                 pass
00079 
00080         ## Function to start the script
00081         #
00082         # First does a simulated turn and then calls Initialize() and Run().
00083         def Start(self):
00084                 self.Parse()
00085                 global ah_counter
00086                 ah_counter = 0
00087                 self.sss = simple_script_server()
00088                 rospy.loginfo("Starting <<%s>> script...",self.basename)
00089                 self.Initialize()
00090                 self.Run()
00091                 # wait until last threaded action finishes
00092                 rospy.loginfo("Wait for script to finish...")
00093                 while ah_counter != 0:
00094                         rospy.sleep(1)
00095                 rospy.loginfo("...script finished.")
00096 
00097         ## Function to generate graph view of script.
00098         #
00099         # Starts the script in simulation mode and calls Initialize() and Run().
00100         def Parse(self):
00101                 rospy.loginfo("Start parsing...")
00102                 global graph
00103                 # run script in simulation mode
00104                 self.sss = simple_script_server(parse=True)
00105                 self.Initialize()
00106                 self.Run()
00107 
00108                 # save graph on parameter server for further processing
00109                 #self.graph = graph
00110                 rospy.set_param("/script_server/graph", graph.string())
00111                 self.graph_pub.publish(graph.string())
00112                 rospy.loginfo("...parsing finished")
00113                 return graph.string()
00114 
00115 ## Simple script server class.
00116 #
00117 # Implements the python interface for the script server.
00118 class simple_script_server:
00119         ## Initializes simple_script_server class.
00120         #
00121         # \param parse Defines wether to run script in simulation for graph generation or not
00122         def __init__(self, parse=False):
00123                 global graph
00124                 self.ns_global_prefix = "/script_server"
00125                 self.wav_path = ""
00126                 self.parse = parse
00127                 rospy.sleep(1) # we have to wait here until publishers are ready, don't ask why
00128 
00129         #------------------- Init section -------------------#
00130         ## Initializes different components.
00131         #
00132         # Based on the component, the corresponding init service will be called.
00133         #
00134         # \param component_name Name of the component.
00135         def init(self,component_name,blocking=True):
00136                 return self.trigger(component_name,"init",blocking=blocking)
00137 
00138         ## Stops different components.
00139         #
00140         # Based on the component, the corresponding stop service will be called.
00141         #
00142         # \param component_name Name of the component.
00143         def stop(self,component_name,mode="omni",blocking=True):
00144                 ah = action_handle("stop", component_name, "", False, self.parse)
00145                 if(self.parse):
00146                         return ah
00147                 else:
00148                         ah.set_active(mode="service")
00149 
00150                 rospy.loginfo("<<stop>> <<%s>>", component_name)
00151                 if component_name == "base":
00152                         if(mode == None or mode == ""):
00153                                 action_server_name = "/move_base"
00154                         elif(mode == "omni"):
00155                                 action_server_name = "/move_base"
00156                         elif(mode == "diff"):
00157                                 action_server_name = "/move_base_diff"
00158                         elif(mode == "linear"):
00159                                 action_server_name = "/move_base_linear"
00160                         else:
00161                                 message = "Given navigation mode " + mode + " for " + component_name + " is not valid, aborting..."
00162                                 rospy.logerr(message)
00163                                 ah.set_failed(33, message)
00164                                 return ah
00165                         client = actionlib.SimpleActionClient(action_server_name, MoveBaseAction)
00166                 else:
00167                         parameter_name = self.ns_global_prefix + "/" + component_name + "/action_name"
00168                         if not rospy.has_param(parameter_name):
00169                                 message = "Parameter " + parameter_name + " does not exist on ROS Parameter Server, aborting..."
00170                                 rospy.logerr(message)
00171                                 ah.set_failed(2, message)
00172                                 return ah
00173                         action_server_name = rospy.get_param(parameter_name)
00174                         client = actionlib.SimpleActionClient(action_server_name, FollowJointTrajectoryAction)
00175 
00176                 # call action server
00177                 rospy.logdebug("calling %s action server",action_server_name)
00178 
00179                 if blocking:
00180                         # trying to connect to server
00181                         rospy.logdebug("waiting for %s action server to start",action_server_name)
00182                         if not client.wait_for_server(rospy.Duration(1)):
00183                                 # error: server did not respond
00184                                 message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
00185                                 rospy.logerr(message)
00186                                 ah.set_failed(4, message)
00187                                 return ah
00188                         else:
00189                                 rospy.logdebug("%s action server ready",action_server_name)
00190 
00191                 # cancel all goals
00192                 client.cancel_all_goals()
00193                 ah.set_succeeded() # full success
00194                 return ah
00195 
00196         ## Recovers different components.
00197         #
00198         # Based on the component, the corresponding recover service will be called.
00199         #
00200         # \param component_name Name of the component.
00201         def recover(self,component_name,blocking=True):
00202                 return self.trigger(component_name,"recover",blocking=blocking)
00203 
00204         ## Halts different components.
00205         #
00206         # Based on the component, the corresponding halt service will be called.
00207         #
00208         # \param component_name Name of the component.
00209         def halt(self,component_name,blocking=True):
00210                 return self.trigger(component_name,"halt",blocking=blocking)
00211 
00212         ## Deals with all kind of trigger services for different components.
00213         #
00214         # Based on the component and service name, the corresponding trigger service will be called.
00215         #
00216         # \param component_name Name of the component.
00217         # \param service_name Name of the trigger service.
00218         # \param blocking Service calls are always blocking. The parameter is only provided for compatibility with other functions.
00219         def trigger(self,component_name,service_name,blocking=True):
00220                 ah = action_handle(service_name, component_name, "", blocking, self.parse)
00221                 if(self.parse):
00222                         return ah
00223                 else:
00224                         ah.set_active(mode="service")
00225 
00226                 rospy.loginfo("<<%s>> <<%s>>", service_name, component_name)
00227                 parameter_name = self.ns_global_prefix + "/" + component_name + "/service_ns"
00228                 if not rospy.has_param(parameter_name):
00229                         message = "Parameter " + parameter_name + " does not exist on ROS Parameter Server, aborting..."
00230                         rospy.logerr(message)
00231                         ah.set_failed(2, message)
00232                         return ah
00233                 service_ns_name = rospy.get_param(parameter_name)
00234                 service_full_name = service_ns_name + "/" + service_name
00235 
00236                 if blocking:
00237                         # check if service is available
00238                         try:
00239                                 rospy.wait_for_service(service_full_name,1)
00240                         except rospy.ROSException, e:
00241                                 error_message = "%s"%e
00242                                 message = "...service <<" + service_name + ">> of <<" + component_name + ">> not available,\n error: " + error_message
00243                                 rospy.logerr(message)
00244                                 ah.set_failed(4, message)
00245                                 return ah
00246 
00247                 # check if service is callable
00248                 try:
00249                         trigger = rospy.ServiceProxy(service_full_name,Trigger)
00250                         if blocking:
00251                                 rospy.loginfo("Wait for <<%s>> to <<%s>>...", component_name, service_name)
00252                                 resp = trigger()
00253                         else:
00254                                 thread.start_new_thread(trigger,())
00255                 except rospy.ServiceException, e:
00256                         error_message = "%s"%e
00257                         message = "...calling <<" + service_name + ">> of <<" + component_name + ">> not successfull,\n error: " + error_message
00258                         rospy.logerr(message)
00259                         ah.set_failed(10, message)
00260                         return ah
00261 
00262                 if blocking:
00263                         # evaluate sevice response
00264                         if not resp.success:
00265                                 message = "...response of <<" + service_name + ">> of <<" + component_name + ">> not successfull,\n error: " + resp.message
00266                                 rospy.logerr(message)
00267                                 ah.set_failed(10, message)
00268                                 return ah
00269 
00270                         # full success
00271                         rospy.loginfo("...<<%s>> is <<%s>>", component_name, service_name)
00272                         ah.set_succeeded() # full success
00273                 return ah
00274 
00275         ## Allows to trigger actions of the type actionlib/TestAction
00276         #
00277         # Based on the component and action name, the corresponding ActionServer will be called.
00278         #
00279         # \param component_name Name of the component.
00280         # \param action_name Name of the action.
00281         # \param blocking Whether to wait for the Action to return.
00282         def trigger_action(self,component_name,action_name,blocking=True):
00283                 ah = action_handle(action_name, component_name, "", blocking, self.parse)
00284                 if(self.parse):
00285                         return ah
00286                 else:
00287                         ah.set_active(mode="action")
00288 
00289                 rospy.loginfo("<<%s>> <<%s>>", action_name, component_name)
00290                 #parameter_name = self.ns_global_prefix + "/" + component_name + "/service_ns"
00291                 #if not rospy.has_param(parameter_name):
00292                         #message = "Parameter " + parameter_name + " does not exist on ROS Parameter Server, aborting..."
00293                         #rospy.logerr(message)
00294                         #ah.set_failed(2, message)
00295                         #return ah
00296                 #service_ns_name = rospy.get_param(parameter_name)
00297                 action_full_name = "/" + component_name + "/" + action_name
00298                 action_client = actionlib.SimpleActionClient(action_full_name, TestAction)
00299 
00300                 if blocking:
00301                         # check if action is available
00302                         if not action_client.wait_for_server(rospy.Duration(1)):
00303                                 message = "ActionServer %s is not running"%action_full_name
00304                                 rospy.logerr(message)
00305                                 ah.set_failed(4, message)
00306                                 return ah
00307 
00308                 # call the action
00309                 if blocking:
00310                         rospy.loginfo("Wait for <<%s>> to <<%s>>...", component_name, action_name)
00311                         goal_state = action_client.send_goal_and_wait(TestGoal())
00312                         if not (action_client.get_state() == GoalStatus.SUCCEEDED):
00313                                 message = "...state of <<" + action_name + ">> of <<" + component_name + ">> : " + GoalStatus.to_string(action_client.get_state())
00314                                 rospy.logerr(message)
00315                                 ah.set_failed(10, message)
00316                                 return ah
00317                 else:
00318                         action_client.send_goal(TestGoal())
00319 
00320                 # full success
00321                 rospy.loginfo("...<<%s>> is <<%s>>", component_name, action_name)
00322                 ah.set_succeeded() # full success
00323                 return ah
00324 
00325 
00326         ## Allows to trigger actions of the type cob_actions/SetString
00327         #
00328         # Based on the component and action name, the corresponding ActionServer will be called.
00329         #
00330         # \param component_name Name of the component (namespace of the action).
00331         # \param data The data to be send in the ActionGoal.
00332         # \param blocking Whether to wait for the Action to return.
00333         def string_action(self,component_name, data, blocking):
00334                 action_name = "set_string"
00335                 ah = action_handle(action_name, component_name, "", blocking, self.parse)
00336                 if(self.parse):
00337                         return ah
00338                 else:
00339                         ah.set_active(mode="action")
00340 
00341                 rospy.loginfo("<<%s>> <<%s>>", action_name, component_name)
00342                 action_full_name = "/" + component_name + "/" + action_name
00343                 action_client = actionlib.SimpleActionClient(action_full_name, SetStringAction)
00344 
00345                 if blocking:
00346                         # check if action is available
00347                         if not action_client.wait_for_server(rospy.Duration(1)):
00348                                 message = "ActionServer %s is not running"%action_full_name
00349                                 rospy.logerr(message)
00350                                 ah.set_failed(4, message)
00351                                 return ah
00352 
00353                 # call the action
00354                 goal = SetStringGoal()
00355                 goal.data = data
00356                 if blocking:
00357                         rospy.loginfo("Wait for <<%s>> to <<%s>>...", component_name, action_name)
00358                         goal_state = action_client.send_goal_and_wait(goal)
00359                         if not (action_client.get_state() == GoalStatus.SUCCEEDED):
00360                                 message = "...state of <<" + action_name + ">> of <<" + component_name + ">> : " + GoalStatus.to_string(action_client.get_state())
00361                                 rospy.logerr(message)
00362                                 ah.set_failed(10, message)
00363                                 return ah
00364                 else:
00365                         action_client.send_goal(goal)
00366 
00367                 # full success
00368                 rospy.loginfo("...<<%s>> is <<%s>>", component_name, action_name)
00369                 ah.set_succeeded() # full success
00370                 return ah
00371 
00372 
00373 #------------------- Move section -------------------#
00374         ## Deals with all kind of movements for different components.
00375         #
00376         # Based on the component, the corresponding move functions will be called.
00377         #
00378         # \param component_name Name of the component.
00379         # \param parameter_name Name of the parameter on the ROS parameter server.
00380         # \param blocking Bool value to specify blocking behaviour.
00381         def move(self,component_name,parameter_name,blocking=True, mode=None):
00382                 if component_name == "base":
00383                         return self.move_base(component_name,parameter_name,blocking, mode)
00384                 else:
00385                         return self.move_traj(component_name,parameter_name,blocking)
00386 
00387         ## Deals with movements of the base.
00388         #
00389         # A target will be sent to the actionlib interface of the move_base node.
00390         #
00391         # \param component_name Name of the component.
00392         # \param parameter_name Name of the parameter on the ROS parameter server.
00393         # \param blocking Bool value to specify blocking behaviour.
00394         def move_base(self,component_name,parameter_name,blocking, mode):
00395                 ah = action_handle("move", component_name, parameter_name, blocking, self.parse)
00396                 if(self.parse):
00397                         return ah
00398                 else:
00399                         ah.set_active()
00400 
00401                 if(mode == None or mode == ""):
00402                         rospy.loginfo("Move <<%s>> to <<%s>>",component_name,parameter_name)
00403                 else:
00404                         rospy.loginfo("Move <<%s>> to <<%s>> using <<%s>> mode",component_name,parameter_name,mode)
00405 
00406                 # get joint values from parameter server
00407                 if type(parameter_name) is str:
00408                         full_parameter_name = self.ns_global_prefix + "/" + component_name + "/" + parameter_name
00409                         if not rospy.has_param(full_parameter_name):
00410                                 message = "Parameter " + full_parameter_name + " does not exist on ROS Parameter Server, aborting..."
00411                                 rospy.logerr(message)
00412                                 ah.set_failed(2, message)
00413                                 return ah
00414                         param = rospy.get_param(self.ns_global_prefix + "/" + component_name + "/" + parameter_name)
00415                 else:
00416                         param = parameter_name
00417 
00418                 # check trajectory parameters
00419                 if not type(param) is list: # check outer list
00420                         message = "No valid parameter for " + component_name + ": not a list, aborting..."
00421                         rospy.logerr(message)
00422                         print "parameter is:",param
00423                         ah.set_failed(3, message)
00424                         return ah
00425                 else:
00426                         #print i,"type1 = ", type(i)
00427                         DOF = 3
00428                         if not len(param) == DOF: # check dimension
00429                                 message = "No valid parameter for " + component_name + ": dimension should be " + str(DOF) + " but is " + str(len(param)) + ", aborting..."
00430                                 rospy.logerr(message)
00431                                 print "parameter is:",param
00432                                 ah.set_failed(3, message)
00433                                 return ah
00434                         else:
00435                                 for i in param:
00436                                         #print i,"type2 = ", type(i)
00437                                         if not ((type(i) is float) or (type(i) is int)): # check type
00438                                                 #print type(i)
00439                                                 message = "No valid parameter for " + component_name + ": not a list of float or int, aborting..."
00440                                                 rospy.logerr(message)
00441                                                 print "parameter is:",param
00442                                                 ah.set_failed(3, message)
00443                                                 return ah
00444                                         else:
00445                                                 rospy.logdebug("accepted parameter %f for %s",i,component_name)
00446 
00447                 # convert to pose message
00448                 pose = PoseStamped()
00449                 pose.header.stamp = rospy.Time.now()
00450                 pose.header.frame_id = "/map"
00451                 pose.pose.position.x = param[0]
00452                 pose.pose.position.y = param[1]
00453                 pose.pose.position.z = 0.0
00454                 q = quaternion_from_euler(0, 0, param[2])
00455                 pose.pose.orientation.x = q[0]
00456                 pose.pose.orientation.y = q[1]
00457                 pose.pose.orientation.z = q[2]
00458                 pose.pose.orientation.w = q[3]
00459 
00460                 # call action server
00461                 if(mode == None or mode == ""):
00462                         action_server_name = "/move_base"
00463                 elif(mode == "omni"):
00464                         action_server_name = "/move_base"
00465                 elif(mode == "diff"):
00466                         action_server_name = "/move_base_diff"
00467                 elif(mode == "linear"):
00468                         action_server_name = "/move_base_linear"
00469                 else:
00470                         message = "Given navigation mode " + mode + " for " + component_name + " is not valid, aborting..."
00471                         rospy.logerr(message)
00472                         ah.set_failed(33, message)
00473                         return ah
00474 
00475                 rospy.logdebug("calling %s action server",action_server_name)
00476                 client = actionlib.SimpleActionClient(action_server_name, MoveBaseAction)
00477                 # trying to connect to server
00478                 rospy.logdebug("waiting for %s action server to start",action_server_name)
00479                 if not client.wait_for_server(rospy.Duration(1)):
00480                         # error: server did not respond
00481                         message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
00482                         rospy.logerr(message)
00483                         ah.set_failed(4, message)
00484                         return ah
00485                 else:
00486                         rospy.logdebug("%s action server ready",action_server_name)
00487 
00488                 # sending goal
00489                 client_goal = MoveBaseGoal()
00490                 client_goal.target_pose = pose
00491                 #print client_goal
00492                 client.send_goal(client_goal)
00493                 ah.set_client(client)
00494                 ah.wait_inside()
00495                 return ah
00496 
00497         ## Parse and compose trajectory message
00498         def compose_trajectory(self, component_name, parameter_name):
00499                 # get joint_names from parameter server
00500                 param_string = self.ns_global_prefix + "/" + component_name + "/joint_names"
00501                 if not rospy.has_param(param_string):
00502                         rospy.logerr("parameter %s does not exist on ROS Parameter Server, aborting...",param_string)
00503                         return (JointTrajectory(), 2)
00504                 joint_names = rospy.get_param(param_string)
00505 
00506                 # check joint_names parameter
00507                 if not type(joint_names) is list: # check list
00508                         rospy.logerr("no valid joint_names for %s: not a list, aborting...",component_name)
00509                         print "joint_names are:",joint_names
00510                         return (JointTrajectory(), 3)
00511                 else:
00512                         for i in joint_names:
00513                                 #print i,"type1 = ", type(i)
00514                                 if not type(i) is str: # check string
00515                                         rospy.logerr("no valid joint_names for %s: not a list of strings, aborting...",component_name)
00516                                         print "joint_names are:",param
00517                                         return (JointTrajectory(), 3)
00518                                 else:
00519                                         rospy.logdebug("accepted joint_names for component %s",component_name)
00520 
00521                 # get joint values from parameter server
00522                 if type(parameter_name) is str:
00523                         full_parameter_name = self.ns_global_prefix + "/" + component_name + "/" + parameter_name
00524                         if not rospy.has_param(full_parameter_name):
00525                                 rospy.logerr("parameter %s does not exist on ROS Parameter Server, aborting...",full_parameter_name)
00526                                 return (JointTrajectory(), 2)
00527                         param = rospy.get_param(full_parameter_name)
00528                 else:
00529                         param = parameter_name
00530 
00531                 # check trajectory parameters
00532                 if not type(param) is list: # check outer list
00533                                 rospy.logerr("no valid parameter for %s: not a list, aborting...",component_name)
00534                                 print "parameter is:",param
00535                                 return (JointTrajectory(), 3)
00536 
00537                 traj = []
00538                 for point in param:
00539                         #print point,"type1 = ", type(point)
00540                         if type(point) is str:
00541                                 full_parameter_name = self.ns_global_prefix + "/" + component_name + "/" + point
00542                                 if not rospy.has_param(full_parameter_name):
00543                                         rospy.logerr("parameter %s does not exist on ROS Parameter Server, aborting...",full_parameter_name)
00544                                         return (JointTrajectory(), 2)
00545                                 point = rospy.get_param(full_parameter_name)
00546                                 point = point[0] # \todo TODO: hack because only first point is used, no support for trajectories inside trajectories
00547                                 #print point
00548                         elif type(point) is list:
00549                                 rospy.logdebug("point is a list")
00550                         else:
00551                                 rospy.logerr("no valid parameter for %s: not a list of lists or strings, aborting...",component_name)
00552                                 print "parameter is:",param
00553                                 return (JointTrajectory(), 3)
00554 
00555                         # here: point should be list of floats/ints
00556                         #print point
00557                         if not len(point) == len(joint_names): # check dimension
00558                                 rospy.logerr("no valid parameter for %s: dimension should be %d and is %d, aborting...",component_name,len(joint_names),len(point))
00559                                 print "parameter is:",param
00560                                 return (JointTrajectory(), 3)
00561 
00562                         for value in point:
00563                                 #print value,"type2 = ", type(value)
00564                                 if not ((type(value) is float) or (type(value) is int)): # check type
00565                                         #print type(value)
00566                                         rospy.logerr("no valid parameter for %s: not a list of float or int, aborting...",component_name)
00567                                         print "parameter is:",param
00568                                         return (JointTrajectory(), 3)
00569 
00570                                 rospy.logdebug("accepted value %f for %s",value,component_name)
00571                         traj.append(point)
00572 
00573                 rospy.logdebug("accepted trajectory for %s",component_name)
00574 
00575                 # get current pos
00576                 timeout = 3.0
00577                 try:
00578                         start_pos = rospy.wait_for_message("/" + component_name + "/joint_states", JointState, timeout = timeout).position
00579                 except rospy.ROSException as e:
00580                         rospy.logwarn("no joint states received from %s within timeout of %ssec. using default point time of 8sec.", component_name, str(timeout))
00581                         start_pos = []
00582 
00583                 # convert to ROS trajectory message
00584                 traj_msg = JointTrajectory()
00585                 # if no timestamp is set in header, this means that the trajectory starts "now"
00586                 traj_msg.joint_names = joint_names
00587                 point_nr = 0
00588                 traj_time = 0
00589 
00590                 param_string = self.ns_global_prefix + "/" + component_name + "/default_vel"
00591                 if not rospy.has_param(param_string):
00592                         default_vel = 0.1 # rad/s
00593                         rospy.logwarn("parameter %s does not exist on ROS Parameter Server, using default of %f [rad/sec].",param_string,default_vel)
00594                 else:
00595                         default_vel = rospy.get_param(param_string)
00596 
00597                 param_string = self.ns_global_prefix + "/" + component_name + "/default_acc"
00598                 if not rospy.has_param(param_string):
00599                         default_acc = 1.0 # rad^2/s
00600                         rospy.logwarn("parameter %s does not exist on ROS Parameter Server, using default of %f [rad^2/sec].",param_string,default_acc)
00601                 else:
00602                         default_acc = rospy.get_param(param_string)
00603 
00604                 for point in traj:
00605                         point_nr = point_nr + 1
00606                         point_msg = JointTrajectoryPoint()
00607                         point_msg.positions = point
00608 
00609                         # set zero velocities for last trajectory point only
00610                         #if point_nr == len(traj):
00611                         #       point_msg.velocities = [0]*len(joint_names)
00612 
00613                         # set zero velocity and accelerations for all trajectory points
00614                         point_msg.velocities = [0]*len(joint_names)
00615                         point_msg.accelerations = [0]*len(joint_names)
00616 
00617                         # use hardcoded point_time if no start_pos available
00618                         if start_pos != []:
00619                                 point_time = self.calculate_point_time(component_name, start_pos, point, default_vel, default_acc)
00620                         else:
00621                                 point_time = 8*point_nr
00622 
00623                         start_pos = point
00624                         point_msg.time_from_start=rospy.Duration(point_time + traj_time)
00625                         traj_time += point_time
00626                         traj_msg.points.append(point_msg)
00627                 return (traj_msg, 0)
00628 
00629         def calculate_point_time(self, component_name, start_pos, end_pos, default_vel, default_acc):
00630                 try:
00631                         d_max = max(list(abs(numpy.array(start_pos) - numpy.array(end_pos))))
00632                         t1 = default_vel / default_acc
00633                         s1 = default_acc / 2 * t1**2
00634                         if (2 * s1 < d_max):
00635                                 # with constant velocity phase (acc, const vel, dec)
00636                                 # 1st phase: accelerate from v=0 to v=default_vel with a=default_acc in t=t1
00637                                 # 2nd phase: constante velocity with v=default_vel and t=t2
00638                                 # 3rd phase: decceleration (analog to 1st phase)
00639                                 s2 = d_max - 2 * s1
00640                                 t2 = s2 / default_vel
00641                                 t = 2 * t1 + t2
00642                         else:
00643                                 # without constant velocity phase (only acc and dec)
00644                                 # 1st phase: accelerate from v=0 to v=default_vel with a=default_acc in t=t1
00645                                 # 2nd phase: missing because distance is to short (we already reached the distance with the acc and dec phase)
00646                                 # 3rd phase: decceleration (analog to 1st phase)
00647                                 t = math.sqrt(d_max / default_acc)
00648                         point_time = max(t, 0.4)        # use minimal point_time
00649                 except ValueError as e:
00650                         print "Value Error", e
00651                         print "Likely due to mimic joints. Using default point_time: 3.0 [sec]"
00652                         point_time = 3.0        # use default point_time
00653                 return point_time
00654 
00655         ## Deals with all kind of trajectory movements for different components.
00656         #
00657         # A trajectory will be sent to the actionlib interface of the corresponding component.
00658         #
00659         # \param component_name Name of the component.
00660         # \param parameter_name Name of the parameter on the ROS parameter server.
00661         # \param blocking Bool value to specify blocking behaviour.
00662         def move_traj(self,component_name,parameter_name,blocking):
00663                 ah = action_handle("move", component_name, parameter_name, blocking, self.parse)
00664                 if(self.parse):
00665                         return ah
00666                 else:
00667                         ah.set_active()
00668 
00669                 rospy.loginfo("Move <<%s>> to <<%s>>",component_name,parameter_name)
00670                 (traj_msg, error_code) = self.compose_trajectory(component_name, parameter_name)
00671                 if error_code != 0:
00672                         message = "Composing the trajectory failed with error: " + str(error_code)
00673                         ah.set_failed(error_code, message)
00674                         return ah
00675 
00676                 # call action server
00677                 parameter_name = self.ns_global_prefix + "/" + component_name + "/action_name"
00678                 if not rospy.has_param(parameter_name):
00679                         message = "Parameter " + parameter_name + " does not exist on ROS Parameter Server, aborting..."
00680                         rospy.logerr(message)
00681                         ah.set_failed(2, message)
00682                         return ah
00683                 action_server_name = rospy.get_param(parameter_name)
00684                 rospy.logdebug("calling %s action server",action_server_name)
00685                 client = actionlib.SimpleActionClient(action_server_name, FollowJointTrajectoryAction)
00686                 # trying to connect to server
00687                 rospy.logdebug("waiting for %s action server to start",action_server_name)
00688                 if not client.wait_for_server(rospy.Duration(1)):
00689                         # error: server did not respond
00690                         message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
00691                         rospy.logerr(message)
00692                         ah.set_failed(4, message)
00693                         return ah
00694                 else:
00695                         rospy.logdebug("%s action server ready",action_server_name)
00696 
00697                 # sending goal
00698                 client_goal = FollowJointTrajectoryGoal()
00699                 client_goal.trajectory = traj_msg
00700                 #print client_goal
00701                 client.send_goal(client_goal)
00702                 ah.set_client(client)
00703                 ah.wait_inside()
00704                 return ah
00705 
00706         ## Relative movement of the base
00707         #
00708         # \param component_name Name of component; here always "base".
00709         # \param parameter_name List of length 3: (item 1 & 2) relative x and y translation [m]; (item 3) relative rotation about z axis [rad].
00710         # \param blocking Bool value to specify blocking behaviour.
00711         #
00712         # # throws error code 3 in case of invalid parameter_name vector
00713         def move_base_rel(self, component_name, parameter_name=[0,0,0], blocking=True):
00714                 ah = action_handle("move_base_rel", component_name, parameter_name, blocking, self.parse)
00715                 if(self.parse):
00716                         return ah
00717                 else:
00718                         ah.set_active(mode="topic")
00719 
00720                 parameter_topic_name = self.ns_global_prefix + "/" + component_name + "/topic_name"
00721                 if not rospy.has_param(parameter_topic_name):
00722                         message = "Parameter " + parameter_topic_name + " does not exist on ROS Parameter Server, aborting..."
00723                         rospy.logerr(message)
00724                         ah.set_failed(3, message)
00725                         return ah
00726                 topic_name = rospy.get_param(parameter_topic_name)
00727                 rospy.loginfo("Move base relatively by <<%s>>", parameter_name)
00728 
00729                 # step 0: check validity of parameters:
00730                 if not len(parameter_name) == 3 or not isinstance(parameter_name[0], (int, float)) or not isinstance(parameter_name[1], (int, float)) or not isinstance(parameter_name[2], (int, float)):
00731                         message = "Parameter " + parameter_name + " not formated correctly (non-numeric list), aborting move_base_rel"
00732                         rospy.logerr(message)
00733                         print("parameter_name must be numeric list of length 3; (relative x and y transl [m], relative rotation [rad])")
00734                         ah.set_failed(3, message)
00735                         return ah
00736                 max_rel_trans_step = 1.0 # [m]
00737                 max_rel_rot_step = math.pi/2 # [rad]
00738                 if math.sqrt(parameter_name[0]**2 + parameter_name[1]**2) > max_rel_trans_step:
00739                         message = "Parameter " + str(parameter_name) + " exceeds maximal relative translation step (" + str(max_rel_trans_step) + "), aborting move_base_rel"
00740                         rospy.logerr(message)
00741                         ah.set_failed(3, message)
00742                         return(ah)
00743                 if abs(parameter_name[2]) > max_rel_rot_step:
00744                         message = "Parameter " + str(parameter_name) + " exceeds maximal relative rotation step (" + str(max_rel_rot_step) + "), aborting move_base_rel"
00745                         rospy.logerr(message)
00746                         ah.set_failed(3, message)
00747                         return(ah)
00748 
00749                 # step 1: determine duration of motion so that upper thresholds for both translational as well as rotational velocity are not exceeded
00750                 max_trans_vel = 0.05 # [m/s]
00751                 max_rot_vel = 0.2 # [rad/s]
00752                 duration_trans_sec = math.sqrt(parameter_name[0]**2 + parameter_name[1]**2) / max_trans_vel
00753                 duration_rot_sec = abs(parameter_name[2] / max_rot_vel)
00754                 duration_sec = max(duration_trans_sec, duration_rot_sec)
00755                 duration_ros = rospy.Duration.from_sec(duration_sec) # duration of motion in ROS time
00756 
00757                 # step 2: determine actual velocities based on calculated duration
00758                 x_vel = parameter_name[0] / duration_sec
00759                 y_vel = parameter_name[1] / duration_sec
00760                 rot_vel = parameter_name[2] / duration_sec
00761 
00762                 # step 3: send constant velocity command to base_controller for the calculated duration of motion
00763                 pub = rospy.Publisher(topic_name, Twist, queue_size=1)
00764                 twist = Twist()
00765                 twist.linear.x = x_vel
00766                 twist.linear.y = y_vel
00767                 twist.angular.z = rot_vel
00768                 end_time = rospy.Time.now() + duration_ros
00769 
00770                 if blocking:
00771                         rospy.loginfo("Wait for <<%s>> to finish move_base_rel...", component_name)
00772                         self.publish_twist(pub, twist, end_time)
00773                 else:
00774                         thread.start_new_thread(self.publish_twist,(pub, twist, end_time))
00775 
00776                 ah.set_succeeded()
00777                 return ah
00778 
00779         def publish_twist(self, pub, twist, end_time):
00780                 r = rospy.Rate(10) # send velocity commands at 10 Hz
00781                 while not rospy.is_shutdown() and rospy.Time.now() < end_time:
00782                         pub.publish(twist)
00783                         r.sleep()
00784 
00785 #------------------- LED section -------------------#
00786         ## Set the color of the cob_light component.
00787         #
00788         # The color is given by a parameter on the parameter server.
00789         #
00790         # \param parameter_name Name of the parameter on the parameter server which holds the rgb values.
00791 
00792         def compose_color(self,component_name,parameter_name):
00793                 # get joint values from parameter server
00794                 if type(parameter_name) is str:
00795                         full_parameter_name = self.ns_global_prefix + "/" + component_name + "/" + parameter_name
00796                         if not rospy.has_param(full_parameter_name):
00797                                 rospy.logerr("parameter %s does not exist on ROS Parameter Server, aborting...",full_parameter_name)
00798                                 return 2, None
00799                         param = rospy.get_param(full_parameter_name)
00800                 else:
00801                         param = parameter_name
00802 
00803                 # check color parameters
00804                 if not type(param) is list: # check outer list
00805                         rospy.logerr("no valid parameter for light: not a list, aborting...")
00806                         print "parameter is:",param
00807                         return 3, None
00808                 else:
00809                         if not len(param) == 4: # check dimension
00810                                 rospy.logerr("no valid parameter for light: dimension should be 4 (r,g,b,a) and is %d, aborting...",len(param))
00811                                 print "parameter is:",param
00812                                 return 3, None
00813                         else:
00814                                 for i in param:
00815                                         #print i,"type1 = ", type(i)
00816                                         if not ((type(i) is float) or (type(i) is int)): # check type
00817                                                 #print type(i)
00818                                                 rospy.logerr("no valid parameter for light: not a list of float or int, aborting...")
00819                                                 print "parameter is:",param
00820                                                 return 3, None
00821                                         else:
00822                                                 rospy.logdebug("accepted parameter %f for light",i)
00823 
00824                 # convert to ColorRGBA message
00825                 color = ColorRGBA()
00826                 color.r = param[0]
00827                 color.g = param[1]
00828                 color.b = param[2]
00829                 color.a = param[3] # Transparency
00830                 return 0, color
00831 
00832         def set_light(self,component_name,parameter_name,blocking=False):
00833                 ah = action_handle("set_light", component_name, parameter_name, blocking, self.parse)
00834                 if(self.parse):
00835                         return ah
00836                 else:
00837                         ah.set_active()
00838                 rospy.loginfo("Set <<%s>> to <<%s>>", component_name, parameter_name)
00839 
00840                 mode = LightMode()
00841                 mode.mode = LightModes.STATIC
00842                 color = ColorRGBA()
00843                 (error,color) = self.compose_color(component_name, parameter_name)
00844                 if error != 0:
00845                         message = "Composing the color failed with error: " + str(error)
00846                         ah.set_failed(error, message)
00847                         return ah
00848                 mode.colors = []
00849                 mode.colors.append(color)
00850 
00851                 # call action server
00852                 action_server_name = component_name + "/set_light"
00853                 rospy.logdebug("calling %s action server",action_server_name)
00854                 client = actionlib.SimpleActionClient(action_server_name, SetLightModeAction)
00855                 # trying to connect to server
00856                 rospy.logdebug("waiting for %s action server to start",action_server_name)
00857                 if not client.wait_for_server(rospy.Duration(1)):
00858                         # error: server did not respond
00859                         message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
00860                         rospy.logerr(message)
00861                         ah.set_failed(4, message)
00862                         return ah
00863                 else:
00864                         rospy.logdebug("%s action server ready",action_server_name)
00865 
00866                 # sending goal
00867                 goal = SetLightModeGoal()
00868                 goal.mode = mode
00869                 client.send_goal(goal)
00870                 ah.set_client(client)
00871                 ah.wait_inside()
00872                 return ah
00873 
00874 #------------------- Mimic section -------------------#
00875         ## Set the mimic of the cob_mimic component.
00876         #
00877         # The mode is given by a parameter on the parameter server.
00878         #
00879         # \param parameter_name Name of the parameter on the parameter server which holds the mimic mode (string).
00880 
00881         def set_mimic(self,component_name,parameter_name,blocking=False):
00882                 ah = action_handle("set_mimic", component_name, parameter_name, blocking, self.parse)
00883                 if(self.parse):
00884                         return ah
00885                 else:
00886                         ah.set_active()
00887                 rospy.loginfo("Set <<%s>> to <<%s>>", component_name, parameter_name)
00888 
00889                 # check mimic parameters
00890                 mimic = SetMimicGoal()
00891                 if not (type(parameter_name) is str or type(parameter_name) is list): # check outer list
00892                         message = "No valid parameter for mimic: not a string or list, aborting..."
00893                         rospy.logerr(message)
00894                         print "parameter is:",parameter_name
00895                         ah.set_failed(3, message)
00896                         return ah
00897 
00898                 if type(parameter_name) is str:
00899                         mimic.mimic = parameter_name
00900                 elif type(parameter_name) is list:
00901                         if len(parameter_name) != 3:
00902                                 message = "No valid parameter for mimic: not a list with size 3, aborting..."
00903                                 rospy.logerr(message)
00904                                 print "parameter is:",parameter_name
00905                                 ah.set_failed(3, message)
00906                                 return ah
00907                         if ((type(parameter_name[0]) is str) and (type(parameter_name[1]) is float or type(parameter_name[1]) is int) and (type(parameter_name[2]) is float or type(parameter_name[2]) is int)):
00908                                 mimic.mimic = parameter_name[0]
00909                                 mimic.speed = parameter_name[1]
00910                                 mimic.repeat = parameter_name[2]
00911                         else:
00912                                 message = "No valid parameter for mimic: not a list with [mode, speed, repeat], aborting..."
00913                                 rospy.logerr(message)
00914                                 print "parameter is:",parameter_name
00915                                 ah.set_failed(3, message)
00916                                 return ah
00917                 else:
00918                         rospy.logerr("you should never be here")
00919                 rospy.logdebug("accepted parameter %s for mimic",parameter_name)
00920 
00921                 # call action server
00922                 action_server_name = component_name + "/set_mimic"
00923                 rospy.logdebug("calling %s action server",action_server_name)
00924                 client = actionlib.SimpleActionClient(action_server_name, SetMimicAction)
00925                 # trying to connect to server
00926                 rospy.logdebug("waiting for %s action server to start",action_server_name)
00927                 if not client.wait_for_server(rospy.Duration(1)):
00928                         # error: server did not respond
00929                         message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
00930                         rospy.logerr(message)
00931                         ah.set_failed(4, message)
00932                         return ah
00933                 else:
00934                         rospy.logdebug("%s action server ready",action_server_name)
00935 
00936                 # sending goal
00937                 client.send_goal(mimic)
00938                 ah.set_client(client)
00939                 ah.wait_inside()
00940                 return ah
00941 
00942 #-------------------- Sound section --------------------#
00943         ## Say some text.
00944         #
00945         # The text to say may be given by a list of strings or a single string which points to a parameter on the ROS parameter server.
00946         #
00947         # \param parameter_name Name of the parameter
00948         # \param language Language to use for the TTS system
00949         def say(self,component_name,parameter_name,blocking=True):
00950                 ah = action_handle("say", component_name, parameter_name, blocking, self.parse)
00951                 if(self.parse):
00952                         return ah
00953                 else:
00954                         ah.set_active()
00955 
00956                 text = ""
00957                 # get values from parameter server
00958                 language = rospy.get_param(self.ns_global_prefix + "/" + component_name + "/language","en")
00959                 if type(parameter_name) is str:
00960                         full_parameter_name = self.ns_global_prefix + "/" + component_name + "/" + language + "/" + parameter_name
00961                         if not rospy.has_param(full_parameter_name):
00962                                 message = "Parameter " + full_parameter_name + " does not exist on ROS Parameter Server, aborting..."
00963                                 rospy.logerr(message)
00964                                 ah.set_failed(2, message)
00965                                 return ah
00966                         param = rospy.get_param(full_parameter_name)
00967                 else:
00968                         param = parameter_name
00969 
00970                 # check parameters
00971                 if not type(param) is list: # check list
00972                         message = "No valid parameter for " + component_name + ": not a list, aborting..."
00973                         rospy.logerr(message)
00974                         print "parameter is:",param
00975                         ah.set_failed(3, message)
00976                         return ah
00977                 else:
00978                         for i in param:
00979                                 #print i,"type1 = ", type(i)
00980                                 if not type(i) is str:
00981                                         message = "No valid parameter for " + component_name + ": not a list of strings, aborting..."
00982                                         rospy.logerr(message)
00983                                         print "parameter is:",param
00984                                         ah.set_failed(3, message)
00985                                         return ah
00986                                 else:
00987                                         text = text + i + " "
00988                                         rospy.logdebug("accepted parameter <<%s>> for <<%s>>",i,component_name)
00989                 rospy.loginfo("Saying <<%s>>",text)
00990 
00991                 # call action server
00992                 action_server_name = component_name + "/say"
00993                 rospy.logdebug("calling %s action server",action_server_name)
00994                 client = actionlib.SimpleActionClient(action_server_name, SayAction)
00995                 # trying to connect to server
00996                 rospy.logdebug("waiting for %s action server to start",action_server_name)
00997                 if not client.wait_for_server(rospy.Duration(1)):
00998                         # error: server did not respond
00999                         message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
01000                         rospy.logerr(message)
01001                         ah.set_failed(4, message)
01002                         return ah
01003                 else:
01004                         rospy.logdebug("%s action server ready",action_server_name)
01005 
01006                 # sending goal
01007                 client_goal = SayGoal()
01008                 client_goal.text = text
01009                 #print client_goal
01010                 client.send_goal(client_goal)
01011                 ah.set_client(client)
01012                 ah.wait_inside()
01013                 return ah
01014 
01015         ## Play a sound file.
01016         #
01017         # \param parameter_name Name of the parameter
01018         # \param language Language to use
01019         def play(self,component_name, parameter_name,blocking=True):
01020                 ah = action_handle("play", component_name, parameter_name, False, self.parse)
01021                 if(self.parse):
01022                         return ah
01023                 else:
01024                         ah.set_active()
01025 
01026                 if not (type(parameter_name) is str or type(parameter_name) is list): # check outer list
01027                         message = "No valid parameter for play: not a string or list, aborting..."
01028                         rospy.logerr(message)
01029                         print "parameter is:",parameter_name
01030                         ah.set_failed(3, message)
01031                         return ah
01032 
01033                 if type(parameter_name) is str:
01034                         full_parameter_name = self.ns_global_prefix + "/" + component_name + "/" + "audio_file_path"
01035                         if not rospy.has_param(full_parameter_name):
01036                                 message = "Parameter " + full_parameter_name + " does not exist on ROS Parameter Server, aborting..."
01037                                 rospy.logerr(message)
01038                                 ah.set_failed(2, message)
01039                                 return ah
01040                         filename = rospy.get_param(full_parameter_name) + "/" + parameter_name + ".wav"
01041                 elif type(parameter_name) is list:
01042                         if len(parameter_name) != 3:
01043                                 message = "No valid parameter for play: not a list with size 3, aborting..."
01044                                 rospy.logerr(message)
01045                                 print "parameter is:",parameter_name
01046                                 ah.set_failed(3, message)
01047                                 return ah
01048                         if ((type(parameter_name[0]) is str) and (type(parameter_name[1]) is str) and (type(parameter_name[2]) is str)):
01049                                 filename = parameter_name[1] + "/" + parameter_name[0] + "." + parameter_name[2]
01050                         else:
01051                                 message = "No valid parameter for play: not a list with [filename, file_path, file_suffix], aborting..."
01052                                 rospy.logerr(message)
01053                                 print "parameter is:",parameter_name
01054                                 ah.set_failed(3, message)
01055                                 return ah
01056                 else:
01057                         rospy.logerr("you should never be here")
01058                 rospy.logdebug("accepted parameter %s for play",parameter_name)
01059 
01060                 action_server_name = component_name + "/play"
01061                 rospy.logdebug("calling %s action server",action_server_name)
01062                 client = actionlib.SimpleActionClient(action_server_name, PlayAction)
01063                 # trying to connect to server
01064                 rospy.logdebug("waiting for %s action server to start",action_server_name)
01065                 if not client.wait_for_server(rospy.Duration(1)):
01066                         # error: server did not respond
01067                         message = "ActionServer " + action_server_name + " not ready  within timeout, aborting..."
01068                         rospy.logerr(message)
01069                         ah.set_failed(4, message)
01070                         return ah
01071                 else:
01072                         rospy.logdebug("%s action server ready",action_server_name)
01073 
01074                 # sending goal
01075                 rospy.loginfo("Playing <<%s>>",filename)
01076                 client_goal = PlayGoal()
01077                 client_goal.filename = filename
01078                 #print client_goal
01079                 client.send_goal(client_goal)
01080                 ah.set_client(client)
01081                 ah.wait_inside()
01082                 ah.set_succeeded()
01083                 return ah
01084 
01085         def set_wav_path(self,parameter_name,blocking=True):
01086                 if type(parameter_name) is str:
01087                         self.wav_path = parameter_name
01088                 else:
01089                         message = "Invalid wav_path parameter specified, aborting..."
01090                         rospy.logerr(message)
01091                         print "parameter is:", parameter_name
01092                         ah.set_failed(2, message)
01093                         return ah
01094 
01095 #------------------- General section -------------------#
01096         ## Sleep for a certain time.
01097         #
01098         # \param duration Duration in seconds to sleep.
01099         #
01100         def sleep(self,duration):
01101                 ah = action_handle("sleep", "", str(duration), True, self.parse)
01102                 if(self.parse):
01103                         return ah
01104                 else:
01105                         ah.set_active()
01106                 rospy.loginfo("Wait for %f sec",duration)
01107                 rospy.sleep(duration)
01108                 ah.set_succeeded()
01109                 return ah
01110 
01111         ## Waits for user input.
01112         #
01113         # Waits either for a user input or until timeout is reached.
01114         #
01115         # \param duration Duration in seconds for timeout.
01116         #
01117         # \todo TODO: implement waiting for timeout
01118         def wait_for_input(self,duration=0):
01119                 ah = action_handle("wait", "input", str(duration), True, self.parse)
01120                 if(self.parse):
01121                         return ah
01122                 else:
01123                         ah.set_active()
01124 
01125                 if (duration != 0):
01126                         rospy.logerr("Wait with duration not implemented yet") # \todo TODO: implement waiting with duration
01127 
01128                 rospy.loginfo("Wait for user input...")
01129                 retVal = raw_input()
01130                 rospy.loginfo("...got string <<%s>>",retVal)
01131                 ah.set_succeeded()
01132                 return retVal
01133 
01134 #------------------- action_handle section -------------------#
01135 ## Action handle class.
01136 #
01137 # The action handle is used to implement asynchronous behaviour within the script.
01138 class action_handle:
01139         ## Initializes the action handle.
01140         def __init__(self, function_name, component_name, parameter_name, blocking, parse):
01141                 global graph
01142                 self.parent_node = ""
01143                 self.error_code = -1
01144                 self.success = False
01145                 self.message = ""
01146                 self.function_name = function_name
01147                 self.component_name = component_name
01148                 self.parameter_name = parameter_name
01149                 self.state = ScriptState.UNKNOWN
01150                 self.blocking = blocking
01151                 self.parse = parse
01152                 self.level = int(rospy.get_param("/script_server/level",100))
01153                 self.state_pub = rospy.Publisher("/script_server/state", ScriptState, queue_size=1)
01154                 self.AppendNode(blocking)
01155                 self.client = None
01156                 self.client_state = 9
01157                 self.client_mode = ""
01158 
01159         ## Sets the actionlib client.
01160         def set_client(self,client):
01161                 self.client = client
01162 
01163         ## Sets the execution state to active, if not paused
01164         def set_active(self,mode=""):
01165                 if mode != "": # not processing an actionlib client
01166                         self.client_mode = mode
01167                         self.client_state = 1
01168                 self.check_pause()
01169                 self.state = ScriptState.ACTIVE
01170                 self.error_code = -1
01171                 self.PublishState()
01172 
01173                 global ah_counter
01174                 ah_counter += 1
01175 
01176         ## Checks for pause
01177         def check_pause(self):
01178                 param_string = "/script_server/pause"
01179                 while bool(rospy.get_param(param_string,False)):
01180                         rospy.logwarn("Script is paused...")
01181                         self.state = ScriptState.PAUSED
01182                         self.PublishState()
01183                         rospy.sleep(1)
01184                 if self.state == ScriptState.PAUSED:
01185                         rospy.loginfo("...continuing script")
01186 
01187         ## Sets the execution state to succeeded.
01188         def set_succeeded(self,message=""):
01189                 if self.client_mode != "": # not processing an actionlib client
01190                         self.client_state = 3
01191                 self.state = ScriptState.SUCCEEDED
01192                 self.error_code = 0
01193                 self.success = True
01194                 self.message = message
01195                 self.PublishState()
01196 
01197                 global ah_counter
01198                 ah_counter -= 1
01199 
01200         ## Sets the execution state to failed.
01201         def set_failed(self,error_code,message=""):
01202                 if self.client_mode != "": # not processing an actionlib client
01203                         self.client_state = 4
01204                 self.state = ScriptState.FAILED
01205                 self.error_code = error_code
01206                 self.success = False
01207                 self.message = message
01208                 self.PublishState()
01209 
01210                 global ah_counter
01211                 ah_counter -= 1
01212 
01213         ## Gets the state of an action handle.
01214         def get_state(self):
01215                 if self.client_mode != "": # not processing an actionlib client
01216                         return self.client_state
01217                 elif self.client == None:
01218                         return None
01219                 else:
01220                         return self.client.get_state()
01221 
01222         ## Gets the error code of an action handle.
01223         def get_error_code(self):
01224                 return self.error_code
01225 
01226         ## Returns the graphstring.
01227         def GetGraphstring(self):
01228                 if type(self.parameter_name) is types.StringType:
01229                         graphstring = str(datetime.datetime.utcnow())+"_"+self.function_name+"_"+self.component_name+"_"+self.parameter_name
01230                 else:
01231                         graphstring = str(datetime.datetime.utcnow())+"_"+self.function_name+"_"+self.component_name
01232                 return graphstring
01233 
01234         ## Gets level of function name.
01235         def GetLevel(self,function_name):
01236                 if (function_name == "move"):
01237                         level = 0
01238                 elif (function_name == "init"):
01239                         level = 1
01240                 elif (function_name == "stop"):
01241                         level = 1
01242                 elif (function_name == "sleep"):
01243                         level = 2
01244                 else:
01245                         level = 100
01246                 return level
01247 
01248         ## Appends a registered function to the graph.
01249         def AppendNode(self, blocking=True):
01250                 global graph
01251                 global graph_wait_list
01252                 global last_node
01253                 graphstring = self.GetGraphstring()
01254                 if self.parse:
01255                         if ( self.level >= self.GetLevel(self.function_name)):
01256                                 #print "adding " + graphstring + " to graph"
01257                                 graph.add_edge(last_node, graphstring)
01258                                 for waiter in graph_wait_list:
01259                                         graph.add_edge(waiter, graphstring)
01260                                 graph_wait_list=[]
01261                                 if blocking:
01262                                         last_node = graphstring
01263                                 else:
01264                                         self.parent_node = graphstring
01265                         #else:
01266                                 #print "not adding " + graphstring + " to graph"
01267                 #else:
01268                         #self.PublishState()
01269 
01270         ## Publishs the state of the action handle
01271         def PublishState(self):
01272                 script_state = ScriptState()
01273                 script_state.header.stamp = rospy.Time.now()
01274                 script_state.function_name = self.function_name
01275                 script_state.component_name = self.component_name
01276                 script_state.full_graph_name = self.GetGraphstring()
01277                 if ( type(self.parameter_name) is str ):
01278                         script_state.parameter_name = self.parameter_name
01279                 else:
01280                         script_state.parameter_name = ""
01281                 script_state.state = self.state
01282                 script_state.error_code = self.error_code
01283                 self.state_pub.publish(script_state)
01284 
01285         ## Handles wait.
01286         #
01287         # This function is meant to be uses directly in the script.
01288         #
01289         # \param duration Duration for timeout.
01290         def wait(self, duration=None):
01291                 global ah_counter
01292                 ah_counter += 1
01293                 self.blocking = True
01294                 self.wait_for_finished(duration,True)
01295 
01296         ## Handles inside wait.
01297         #
01298         # This function is meant to be uses inside the simple_script_server.
01299         #
01300         # \param duration Duration for timeout.
01301         def wait_inside(self, duration=None):
01302                 if self.blocking:
01303                         self.wait_for_finished(duration,True)
01304                 else:
01305                         thread.start_new_thread(self.wait_for_finished,(duration,False,))
01306                 return self.error_code
01307 
01308         ## Waits for the action to be finished.
01309         #
01310         # If duration is specified, waits until action is finished or timeout is reached.
01311         #
01312         # \param duration Duration for timeout.
01313         # \param logging Enables or disables logging for this wait.
01314         def wait_for_finished(self, duration, logging):
01315                 global graph_wait_list
01316                 if(self.parse):
01317                         if(self.parent_node != ""):
01318                                 graph_wait_list.append(self.parent_node)
01319                         return
01320 
01321                 if self.error_code <= 0:
01322                         if duration is None:
01323                                 if logging:
01324                                         rospy.loginfo("Wait for <<%s>> reaching <<%s>>...",self.component_name, self.parameter_name)
01325                                 self.client.wait_for_result()
01326                         else:
01327                                 if logging:
01328                                         rospy.loginfo("Wait for <<%s>> reached <<%s>> (max %f secs)...",self.component_name, self.parameter_name,duration)
01329                                 if not self.client.wait_for_result(rospy.Duration(duration)):
01330                                         message = "Timeout while waiting for <<%s>> to reach <<%s>>. Continuing..."%(self.component_name, self.parameter_name)
01331                                         if logging:
01332                                                 rospy.logerr(message)
01333                                         self.set_failed(10, message)
01334                                         return
01335                         # check state of action server
01336                         #print self.client.get_state()
01337                         if self.client.get_state() != 3:
01338                                 message = "...<<%s>> could not reach <<%s>>, aborting..."%(self.component_name, self.parameter_name)
01339                                 if logging:
01340                                         rospy.logerr(message)
01341                                 self.set_failed(11, message)
01342                                 return
01343                         if logging:
01344                                 rospy.loginfo("...<<%s>> reached <<%s>>",self.component_name, self.parameter_name)
01345                 else:
01346                         message = "Execution of <<%s>> to <<%s>> was aborted, wait not possible. Continuing..."%(self.component_name, self.parameter_name)
01347                         rospy.logwarn(message)
01348                         self.set_failed(self.error_code, message)
01349                         return
01350 
01351                 self.set_succeeded() # full success
01352 
01353         ## Cancel action
01354         #
01355         # Cancels action goal(s).
01356         def cancel(self):
01357                 self.client.cancel_all_goals()


cob_script_server
Author(s): Florian Weisshardt
autogenerated on Sun Jun 9 2019 20:20:12