simple_script_server.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 #
3 # Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 
18 import time
19 import datetime
20 import os
21 import sys
22 import math
23 import threading
24 import numpy
25 import itertools
26 import six
27 from threading import Thread
28 
29 try: # izip is only available in 2.x
30  from itertools import izip as zip
31 except ImportError:
32  pass
33 
34 # graph includes
35 import pygraphviz as pgv
36 
37 # ROS imports
38 import rospy
39 import actionlib
40 from actionlib.msg import TestAction, TestGoal
41 from actionlib_msgs.msg import GoalStatus
42 
43 from urdf_parser_py.urdf import URDF
44 
45 # msg imports
46 from std_msgs.msg import String,ColorRGBA
47 from std_srvs.srv import Trigger
48 from sensor_msgs.msg import JointState
49 from geometry_msgs.msg import PoseStamped, Twist
50 from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint
51 from move_base_msgs.msg import MoveBaseAction, MoveBaseGoal
52 from control_msgs.msg import FollowJointTrajectoryAction, FollowJointTrajectoryGoal
53 from tf.transformations import quaternion_from_euler
54 
55 # care-o-bot includes
56 from cob_actions.msg import SetStringAction, SetStringGoal
57 from cob_sound.msg import SayAction, SayGoal, PlayAction, PlayGoal
58 from cob_script_server.msg import ScriptState
59 from cob_light.msg import LightMode, LightModes, SetLightModeGoal, SetLightModeAction
60 from cob_mimic.msg import SetMimicGoal, SetMimicAction
61 
62 graph=""
63 graph_wait_list=[]
64 ah_counter = 0
65 graph = pgv.AGraph()
66 graph.node_attr['shape']='box'
67 last_node = "Start"
68 
69 
72 class script():
73  def __init__(self):
74  # use filename as nodename
75  filename = os.path.basename(sys.argv[0])
76  self.basename, extension = os.path.splitext(filename)
77  rospy.init_node(self.basename)
78  self.graph_pub = rospy.Publisher("/script_server/graph", String, queue_size=1)
79 
80 
81  def Initialize(self):
82  pass
83 
84 
85  def Run(self):
86  pass
87 
88 
91  def Start(self):
92  self.Parse()
93  global ah_counter
94  ah_counter = 0
96  rospy.loginfo("Starting <<%s>> script...",self.basename)
97  self.Initialize()
98  self.Run()
99  # wait until last threaded action finishes
100  rospy.loginfo("Wait for script to finish...")
101  while ah_counter != 0:
102  rospy.sleep(1)
103  rospy.loginfo("...script finished.")
104 
105 
108  def Parse(self):
109  rospy.loginfo("Start parsing...")
110  global graph
111  # run script in simulation mode
112  self.sss = simple_script_server(parse=True)
113  self.Initialize()
114  self.Run()
115 
116  # save graph on parameter server for further processing
117  #self.graph = graph
118  rospy.set_param("/script_server/graph", graph.string())
119  self.graph_pub.publish(graph.string())
120  rospy.loginfo("...parsing finished")
121  return graph.string()
122 
123 
127 
130  def __init__(self, parse=False):
131  global graph
132  self.ns_global_prefix = "/script_server"
133  self.wav_path = ""
134  self.parse = parse
135  try:
136  robot_description = rospy.search_param('robot_description') if rospy.search_param('robot_description') else '/robot_description'
137  rospy.loginfo("Initialize urdf structure from '{}'".format(robot_description))
138  self.robot_urdf = URDF.from_parameter_server(key=robot_description)
139  except KeyError as key_err:
140  self.robot_urdf = None
141  message = "Unable to initialize urdf structure: {}".format(key_err)
142  rospy.logerr(message)
143  rospy.sleep(1) # we have to wait here until publishers are ready, don't ask why
144 
145 #------------------- Init section -------------------#
146 
151  def init(self,component_name,blocking=True):
152  return self.trigger(component_name,"init",blocking=blocking)
153 
154 
159  def stop(self,component_name,mode="omni",blocking=True):
160  ah = action_handle("stop", component_name, "", False, self.parse)
161  if(self.parse):
162  return ah
163  else:
164  ah.set_active(mode="service")
165 
166  rospy.loginfo("<<stop>> <<%s>>", component_name)
167  if component_name == "base":
168  if(mode == None or mode == ""):
169  action_server_name = "/move_base"
170  elif(mode == "omni"):
171  action_server_name = "/move_base"
172  elif(mode == "diff"):
173  action_server_name = "/move_base_diff"
174  elif(mode == "linear"):
175  action_server_name = "/move_base_linear"
176  else:
177  message = "Given navigation mode " + mode + " for " + component_name + " is not valid, aborting..."
178  rospy.logerr(message)
179  ah.set_failed(33, message)
180  return ah
181  client = actionlib.SimpleActionClient(action_server_name, MoveBaseAction)
182  else:
183  parameter_name = self.ns_global_prefix + "/" + component_name + "/action_name"
184  if not rospy.has_param(parameter_name):
185  message = "Parameter " + parameter_name + " does not exist on ROS Parameter Server, aborting..."
186  rospy.logerr(message)
187  ah.set_failed(2, message)
188  return ah
189  action_server_name = rospy.get_param(parameter_name)
190  client = actionlib.SimpleActionClient(action_server_name, FollowJointTrajectoryAction)
191 
192  # call action server
193  rospy.logdebug("calling %s action server",action_server_name)
194 
195  if blocking:
196  # trying to connect to server
197  rospy.logdebug("waiting for %s action server to start",action_server_name)
198  if not client.wait_for_server(rospy.Duration(1)):
199  # error: server did not respond
200  message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
201  rospy.logerr(message)
202  ah.set_failed(4, message)
203  return ah
204  else:
205  rospy.logdebug("%s action server ready",action_server_name)
206 
207  # cancel all goals
208  client.cancel_all_goals()
209  ah.set_succeeded() # full success
210  return ah
211 
212 
217  def recover(self,component_name,blocking=True):
218  return self.trigger(component_name,"recover",blocking=blocking)
219 
220 
225  def halt(self,component_name,blocking=True):
226  return self.trigger(component_name,"halt",blocking=blocking)
227 
228 
235  def trigger(self,component_name,service_name,blocking=True):
236  ah = action_handle(service_name, component_name, "", blocking, self.parse)
237  if(self.parse):
238  return ah
239  else:
240  ah.set_active(mode="service")
241 
242  rospy.loginfo("<<%s>> <<%s>>", service_name, component_name)
243  parameter_name = self.ns_global_prefix + "/" + component_name + "/service_ns"
244  if not rospy.has_param(parameter_name):
245  message = "Parameter " + parameter_name + " does not exist on ROS Parameter Server, aborting..."
246  rospy.logerr(message)
247  ah.set_failed(2, message)
248  return ah
249  service_ns_name = rospy.get_param(parameter_name)
250  service_full_name = service_ns_name + "/" + service_name
251 
252  if blocking:
253  # check if service is available
254  try:
255  rospy.wait_for_service(service_full_name,1)
256  except rospy.ROSException as e:
257  error_message = "%s"%e
258  message = "...service <<" + service_name + ">> of <<" + component_name + ">> not available,\n error: " + error_message
259  rospy.logerr(message)
260  ah.set_failed(4, message)
261  return ah
262 
263  # check if service is callable
264  try:
265  trigger = rospy.ServiceProxy(service_full_name,Trigger)
266  if blocking:
267  rospy.loginfo("Wait for <<%s>> to <<%s>>...", component_name, service_name)
268  resp = trigger()
269  else:
270  Thread(target=trigger).start()
271  except rospy.ServiceException as e:
272  error_message = "%s"%e
273  message = "...calling <<" + service_name + ">> of <<" + component_name + ">> not successfull,\n error: " + error_message
274  rospy.logerr(message)
275  ah.set_failed(10, message)
276  return ah
277 
278  if blocking:
279  # evaluate sevice response
280  if not resp.success:
281  message = "...response of <<" + service_name + ">> of <<" + component_name + ">> not successfull,\n error: " + resp.message
282  rospy.logerr(message)
283  ah.set_failed(10, message)
284  return ah
285 
286  # full success
287  rospy.loginfo("...<<%s>> is <<%s>>", component_name, service_name)
288  ah.set_succeeded() # full success
289  return ah
290 
291 
298  def trigger_action(self,component_name,action_name,blocking=True):
299  ah = action_handle(action_name, component_name, "", blocking, self.parse)
300  if(self.parse):
301  return ah
302  else:
303  ah.set_active(mode="action")
304 
305  rospy.loginfo("<<%s>> <<%s>>", action_name, component_name)
306  #parameter_name = self.ns_global_prefix + "/" + component_name + "/service_ns"
307  #if not rospy.has_param(parameter_name):
308  #message = "Parameter " + parameter_name + " does not exist on ROS Parameter Server, aborting..."
309  #rospy.logerr(message)
310  #ah.set_failed(2, message)
311  #return ah
312  #service_ns_name = rospy.get_param(parameter_name)
313  action_full_name = "/" + component_name + "/" + action_name
314  action_client = actionlib.SimpleActionClient(action_full_name, TestAction)
315 
316  if blocking:
317  # check if action is available
318  if not action_client.wait_for_server(rospy.Duration(1)):
319  message = "ActionServer %s is not running"%action_full_name
320  rospy.logerr(message)
321  ah.set_failed(4, message)
322  return ah
323 
324  # call the action
325  if blocking:
326  rospy.loginfo("Wait for <<%s>> to <<%s>>...", component_name, action_name)
327  goal_state = action_client.send_goal_and_wait(TestGoal())
328  if not (action_client.get_state() == GoalStatus.SUCCEEDED):
329  message = "...state of <<" + action_name + ">> of <<" + component_name + ">> : " + GoalStatus.to_string(action_client.get_state())
330  rospy.logerr(message)
331  ah.set_failed(10, message)
332  return ah
333  else:
334  action_client.send_goal(TestGoal())
335 
336  # full success
337  rospy.loginfo("...<<%s>> is <<%s>>", component_name, action_name)
338  ah.set_succeeded() # full success
339  return ah
340 
341 
342 
349  def string_action(self,component_name, data, blocking):
350  action_name = "set_string"
351  ah = action_handle(action_name, component_name, "", blocking, self.parse)
352  if(self.parse):
353  return ah
354  else:
355  ah.set_active(mode="action")
356 
357  rospy.loginfo("<<%s>> <<%s>>", action_name, component_name)
358  action_full_name = "/" + component_name + "/" + action_name
359  action_client = actionlib.SimpleActionClient(action_full_name, SetStringAction)
360 
361  if blocking:
362  # check if action is available
363  if not action_client.wait_for_server(rospy.Duration(1)):
364  message = "ActionServer %s is not running"%action_full_name
365  rospy.logerr(message)
366  ah.set_failed(4, message)
367  return ah
368 
369  # call the action
370  goal = SetStringGoal()
371  goal.data = data
372  if blocking:
373  rospy.loginfo("Wait for <<%s>> to <<%s>>...", component_name, action_name)
374  goal_state = action_client.send_goal_and_wait(goal)
375  if not (action_client.get_state() == GoalStatus.SUCCEEDED):
376  message = "...state of <<" + action_name + ">> of <<" + component_name + ">> : " + GoalStatus.to_string(action_client.get_state())
377  rospy.logerr(message)
378  ah.set_failed(10, message)
379  return ah
380  else:
381  action_client.send_goal(goal)
382 
383  # full success
384  rospy.loginfo("...<<%s>> is <<%s>>", component_name, action_name)
385  ah.set_succeeded() # full success
386  return ah
387 
388 
389 #------------------- Move section -------------------#
390 
397  def move(self,component_name,parameter_name,blocking=True, mode=None, speed_factor=1.0, urdf_vel=False, default_vel=None, stop_at_waypoints=False):
398  if component_name == "base":
399  return self.move_base(component_name,parameter_name,blocking, mode)
400  else:
401  return self.move_traj(component_name,parameter_name,blocking, speed_factor=speed_factor, urdf_vel=urdf_vel, default_vel=default_vel, stop_at_waypoints=stop_at_waypoints)
402 
403 
410  def move_base(self,component_name,parameter_name,blocking, mode):
411  ah = action_handle("move", component_name, parameter_name, blocking, self.parse)
412  if(self.parse):
413  return ah
414  else:
415  ah.set_active()
416 
417  if(mode == None or mode == ""):
418  rospy.loginfo("Move <<%s>> to <<%s>>",component_name,parameter_name)
419  else:
420  rospy.loginfo("Move <<%s>> to <<%s>> using <<%s>> mode",component_name,parameter_name,mode)
421 
422  # get joint values from parameter server
423  if type(parameter_name) is str:
424  full_parameter_name = self.ns_global_prefix + "/" + component_name + "/" + parameter_name
425  if not rospy.has_param(full_parameter_name):
426  message = "Parameter " + full_parameter_name + " does not exist on ROS Parameter Server, aborting..."
427  rospy.logerr(message)
428  ah.set_failed(2, message)
429  return ah
430  param = rospy.get_param(self.ns_global_prefix + "/" + component_name + "/" + parameter_name)
431  else:
432  param = parameter_name
433 
434  # check trajectory parameters
435  if not type(param) is list: # check outer list
436  message = "No valid parameter for " + component_name + ": not a list, aborting..."
437  rospy.logerr(message)
438  print("parameter is:",param)
439  ah.set_failed(3, message)
440  return ah
441  else:
442  #print i,"type1 = ", type(i)
443  DOF = 3
444  if not len(param) == DOF: # check dimension
445  message = "No valid parameter for " + component_name + ": dimension should be " + str(DOF) + " but is " + str(len(param)) + ", aborting..."
446  rospy.logerr(message)
447  print("parameter is:",param)
448  ah.set_failed(3, message)
449  return ah
450  else:
451  for i in param:
452  #print i,"type2 = ", type(i)
453  if not ((type(i) is float) or (type(i) is int)): # check type
454  #print type(i)
455  message = "No valid parameter for " + component_name + ": not a list of float or int, aborting..."
456  rospy.logerr(message)
457  print("parameter is:",param)
458  ah.set_failed(3, message)
459  return ah
460  else:
461  rospy.logdebug("accepted parameter %f for %s",i,component_name)
462 
463  # convert to pose message
464  pose = PoseStamped()
465  pose.header.stamp = rospy.Time.now()
466  pose.header.frame_id = "map"
467  pose.pose.position.x = param[0]
468  pose.pose.position.y = param[1]
469  pose.pose.position.z = 0.0
470  q = quaternion_from_euler(0, 0, param[2])
471  pose.pose.orientation.x = q[0]
472  pose.pose.orientation.y = q[1]
473  pose.pose.orientation.z = q[2]
474  pose.pose.orientation.w = q[3]
475 
476  # call action server
477  if(mode == None or mode == ""):
478  action_server_name = "/move_base"
479  elif(mode == "omni"):
480  action_server_name = "/move_base"
481  elif(mode == "diff"):
482  action_server_name = "/move_base_diff"
483  elif(mode == "linear"):
484  action_server_name = "/move_base_linear"
485  else:
486  message = "Given navigation mode " + mode + " for " + component_name + " is not valid, aborting..."
487  rospy.logerr(message)
488  ah.set_failed(33, message)
489  return ah
490 
491  rospy.logdebug("calling %s action server",action_server_name)
492  client = actionlib.SimpleActionClient(action_server_name, MoveBaseAction)
493  # trying to connect to server
494  rospy.logdebug("waiting for %s action server to start",action_server_name)
495  if not client.wait_for_server(rospy.Duration(1)):
496  # error: server did not respond
497  message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
498  rospy.logerr(message)
499  ah.set_failed(4, message)
500  return ah
501  else:
502  rospy.logdebug("%s action server ready",action_server_name)
503 
504  # sending goal
505  client_goal = MoveBaseGoal()
506  client_goal.target_pose = pose
507  #print client_goal
508  client.send_goal(client_goal)
509  ah.set_client(client)
510  ah.wait_inside()
511  return ah
512 
513  def _determine_desired_velocity(self, default_vel, start_pos, component_name, joint_names, speed_factor, urdf_vel):
514  if default_vel: # passed via argument
515  rospy.logdebug("using default_vel from argument")
516  if (type(default_vel) is float) or (type(default_vel) is int):
517  default_vel = numpy.array([default_vel for _ in start_pos])
518  elif (type(default_vel) is list) and (len(default_vel) == len(start_pos)) and all(
519  ((type(item) is float) or (type(item) is int)) for item in default_vel):
520  default_vel = default_vel
521  else:
522  raise ValueError("argument 'default_vel' {} has wrong format (must be float/int or list of float/int) with proper dimensions.".format(default_vel))
523  else: # get from parameter server
524  rospy.logdebug("using default_vel parameter server")
525  param_string = self.ns_global_prefix + "/" + component_name + "/default_vel"
526  if not rospy.has_param(param_string):
527  default_vel = numpy.array([0.1 for _ in start_pos]) # rad/s
528  rospy.logwarn(
529  "parameter '{}' does not exist on ROS Parameter Server, using default_vel {} [rad/sec].".format(
530  param_string, default_vel))
531  else:
532  param_vel = rospy.get_param(param_string)
533  if (type(param_vel) is float) or (type(param_vel) is int):
534  default_vel = numpy.array([param_vel for _ in start_pos])
535  elif (type(param_vel) is list) and (len(param_vel) == len(start_pos)) and all(
536  ((type(item) is float) or (type(item) is int)) for item in param_vel):
537  default_vel = numpy.array(param_vel)
538  else:
539  default_vel = numpy.array([0.1 for _ in start_pos]) # rad/s
540  rospy.logwarn(
541  "parameter '{}' {} has wrong format (must be float/int or list of float/int), using default_vel {} [rad/sec].".format(
542  param_string, param_vel, default_vel))
543  rospy.logdebug("default_vel: {}".format(default_vel))
544 
545  limit_vel = []
546  for idx, joint_name in enumerate(joint_names):
547  try:
548  limit_vel.append(self.robot_urdf.joint_map[joint_name].limit.velocity)
549  except Exception as e:
550  rospy.logwarn("Velocity limits for '{}' could not be retrieved from urdf structure:\n{}\nUsing default velocity: {}".format(joint_name, e, default_vel[idx]))
551  limit_vel.append(default_vel[idx])
552 
553  # limit_vel from urdf or default_vel (from argument or parameter server)
554  if urdf_vel:
555  rospy.logdebug("using default_vel from urdf_limits")
556  velocities = limit_vel
557  else:
558  rospy.logdebug("using default_vel from argument or parameter server")
559  velocities = list(default_vel)
560 
561  # check velocity limits
562  desired_vel = numpy.array(velocities)*speed_factor
563  if (numpy.any(desired_vel > numpy.array(limit_vel))):
564  raise ValueError("desired velocities {} exceed velocity limits {},...aborting".format(desired_vel, numpy.array(limit_vel)))
565 
566  if (numpy.any(desired_vel <= numpy.zeros_like(desired_vel))):
567  raise ValueError("desired velocities {} cannot be zero or negative,...aborting".format(desired_vel))
568  rospy.logdebug("Velocities are: {}".format(desired_vel))
569  return desired_vel
570 
571 
572  def compose_trajectory(self, component_name, parameter_name, speed_factor=1.0, urdf_vel=False, default_vel=None, stop_at_waypoints=False):
573  if urdf_vel and default_vel:
574  rospy.logerr("arguments not valid - cannot set 'urdf_vel' and 'default_vel' at the same time, aborting...")
575  return (JointTrajectory(), 3)
576 
577  # get joint_names from parameter server
578  param_string = self.ns_global_prefix + "/" + component_name + "/joint_names"
579  if not rospy.has_param(param_string):
580  rospy.logerr("parameter %s does not exist on ROS Parameter Server, aborting...",param_string)
581  return (JointTrajectory(), 2)
582  joint_names = rospy.get_param(param_string)
583 
584  # check joint_names parameter
585  if not type(joint_names) is list: # check list
586  rospy.logerr("no valid joint_names for %s: not a list, aborting...",component_name)
587  print("joint_names are:",joint_names)
588  return (JointTrajectory(), 3)
589  else:
590  for i in joint_names:
591  #print i,"type1 = ", type(i)
592  if not type(i) is str: # check string
593  rospy.logerr("no valid joint_names for %s: not a list of strings, aborting...",component_name)
594  print("joint_names are:", joint_names)
595  return (JointTrajectory(), 3)
596  else:
597  rospy.logdebug("accepted joint_names for component %s",component_name)
598 
599  # get joint values from parameter server
600  if type(parameter_name) is str:
601  full_parameter_name = self.ns_global_prefix + "/" + component_name + "/" + parameter_name
602  if not rospy.has_param(full_parameter_name):
603  rospy.logerr("parameter %s does not exist on ROS Parameter Server, aborting...",full_parameter_name)
604  return (JointTrajectory(), 2)
605  param = rospy.get_param(full_parameter_name)
606  else:
607  param = parameter_name
608 
609  # check trajectory parameters
610  if not type(param) is list: # check outer list
611  rospy.logerr("no valid parameter for %s: not a list, aborting...",component_name)
612  print("parameter is:",param)
613  return (JointTrajectory(), 3)
614 
615  traj = []
616  for point in param:
617  #print point,"type1 = ", type(point)
618  if type(point) is str:
619  full_parameter_name = self.ns_global_prefix + "/" + component_name + "/" + point
620  if not rospy.has_param(full_parameter_name):
621  rospy.logerr("parameter %s does not exist on ROS Parameter Server, aborting...",full_parameter_name)
622  return (JointTrajectory(), 2)
623  point = rospy.get_param(full_parameter_name)
624  point = point[0] # \todo TODO: hack because only first point is used, no support for trajectories inside trajectories
625  #print point
626  elif type(point) is list:
627  rospy.logdebug("point is a list")
628  else:
629  rospy.logerr("no valid parameter for %s: not a list of lists or strings, aborting...",component_name)
630  print("parameter is:",param)
631  return (JointTrajectory(), 3)
632 
633  # here: point should be list of floats/ints
634  #print point
635  if not len(point) == len(joint_names): # check dimension
636  rospy.logerr("no valid parameter for %s: dimension should be %d and is %d, aborting...",component_name,len(joint_names),len(point))
637  print("parameter is:",param)
638  return (JointTrajectory(), 3)
639 
640  for value in point:
641  #print value,"type2 = ", type(value)
642  if not ((type(value) is float) or (type(value) is int)): # check type
643  #print type(value)
644  rospy.logerr("no valid parameter for %s: not a list of float or int, aborting...",component_name)
645  print("parameter is:",param)
646  return (JointTrajectory(), 3)
647 
648  rospy.logdebug("accepted value %f for %s",value,component_name)
649  traj.append(point)
650 
651  rospy.logdebug("accepted trajectory for %s",component_name)
652  rospy.logdebug("traj after param: {}".format(traj))
653 
654  # get current pos
655  timeout = 3.0
656  try:
657  joint_state_topic = rospy.get_param(self.ns_global_prefix + "/" + component_name + "/joint_state_topic", "/" + component_name + "/joint_states")
658  joint_state_message = rospy.wait_for_message(joint_state_topic, JointState, timeout = timeout) # type: JointState
659  # make sure we have the same joint order
660  start_pos = []
661  for name in joint_names:
662  idx = joint_state_message.name.index(name)
663  start_pos.append(joint_state_message.position[idx])
664  except rospy.ROSException as e:
665  rospy.logwarn("no joint states received from %s within timeout of %ssec. using default point time of 8sec.", component_name, str(timeout))
666  start_pos = []
667 
668  # insert start_pos to trajectory
669  if start_pos:
670  traj.insert(0,start_pos)
671  rospy.logdebug("traj after add: {}".format(traj))
672 
673  # convert to ROS trajectory message
674  traj_msg = JointTrajectory()
675  # if no timestamp is set in header, this means that the trajectory starts "now"
676  traj_msg.joint_names = joint_names
677  point_nr = 0
678  traj_time = 0
679 
680  # get desired_vel
681  try:
682  desired_vel = self._determine_desired_velocity(default_vel, start_pos, component_name, joint_names, speed_factor, urdf_vel)
683  except ValueError as val_err:
684  rospy.logerr(val_err)
685  return (JointTrajectory(), 3)
686 
687  # get default_acc
688  param_string = self.ns_global_prefix + "/" + component_name + "/default_acc"
689  if not rospy.has_param(param_string):
690  default_acc = numpy.array([1.0 for _ in start_pos]) # rad^2/s
691  rospy.logwarn("parameter '{}' does not exist on ROS Parameter Server, using default_acc {} [rad^2/sec].".format(param_string,default_acc))
692  else:
693  param_acc = rospy.get_param(param_string)
694  if (type(param_acc) is float) or (type(param_acc) is int):
695  default_acc = numpy.array([param_acc for _ in start_pos])
696  elif (type(param_acc) is list) and (len(param_acc) == len(start_pos)) and all(
697  ((type(item) is float) or (type(item) is int)) for item in param_acc):
698  default_acc = numpy.array(param_acc)
699  else:
700  default_acc = numpy.array([1.0 for _ in start_pos]) # rad^2/s
701  rospy.logwarn("parameter '{}' {} has wrong format (must be float/int or list of float/int), using default_acc {} [rad^2/sec].".format(param_string,param_acc,default_acc))
702 
703  # filter duplicates
704  def is_close(a,b):
705  return numpy.all(numpy.isclose(numpy.array(a), numpy.array(b), atol=0.001))
706 
707  def unique_next(elems):
708  for i, (curr, nxt) in enumerate(zip(elems, elems[1:]+[None])):
709  if not nxt:
710  yield curr
711  else:
712  if not is_close(curr, nxt):
713  yield curr
714  else:
715  rospy.logdebug("dropping trajectory point {} due to is close: (curr {}, nxt: {})".format(i, curr, nxt))
716 
717  try:
718  traj = list(unique_next(traj))
719  except Exception as e:
720  rospy.logerr(e)
721  return (JointTrajectory(), 3)
722  rospy.logdebug("traj after unique_nxt: {}".format(traj))
723 
724  # calculate time_from_start
725  for point in traj:
726  point_nr = point_nr + 1
727  point_msg = JointTrajectoryPoint()
728  point_msg.positions = point
729 
730  # use hardcoded point_time if no start_pos available
731  if start_pos != []:
732  point_time = self.calculate_point_time(start_pos, point, desired_vel, default_acc)
733  else:
734  point_time = 8*point_nr
735 
736  start_pos = point
737  point_msg.time_from_start=rospy.Duration(point_time + traj_time)
738  traj_time += point_time
739  traj_msg.points.append(point_msg)
740 
741  # calculate traj_point velocities and accelerations
742  prevs, items, nexts = itertools.tee(traj_msg.points, 3)
743  prevs = itertools.chain([None], prevs)
744  nexts = itertools.chain(itertools.islice(nexts, 1, None), [None])
745  for idx, (pre, curr, post) in enumerate(zip(prevs, items, nexts)):
746  traj_msg.points[idx].velocities = self.calculate_point_velocities(pre, curr, post, stop_at_waypoints)
747  traj_msg.points[idx].accelerations = self.calculate_point_accelerations(pre, curr, post)
748 
749  # drop first trajectory point because it is equal to start_pos
750  traj_msg.points = traj_msg.points[1:]
751 
752  return (traj_msg, 0)
753 
754  def calculate_point_time(self, start_pos, end_pos, default_vel, default_acc):
755  if isinstance(default_vel, float):
756  default_vel = numpy.array([default_vel for _ in start_pos])
757 
758  if isinstance(default_acc, float):
759  default_acc = numpy.array([default_acc for _ in start_pos])
760 
761  try:
762  # dist: Distance traveled in the move by each joint
763  dist = numpy.abs(numpy.array(start_pos) - numpy.array(end_pos))
764 
765  t1 = default_vel / default_acc # Time needed for joints to accelerate to desired velocity
766  s1 = default_acc / 2.0 * t1**2 # Distance traveled during this time
767 
768  t = numpy.zeros_like(dist)
769 
770  for i in range(len(start_pos)):
771  if 2 * s1[i] < dist[i]:
772  # If we can accelerate and decelerate in less than the total distance, then:
773  # accelerate up to speed, travel at that speed for a bit and then decelerate, a three phase trajectory:
774  # with constant velocity phase (acc, const vel, dec)
775  # 1st phase: accelerate from v=0 to v=default_vel with a=default_acc in t=t1. Need s1 distance for this
776  # 2nd phase: constant velocity with v=default_vel and t=t2
777  # 3rd phase: deceleration (analog to 1st phase). Need s1 distance for this
778  # ^
779  # | __2__
780  # | / \
781  # v|1 / \ 3
782  # | / \
783  # o--------------->
784  # t d_max
785  s2 = dist[i] - 2 * s1[i]
786  t2 = s2 / default_vel[i]
787  t[i] = 2 * t1[i] + t2
788  else:
789  # If we don't have enough distance to get to full speed, then we do
790  # without constant velocity phase (only acc and dec, so a two phase trajectory)
791  # 1st phase: accelerate from v=0 to v=default_vel with a=default_acc in t=t1
792  # 2nd phase: missing because distance is to short (we already reached the distance with the acc and dec phase)
793  # 3rd phase: deceleration (analog to 1st phase)
794  t[i] = numpy.sqrt(dist[i] / default_acc[i])
795 
796  # Instead of deciding per joint if we can do a three or two-phase trajectory,
797  # we can simply take the slowest joint of them all and select that.
798  #point_time = max(numpy.max(t), 0.4) # use minimal point_time
799  point_time = numpy.max(t)
800  except ValueError as e:
801  print("Value Error: {}".format(e))
802  print("Likely due to mimic joints. Using default point_time: 3.0 [sec]")
803  point_time = 3.0 # use default point_time
804  return point_time
805 
806  def calculate_point_velocities(self, prev, curr, post, stop_at_waypoints=False):
807  # commenting rospy.logdebug for performance reasons
808  #rospy.logdebug("calculate_point_velocities")
809  #rospy.logdebug("prev: {}".format(prev))
810  #rospy.logdebug("curr: {}".format(curr))
811  #rospy.logdebug("post: {}".format(post))
812 
813  if stop_at_waypoints:
814  #rospy.logdebug("stop_at_waypoints")
815  point_velocities = numpy.zeros(len(curr.positions))
816  elif not post: # set zero velocities for last trajectory point only
817  #rospy.logdebug("not has post")
818  point_velocities = numpy.zeros(len(curr.positions))
819  elif not prev:
820  #rospy.logdebug("not has prev")
821  point_velocities = numpy.zeros(len(curr.positions))
822  else:
823  #rospy.logdebug("has prev, has post")
824  # calculate based on difference quotient post-curr
825  point_velocities = numpy.divide(numpy.subtract(numpy.array(post.positions), numpy.array(prev.positions)), numpy.array([(post.time_from_start-prev.time_from_start).to_sec()]*len(curr.positions)))
826  #rospy.logdebug("point_velocities diff quot: {}".format(point_velocities))
827 
828  # check sign change or consecutive points too close
829  #rospy.logdebug("has prev")
830  curr_prev_diff = numpy.subtract(numpy.array(curr.positions), numpy.array(prev.positions))
831  post_curr_diff = numpy.subtract(numpy.array(post.positions), numpy.array(curr.positions))
832  #rospy.logdebug("curr_prev_diff: {}".format(curr_prev_diff))
833  #rospy.logdebug("post_curr_diff: {}".format(post_curr_diff))
834  same_sign = numpy.equal(numpy.sign(curr_prev_diff), numpy.sign(post_curr_diff))
835  prev_close = numpy.isclose(curr_prev_diff, numpy.zeros_like(curr_prev_diff), atol=0.0001)
836  post_close = numpy.isclose(post_curr_diff, numpy.zeros_like(post_curr_diff), atol=0.0001)
837  #rospy.logdebug("same_sign: {}".format(same_sign))
838  #rospy.logdebug("prev_close: {}".format(prev_close))
839  #rospy.logdebug("post_close: {}".format(post_close))
840 
841  for idx, vel in enumerate(point_velocities):
842  if prev_close[idx]:
843  #rospy.logdebug("prev close for joint {} - setting vel to 0.0".format(idx))
844  point_velocities[idx] = 0.0
845  if post_close[idx]:
846  #rospy.logdebug("post close for joint {} - setting vel to 0.0".format(idx))
847  point_velocities[idx] = 0.0
848  if not same_sign[idx]:
849  #rospy.logdebug("sign change for joint {} - setting vel to 0.0".format(idx))
850  point_velocities[idx] = 0.0
851 
852  #rospy.logdebug("point_velocities: {}".format(point_velocities))
853  return list(point_velocities)
854 
855  def calculate_point_accelerations(self, prev, curr, post):
856  return [0]*len(curr.positions)
857 
858 
865  def move_traj(self,component_name,parameter_name,blocking, speed_factor=1.0, urdf_vel=False, default_vel=None, stop_at_waypoints=False):
866  ah = action_handle("move", component_name, parameter_name, blocking, self.parse)
867  if(self.parse):
868  return ah
869  else:
870  ah.set_active()
871 
872  rospy.loginfo("Move <<%s>> to <<%s>>",component_name,parameter_name)
873  (traj_msg, error_code) = self.compose_trajectory(component_name, parameter_name, speed_factor=speed_factor, urdf_vel=urdf_vel, default_vel=default_vel, stop_at_waypoints=stop_at_waypoints)
874  if error_code != 0:
875  message = "Composing the trajectory failed with error: " + str(error_code)
876  ah.set_failed(error_code, message)
877  return ah
878 
879  # call action server
880  parameter_name = self.ns_global_prefix + "/" + component_name + "/action_name"
881  if not rospy.has_param(parameter_name):
882  message = "Parameter " + parameter_name + " does not exist on ROS Parameter Server, aborting..."
883  rospy.logerr(message)
884  ah.set_failed(2, message)
885  return ah
886  action_server_name = rospy.get_param(parameter_name)
887  rospy.logdebug("calling %s action server",action_server_name)
888  client = actionlib.SimpleActionClient(action_server_name, FollowJointTrajectoryAction)
889  # trying to connect to server
890  rospy.logdebug("waiting for %s action server to start",action_server_name)
891  if not client.wait_for_server(rospy.Duration(1)):
892  # error: server did not respond
893  message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
894  rospy.logerr(message)
895  ah.set_failed(4, message)
896  return ah
897  else:
898  rospy.logdebug("%s action server ready",action_server_name)
899 
900  # sending goal
901  client_goal = FollowJointTrajectoryGoal()
902  client_goal.trajectory = traj_msg
903  #print client_goal
904  client.send_goal(client_goal)
905  ah.set_client(client)
906  ah.wait_inside()
907  return ah
908 
909 
916  def move_base_rel(self, component_name, parameter_name=[0,0,0], blocking=True):
917  ah = action_handle("move_base_rel", component_name, parameter_name, blocking, self.parse)
918  if(self.parse):
919  return ah
920  else:
921  ah.set_active(mode="topic")
922 
923  parameter_topic_name = self.ns_global_prefix + "/" + component_name + "/topic_name"
924  if not rospy.has_param(parameter_topic_name):
925  message = "Parameter " + parameter_topic_name + " does not exist on ROS Parameter Server, aborting..."
926  rospy.logerr(message)
927  ah.set_failed(3, message)
928  return ah
929  topic_name = rospy.get_param(parameter_topic_name)
930  rospy.loginfo("Move base relatively by <<%s>>", parameter_name)
931 
932  # step 0: check validity of parameters:
933  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)):
934  message = "Parameter " + parameter_name + " not formated correctly (non-numeric list), aborting move_base_rel"
935  rospy.logerr(message)
936  print("parameter_name must be numeric list of length 3; (relative x and y transl [m], relative rotation [rad])")
937  ah.set_failed(3, message)
938  return ah
939  max_rel_trans_step = 1.0 # [m]
940  max_rel_rot_step = math.pi/2 # [rad]
941  if math.sqrt(parameter_name[0]**2 + parameter_name[1]**2) > max_rel_trans_step:
942  message = "Parameter " + str(parameter_name) + " exceeds maximal relative translation step (" + str(max_rel_trans_step) + "), aborting move_base_rel"
943  rospy.logerr(message)
944  ah.set_failed(3, message)
945  return(ah)
946  if abs(parameter_name[2]) > max_rel_rot_step:
947  message = "Parameter " + str(parameter_name) + " exceeds maximal relative rotation step (" + str(max_rel_rot_step) + "), aborting move_base_rel"
948  rospy.logerr(message)
949  ah.set_failed(3, message)
950  return(ah)
951 
952  # step 1: determine duration of motion so that upper thresholds for both translational as well as rotational velocity are not exceeded
953  max_trans_vel = 0.05 # [m/s]
954  max_rot_vel = 0.2 # [rad/s]
955  duration_trans_sec = math.sqrt(parameter_name[0]**2 + parameter_name[1]**2) / max_trans_vel
956  duration_rot_sec = abs(parameter_name[2] / max_rot_vel)
957  duration_sec = max(duration_trans_sec, duration_rot_sec)
958  duration_ros = rospy.Duration.from_sec(duration_sec) # duration of motion in ROS time
959 
960  # step 2: determine actual velocities based on calculated duration
961  x_vel = parameter_name[0] / duration_sec
962  y_vel = parameter_name[1] / duration_sec
963  rot_vel = parameter_name[2] / duration_sec
964 
965  # step 3: send constant velocity command to base_controller for the calculated duration of motion
966  pub = rospy.Publisher(topic_name, Twist, queue_size=1)
967  twist = Twist()
968  twist.linear.x = x_vel
969  twist.linear.y = y_vel
970  twist.angular.z = rot_vel
971  end_time = rospy.Time.now() + duration_ros
972 
973  if blocking:
974  rospy.loginfo("Wait for <<%s>> to finish move_base_rel...", component_name)
975  self.publish_twist(pub, twist, end_time)
976  else:
977  Thread(target=self.publish_twist, args=(pub, twist, end_time)).start()
978 
979  ah.set_succeeded()
980  return ah
981 
982  def publish_twist(self, pub, twist, end_time):
983  r = rospy.Rate(10) # send velocity commands at 10 Hz
984  while not rospy.is_shutdown() and rospy.Time.now() < end_time:
985  pub.publish(twist)
986  r.sleep()
987 
988 
998  def move_rel(self, component_name, parameter_name, blocking=True, speed_factor=1.0, urdf_vel=False, default_vel=None, stop_at_waypoints=False):
999  ah = action_handle("move_rel", component_name, parameter_name, blocking, self.parse)
1000  if(self.parse):
1001  return ah
1002  else:
1003  ah.set_active(mode="topic")
1004 
1005  rospy.loginfo("Move <<%s>> relatively by <<%s>>", component_name, parameter_name)
1006 
1007  # get joint_names from parameter server
1008  param_string = self.ns_global_prefix + "/" + component_name + "/joint_names"
1009  if not rospy.has_param(param_string):
1010  message = "parameter " + str(param_string) + " does not exist on ROS Parameter Server, aborting move_rel"
1011  rospy.logerr(message)
1012  ah.set_failed(3, message)
1013  return ah
1014  joint_names = rospy.get_param(param_string)
1015 
1016  # check joint_names parameter
1017  if not type(joint_names) is list: # check list
1018  message = "no valid joint_names for " + str(component_name) + ": not a list, aborting move_rel"
1019  rospy.logerr(message)
1020  print("joint_names are:",joint_names)
1021  ah.set_failed(3, message)
1022  return ah
1023  else:
1024  for i in joint_names:
1025  #print i,"type1 = ", type(i)
1026  if not type(i) is str: # check string
1027  message = "no valid joint_names for " + str(component_name) + ": not a list of strings, aborting move_rel"
1028  rospy.logerr(message)
1029  print("joint_names are:", joint_names)
1030  ah.set_failed(3, message)
1031  return ah
1032  else:
1033  rospy.logdebug("accepted joint_names for component %s",component_name)
1034 
1035  # step 0: check validity of parameters:
1036  if not isinstance(parameter_name, list):
1037  message = "Parameter " + str(parameter_name) + " not formated correctly (not a list), aborting move_rel"
1038  rospy.logerr(message)
1039  ah.set_failed(3, message)
1040  return ah
1041  for parameter in parameter_name:
1042  if not isinstance(parameter, list):
1043  message = "Parameter " + str(parameter_name) + " not formated correctly (not a list of lists), aborting move_rel"
1044  rospy.logerr(message)
1045  ah.set_failed(3, message)
1046  return ah
1047  for param in parameter:
1048  if not isinstance(param, (int, float)):
1049  message = "Parameter " + str(parameter) + " not formated correctly (not a list of numeric lists), aborting move_rel"
1050  rospy.logerr(message)
1051  ah.set_failed(3, message)
1052  return ah
1053 
1054  # step 1: get current position
1055  timeout = 1.0
1056  try:
1057  joint_state_topic = rospy.get_param(self.ns_global_prefix + "/" + component_name + "/joint_state_topic", "/" + component_name + "/joint_states")
1058  joint_state_message = rospy.wait_for_message(joint_state_topic, JointState, timeout = timeout) # type: JointState
1059  # make sure we have the same joint order
1060  start_pos = []
1061  for name in joint_names:
1062  idx = joint_state_message.name.index(name)
1063  start_pos.append(joint_state_message.position[idx])
1064  except rospy.ROSException:
1065  message = "no joint states received from %s within timeout of %ssec."%(component_name, str(timeout))
1066  rospy.logerr(message)
1067  ah.set_failed(3, message)
1068  return ah
1069 
1070  # step 2: get joint limits from urdf
1071  if not self.robot_urdf:
1072  message = "Failed to get joint limits from urdf structure - urdf structure is not initialized"
1073  rospy.logerr(message)
1074  ah.set_failed(3, message)
1075  return ah
1076  limits = {}
1077  for joint in self.robot_urdf.joints:
1078  limits.update({joint.name : joint.limit})
1079 
1080  # step 3 calculate and send goal
1081  end_poses = []
1082  for move_rel_param in parameter_name:
1083  end_pos = []
1084  if len(start_pos) == len(move_rel_param) and len(joint_names) == len(move_rel_param):
1085  for i in range(len(joint_names)):
1086  if (end_poses == []):
1087  pos_val = start_pos[i] + move_rel_param[i]
1088  # for multiple movements, append move_rel_param to previous calculated pose
1089  else:
1090  pos_val = end_poses[-1][i] + move_rel_param[i]
1091  # check if joint limits are exceeded
1092  if limits[joint_names[i]].upper > pos_val and limits[joint_names[i]].lower < pos_val:
1093  end_pos.append(pos_val)
1094  else:
1095  message = "Relative motion wil exceed absolute limits! %s would go to %f but limits are: %f (upper) and %f (lower)"%(joint_names[i], pos_val, limits[joint_names[i]].upper, limits[joint_names[i]].lower)
1096  rospy.logerr(message)
1097  ah.set_failed(3, message)
1098  return ah
1099  else:
1100  message = "Parameters %s don't fit with joint states!"%str(move_rel_param)
1101  rospy.logerr(message)
1102  ah.set_failed(3, message)
1103  return ah
1104  end_poses.append(end_pos)
1105 
1106  return self.move_traj(component_name, end_poses, blocking, speed_factor=speed_factor, urdf_vel=urdf_vel, default_vel=default_vel, stop_at_waypoints=stop_at_waypoints)
1107 
1108 #------------------- LED section -------------------#
1109 
1114 
1115  def compose_color(self,component_name,parameter_name):
1116  # get joint values from parameter server
1117  if type(parameter_name) is str:
1118  full_parameter_name = self.ns_global_prefix + "/" + component_name + "/" + parameter_name
1119  if not rospy.has_param(full_parameter_name):
1120  rospy.logerr("parameter %s does not exist on ROS Parameter Server, aborting...",full_parameter_name)
1121  return 2, None
1122  param = rospy.get_param(full_parameter_name)
1123  else:
1124  param = parameter_name
1125 
1126  # check color parameters
1127  if not type(param) is list: # check outer list
1128  rospy.logerr("no valid parameter for light: not a list, aborting...")
1129  print("parameter is:",param)
1130  return 3, None
1131  else:
1132  if not len(param) == 4: # check dimension
1133  rospy.logerr("no valid parameter for light: dimension should be 4 (r,g,b,a) and is %d, aborting...",len(param))
1134  print("parameter is:",param)
1135  return 3, None
1136  else:
1137  for i in param:
1138  #print i,"type1 = ", type(i)
1139  if not ((type(i) is float) or (type(i) is int)): # check type
1140  #print type(i)
1141  rospy.logerr("no valid parameter for light: not a list of float or int, aborting...")
1142  print("parameter is:",param)
1143  return 3, None
1144  else:
1145  rospy.logdebug("accepted parameter %f for light",i)
1146 
1147  # convert to ColorRGBA message
1148  color = ColorRGBA()
1149  color.r = param[0]
1150  color.g = param[1]
1151  color.b = param[2]
1152  color.a = param[3] # Transparency
1153  return 0, color
1154 
1155  def set_light(self,component_name,parameter_name,blocking=False):
1156  ah = action_handle("set_light", component_name, parameter_name, blocking, self.parse)
1157  if(self.parse):
1158  return ah
1159  else:
1160  ah.set_active()
1161  rospy.loginfo("Set <<%s>> to <<%s>>", component_name, parameter_name)
1162 
1163  mode = LightMode()
1164  mode.mode = LightModes.STATIC
1165  color = ColorRGBA()
1166  (error,color) = self.compose_color(component_name, parameter_name)
1167  if error != 0:
1168  message = "Composing the color failed with error: " + str(error)
1169  ah.set_failed(error, message)
1170  return ah
1171  mode.colors = []
1172  mode.colors.append(color)
1173 
1174  # call action server
1175  action_server_name = component_name + "/set_light"
1176  rospy.logdebug("calling %s action server",action_server_name)
1177  client = actionlib.SimpleActionClient(action_server_name, SetLightModeAction)
1178  # trying to connect to server
1179  rospy.logdebug("waiting for %s action server to start",action_server_name)
1180  if not client.wait_for_server(rospy.Duration(1)):
1181  # error: server did not respond
1182  message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
1183  rospy.logerr(message)
1184  ah.set_failed(4, message)
1185  return ah
1186  else:
1187  rospy.logdebug("%s action server ready",action_server_name)
1188 
1189  # sending goal
1190  goal = SetLightModeGoal()
1191  goal.mode = mode
1192  client.send_goal(goal)
1193  ah.set_client(client)
1194  ah.wait_inside()
1195  return ah
1196 
1197 #------------------- Mimic section -------------------#
1198 
1203 
1204  def set_mimic(self,component_name,parameter_name,blocking=False):
1205  ah = action_handle("set_mimic", component_name, parameter_name, blocking, self.parse)
1206  if(self.parse):
1207  return ah
1208  else:
1209  ah.set_active()
1210  rospy.loginfo("Set <<%s>> to <<%s>>", component_name, parameter_name)
1211 
1212  # check mimic parameters
1213  mimic = SetMimicGoal()
1214  if not (type(parameter_name) is str or type(parameter_name) is list): # check outer list
1215  message = "No valid parameter for mimic: not a string or list, aborting..."
1216  rospy.logerr(message)
1217  print("parameter is:",parameter_name)
1218  ah.set_failed(3, message)
1219  return ah
1220 
1221  if type(parameter_name) is str:
1222  mimic.mimic = parameter_name
1223  elif type(parameter_name) is list:
1224  if len(parameter_name) != 3:
1225  message = "No valid parameter for mimic: not a list with size 3, aborting..."
1226  rospy.logerr(message)
1227  print("parameter is:",parameter_name)
1228  ah.set_failed(3, message)
1229  return ah
1230  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)):
1231  mimic.mimic = parameter_name[0]
1232  mimic.speed = parameter_name[1]
1233  mimic.repeat = parameter_name[2]
1234  else:
1235  message = "No valid parameter for mimic: not a list with [mode, speed, repeat], aborting..."
1236  rospy.logerr(message)
1237  print("parameter is:",parameter_name)
1238  ah.set_failed(3, message)
1239  return ah
1240  else:
1241  rospy.logerr("you should never be here")
1242  rospy.logdebug("accepted parameter %s for mimic",parameter_name)
1243 
1244  # call action server
1245  action_server_name = component_name + "/set_mimic"
1246  rospy.logdebug("calling %s action server",action_server_name)
1247  client = actionlib.SimpleActionClient(action_server_name, SetMimicAction)
1248  # trying to connect to server
1249  rospy.logdebug("waiting for %s action server to start",action_server_name)
1250  if not client.wait_for_server(rospy.Duration(1)):
1251  # error: server did not respond
1252  message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
1253  rospy.logerr(message)
1254  ah.set_failed(4, message)
1255  return ah
1256  else:
1257  rospy.logdebug("%s action server ready",action_server_name)
1258 
1259  # sending goal
1260  client.send_goal(mimic)
1261  ah.set_client(client)
1262  ah.wait_inside()
1263  return ah
1264 
1265 #-------------------- Sound section --------------------#
1266 
1272  def say(self,component_name,parameter_name,blocking=True):
1273  ah = action_handle("say", component_name, parameter_name, blocking, self.parse)
1274  if(self.parse):
1275  return ah
1276  else:
1277  ah.set_active()
1278 
1279  text = ""
1280  # get values from parameter server
1281  language = rospy.get_param(self.ns_global_prefix + "/" + component_name + "/language","en")
1282  if type(parameter_name) is str:
1283  full_parameter_name = self.ns_global_prefix + "/" + component_name + "/" + language + "/" + parameter_name
1284  if not rospy.has_param(full_parameter_name):
1285  message = "Parameter " + full_parameter_name + " does not exist on ROS Parameter Server, aborting..."
1286  rospy.logerr(message)
1287  ah.set_failed(2, message)
1288  return ah
1289  param = rospy.get_param(full_parameter_name)
1290  else:
1291  param = parameter_name
1292 
1293  # check parameters
1294  if not type(param) is list: # check list
1295  message = "No valid parameter for " + component_name + ": not a list, aborting..."
1296  rospy.logerr(message)
1297  print("parameter is:",param)
1298  ah.set_failed(3, message)
1299  return ah
1300  else:
1301  for i in param:
1302  #print i,"type1 = ", type(i)
1303  if not type(i) is str:
1304  message = "No valid parameter for " + component_name + ": not a list of strings, aborting..."
1305  rospy.logerr(message)
1306  print("parameter is:",param)
1307  ah.set_failed(3, message)
1308  return ah
1309  else:
1310  text = text + i + " "
1311  rospy.logdebug("accepted parameter <<%s>> for <<%s>>",i,component_name)
1312  rospy.loginfo("Saying <<%s>>",text)
1313 
1314  # call action server
1315  action_server_name = component_name + "/say"
1316  rospy.logdebug("calling %s action server",action_server_name)
1317  client = actionlib.SimpleActionClient(action_server_name, SayAction)
1318  # trying to connect to server
1319  rospy.logdebug("waiting for %s action server to start",action_server_name)
1320  if not client.wait_for_server(rospy.Duration(1)):
1321  # error: server did not respond
1322  message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
1323  rospy.logerr(message)
1324  ah.set_failed(4, message)
1325  return ah
1326  else:
1327  rospy.logdebug("%s action server ready",action_server_name)
1328 
1329  # sending goal
1330  client_goal = SayGoal()
1331  client_goal.text = text
1332  #print client_goal
1333  client.send_goal(client_goal)
1334  ah.set_client(client)
1335  ah.wait_inside()
1336  return ah
1337 
1338 
1342  def play(self,component_name, parameter_name,blocking=True):
1343  ah = action_handle("play", component_name, parameter_name, False, self.parse)
1344  if(self.parse):
1345  return ah
1346  else:
1347  ah.set_active()
1348 
1349  if not (type(parameter_name) is str or type(parameter_name) is list): # check outer list
1350  message = "No valid parameter for play: not a string or list, aborting..."
1351  rospy.logerr(message)
1352  print("parameter is:",parameter_name)
1353  ah.set_failed(3, message)
1354  return ah
1355 
1356  if type(parameter_name) is str:
1357  full_parameter_name = self.ns_global_prefix + "/" + component_name + "/" + "audio_file_path"
1358  if not rospy.has_param(full_parameter_name):
1359  message = "Parameter " + full_parameter_name + " does not exist on ROS Parameter Server, aborting..."
1360  rospy.logerr(message)
1361  ah.set_failed(2, message)
1362  return ah
1363  filename = rospy.get_param(full_parameter_name) + "/" + parameter_name + ".wav"
1364  elif type(parameter_name) is list:
1365  if len(parameter_name) != 3:
1366  message = "No valid parameter for play: not a list with size 3, aborting..."
1367  rospy.logerr(message)
1368  print("parameter is:",parameter_name)
1369  ah.set_failed(3, message)
1370  return ah
1371  if ((type(parameter_name[0]) is str) and (type(parameter_name[1]) is str) and (type(parameter_name[2]) is str)):
1372  filename = parameter_name[1] + "/" + parameter_name[0] + "." + parameter_name[2]
1373  else:
1374  message = "No valid parameter for play: not a list with [filename, file_path, file_suffix], aborting..."
1375  rospy.logerr(message)
1376  print("parameter is:",parameter_name)
1377  ah.set_failed(3, message)
1378  return ah
1379  else:
1380  rospy.logerr("you should never be here")
1381  rospy.logdebug("accepted parameter %s for play",parameter_name)
1382 
1383  action_server_name = component_name + "/play"
1384  rospy.logdebug("calling %s action server",action_server_name)
1385  client = actionlib.SimpleActionClient(action_server_name, PlayAction)
1386  # trying to connect to server
1387  rospy.logdebug("waiting for %s action server to start",action_server_name)
1388  if not client.wait_for_server(rospy.Duration(1)):
1389  # error: server did not respond
1390  message = "ActionServer " + action_server_name + " not ready within timeout, aborting..."
1391  rospy.logerr(message)
1392  ah.set_failed(4, message)
1393  return ah
1394  else:
1395  rospy.logdebug("%s action server ready",action_server_name)
1396 
1397  # sending goal
1398  rospy.loginfo("Playing <<%s>>",filename)
1399  client_goal = PlayGoal()
1400  client_goal.filename = filename
1401  #print client_goal
1402  client.send_goal(client_goal)
1403  ah.set_client(client)
1404  ah.wait_inside()
1405  ah.set_succeeded()
1406  return ah
1407 
1408  def set_wav_path(self,parameter_name,blocking=True):
1409  ah = action_handle("set_wav_path", "set_wav_path", parameter_name, blocking, self.parse)
1410  if type(parameter_name) is str:
1411  self.wav_path = parameter_name
1412  else:
1413  message = "Invalid wav_path parameter specified, aborting..."
1414  rospy.logerr(message)
1415  print("parameter is:", parameter_name)
1416  ah.set_failed(2, message)
1417  return ah
1418 
1419 #------------------- General section -------------------#
1420 
1424  def sleep(self,duration):
1425  ah = action_handle("sleep", "", str(duration), True, self.parse)
1426  if(self.parse):
1427  return ah
1428  else:
1429  ah.set_active()
1430  rospy.loginfo("Wait for %f sec",duration)
1431  rospy.sleep(duration)
1432  ah.set_succeeded()
1433  return ah
1434 
1435 
1442  def wait_for_input(self,duration=0):
1443  ah = action_handle("wait", "input", str(duration), True, self.parse)
1444  if(self.parse):
1445  return ah
1446  else:
1447  ah.set_active()
1448 
1449  if (duration != 0):
1450  rospy.logerr("Wait with duration not implemented yet") # \todo TODO: implement waiting with duration
1451 
1452  rospy.loginfo("Wait for user input...")
1453  retVal = six.moves.input()
1454  rospy.loginfo("...got string <<%s>>",retVal)
1455  ah.set_succeeded()
1456  return retVal
1457 
1458 #------------------- action_handle section -------------------#
1459 
1463 
1464  def __init__(self, function_name, component_name, parameter_name, blocking, parse):
1465  global graph
1466  self.parent_node = ""
1467  self.error_code = -1
1468  self.success = False
1469  self.message = ""
1470  self.function_name = function_name
1471  self.component_name = component_name
1472  self.parameter_name = parameter_name
1473  self.state = ScriptState.UNKNOWN
1474  self.blocking = blocking
1475  self.parse = parse
1476  self.level = int(rospy.get_param("/script_server/level",100))
1477  self.state_pub = rospy.Publisher("/script_server/state", ScriptState, queue_size=1)
1478  self.AppendNode(blocking)
1479  self.client = None
1480  self.client_state = GoalStatus.LOST
1481  self.client_mode = ""
1482 
1483 
1484  def set_client(self,client):
1485  self.client = client
1486 
1487 
1488  def set_active(self,mode=""):
1489  if mode != "": # not processing an actionlib client
1490  self.client_mode = mode
1491  self.client_state = GoalStatus.ACTIVE
1492  self.check_pause()
1493  self.state = ScriptState.ACTIVE
1494  self.error_code = -1
1495  self.PublishState()
1496 
1497  global ah_counter
1498  ah_counter += 1
1499 
1500 
1501  def check_pause(self):
1502  param_string = "/script_server/pause"
1503  while bool(rospy.get_param(param_string,False)):
1504  rospy.logwarn("Script is paused...")
1505  self.state = ScriptState.PAUSED
1506  self.PublishState()
1507  rospy.sleep(1)
1508  if self.state == ScriptState.PAUSED:
1509  rospy.loginfo("...continuing script")
1510 
1511 
1512  def set_succeeded(self,message=""):
1513  if self.client_mode != "": # not processing an actionlib client
1514  self.client_state = GoalStatus.SUCCEEDED
1515  self.state = ScriptState.SUCCEEDED
1516  self.error_code = 0
1517  self.success = True
1518  self.message = message
1519  self.PublishState()
1520 
1521  global ah_counter
1522  ah_counter -= 1
1523 
1524 
1525  def set_failed(self,error_code,message=""):
1526  if self.client_mode != "": # not processing an actionlib client
1527  self.client_state = GoalStatus.ABORTED
1528  self.state = ScriptState.FAILED
1529  self.error_code = error_code
1530  self.success = False
1531  self.message = message
1532  self.PublishState()
1533 
1534  global ah_counter
1535  ah_counter -= 1
1536 
1537 
1538  def get_state(self):
1539  if self.client_mode != "": # not processing an actionlib client
1540  return self.client_state
1541  elif self.client == None:
1542  return GoalStatus.LOST
1543  else:
1544  return self.client.get_state()
1545 
1546 
1547  def get_error_code(self):
1548  return self.error_code
1549 
1550 
1551  def GetGraphstring(self):
1552  if type(self.parameter_name) is str:
1553  graphstring = str(datetime.datetime.utcnow())+"_"+self.function_name+"_"+self.component_name+"_"+self.parameter_name
1554  else:
1555  graphstring = str(datetime.datetime.utcnow())+"_"+self.function_name+"_"+self.component_name
1556  return graphstring
1557 
1558 
1559  def GetLevel(self,function_name):
1560  if (function_name == "move"):
1561  level = 0
1562  elif (function_name == "init"):
1563  level = 1
1564  elif (function_name == "stop"):
1565  level = 1
1566  elif (function_name == "sleep"):
1567  level = 2
1568  else:
1569  level = 100
1570  return level
1571 
1572 
1573  def AppendNode(self, blocking=True):
1574  global graph
1575  global graph_wait_list
1576  global last_node
1577  graphstring = self.GetGraphstring()
1578  if self.parse:
1579  if ( self.level >= self.GetLevel(self.function_name)):
1580  #print "adding " + graphstring + " to graph"
1581  graph.add_edge(last_node, graphstring)
1582  for waiter in graph_wait_list:
1583  graph.add_edge(waiter, graphstring)
1584  graph_wait_list=[]
1585  if blocking:
1586  last_node = graphstring
1587  else:
1588  self.parent_node = graphstring
1589  #else:
1590  #print "not adding " + graphstring + " to graph"
1591  #else:
1592  #self.PublishState()
1593 
1594 
1595  def PublishState(self):
1596  script_state = ScriptState()
1597  script_state.header.stamp = rospy.Time.now()
1598  script_state.function_name = self.function_name
1599  script_state.component_name = self.component_name
1600  script_state.full_graph_name = self.GetGraphstring()
1601  if ( type(self.parameter_name) is str ):
1602  script_state.parameter_name = self.parameter_name
1603  else:
1604  script_state.parameter_name = ""
1605  script_state.state = self.state
1606  script_state.error_code = self.error_code
1607  self.state_pub.publish(script_state)
1608 
1609 
1614  def wait(self, duration=None):
1615  global ah_counter
1616  ah_counter += 1
1617  self.blocking = True
1618  self.wait_for_finished(duration,True)
1619 
1620 
1625  def wait_inside(self, duration=None):
1626  if self.blocking:
1627  self.wait_for_finished(duration,True)
1628  else:
1629  Thread(target=self.wait_for_finished, args=(duration,False,)).start()
1630  return self.error_code
1631 
1632 
1638  def wait_for_finished(self, duration, logging):
1639  global graph_wait_list
1640  if(self.parse):
1641  if(self.parent_node != ""):
1642  graph_wait_list.append(self.parent_node)
1643  return
1644 
1645  if self.error_code <= 0:
1646  if duration is None:
1647  if logging:
1648  rospy.loginfo("Wait for <<%s>> reaching <<%s>>...",self.component_name, self.parameter_name)
1649  self.client.wait_for_result()
1650  else:
1651  if logging:
1652  rospy.loginfo("Wait for <<%s>> reached <<%s>> (max %f secs)...",self.component_name, self.parameter_name,duration)
1653  if not self.client.wait_for_result(rospy.Duration(duration)):
1654  message = "Timeout while waiting for <<%s>> to reach <<%s>>. Continuing..."%(self.component_name, self.parameter_name)
1655  if logging:
1656  rospy.logerr(message)
1657  self.set_failed(10, message)
1658  return
1659  # check state of action server
1660  #print self.client.get_state()
1661  if self.client.get_state() != GoalStatus.SUCCEEDED:
1662  message = "...<<%s>> could not reach <<%s>>, aborting..."%(self.component_name, self.parameter_name)
1663  if logging:
1664  rospy.logerr(message)
1665  self.set_failed(11, message)
1666  return
1667  if logging:
1668  rospy.loginfo("...<<%s>> reached <<%s>>",self.component_name, self.parameter_name)
1669  else:
1670  message = "Execution of <<%s>> to <<%s>> was aborted, wait not possible. Continuing..."%(self.component_name, self.parameter_name)
1671  rospy.logwarn(message)
1672  self.set_failed(self.error_code, message)
1673  return
1674 
1675  self.set_succeeded() # full success
1676 
1677 
1680  def cancel(self):
1681  self.client.cancel_all_goals()
def string_action(self, component_name, data, blocking)
Allows to trigger actions of the type cob_actions/SetString.
def calculate_point_time(self, start_pos, end_pos, default_vel, default_acc)
def recover(self, component_name, blocking=True)
Recovers different components.
def say(self, component_name, parameter_name, blocking=True)
Say some text.
def halt(self, component_name, blocking=True)
Halts different components.
def get_error_code(self)
Gets the error code of an action handle.
def _determine_desired_velocity(self, default_vel, start_pos, component_name, joint_names, speed_factor, urdf_vel)
def Parse(self)
Function to generate graph view of script.
def wait_for_finished(self, duration, logging)
Waits for the action to be finished.
def move_traj(self, component_name, parameter_name, blocking, speed_factor=1.0, urdf_vel=False, default_vel=None, stop_at_waypoints=False)
Deals with all kind of trajectory movements for different components.
def set_mimic(self, component_name, parameter_name, blocking=False)
Set the mimic of the cob_mimic component.
def AppendNode(self, blocking=True)
Appends a registered function to the graph.
def Start(self)
Function to start the script.
def trigger_action(self, component_name, action_name, blocking=True)
Allows to trigger actions of the type actionlib/TestAction.
def move_rel(self, component_name, parameter_name, blocking=True, speed_factor=1.0, urdf_vel=False, default_vel=None, stop_at_waypoints=False)
Relative movement Deals with all kind of relative movements for different components.
def Run(self)
Dummy function for main run function.
def get_state(self)
Gets the state of an action handle.
def init(self, component_name, blocking=True)
Initializes different components.
def set_active(self, mode="")
Sets the execution state to active, if not paused.
def play(self, component_name, parameter_name, blocking=True)
Play a sound file.
def stop(self, component_name, mode="omni", blocking=True)
Stops different components.
def wait_for_input(self, duration=0)
Waits for user input.
def calculate_point_velocities(self, prev, curr, post, stop_at_waypoints=False)
def move(self, component_name, parameter_name, blocking=True, mode=None, speed_factor=1.0, urdf_vel=False, default_vel=None, stop_at_waypoints=False)
Deals with all kind of movements for different components.
Script class from which all script inherit.
def compose_color(self, component_name, parameter_name)
Set the color of the cob_light component.
def set_client(self, client)
Sets the actionlib client.
def Initialize(self)
Dummy function for initialization.
def __init__(self, parse=False)
Initializes simple_script_server class.
def move_base_rel(self, component_name, parameter_name=[0, blocking=True)
Relative movement of the base.
def PublishState(self)
Publishs the state of the action handle.
def compose_trajectory(self, component_name, parameter_name, speed_factor=1.0, urdf_vel=False, default_vel=None, stop_at_waypoints=False)
Parse and compose trajectory message.
def set_failed(self, error_code, message="")
Sets the execution state to failed.
def trigger(self, component_name, service_name, blocking=True)
Deals with all kind of trigger services for different components.
def GetLevel(self, function_name)
Gets level of function name.
def wait_inside(self, duration=None)
Handles inside wait.
def __init__(self, function_name, component_name, parameter_name, blocking, parse)
Initializes the action handle.
def move_base(self, component_name, parameter_name, blocking, mode)
Deals with movements of the base.
def set_light(self, component_name, parameter_name, blocking=False)
def set_succeeded(self, message="")
Sets the execution state to succeeded.


cob_script_server
Author(s): Florian Weisshardt
autogenerated on Tue May 2 2023 02:26:05