WUT Velma robot API
velma_interface.py
Go to the documentation of this file.
1 
4 
5 # Copyright (c) 2014, Robot Control and Pattern Recognition Group, Warsaw University of Technology
6 # All rights reserved.
7 #
8 # Redistribution and use in source and binary forms, with or without
9 # modification, are permitted provided that the following conditions are met:
10 # * Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # * Redistributions in binary form must reproduce the above copyright
13 # notice, this list of conditions and the following disclaimer in the
14 # documentation and/or other materials provided with the distribution.
15 # * Neither the name of the Warsaw University of Technology nor the
16 # names of its contributors may be used to endorse or promote products
17 # derived from this software without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 # DISCLAIMED. IN NO EVENT SHALL <COPYright HOLDER> BE LIABLE FOR ANY
23 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 import rospy
31 import tf
32 import tf2_ros
33 import math
34 import time
35 import copy
36 import threading
37 from functools import partial
38 import PyKDL
39 
40 from std_msgs.msg import Int32
41 from geometry_msgs.msg import Wrench, Vector3, Twist
42 from sensor_msgs.msg import JointState
43 from barrett_hand_msgs.msg import *
44 from barrett_hand_action_msgs.msg import *
46 from motor_action_msgs.msg import *
47 from grasped_action_msgs.msg import *
49 from behavior_switch_action_msgs.msg import BehaviorSwitchAction, BehaviorSwitchGoal
50 import actionlib
51 from trajectory_msgs.msg import JointTrajectory, JointTrajectoryPoint
52 from control_msgs.msg import FollowJointTrajectoryAction, FollowJointTrajectoryResult,\
53  FollowJointTrajectoryGoal, JointTolerance
54 from velma_look_at_action_msgs.msg import LookAtAction, LookAtGoal, LookAtResult
55 import diagnostic_msgs.msg
56 import tf_conversions.posemath as pm
57 
58 import subsystem_common
59 
60 import xml.dom.minidom as minidom
61 
62 # Do not use rospy.sleep(), because it hangs when simulation is stopped or terminated.
63 
64 def getSymmetricalJointName(joint_name):
65  """!
66  For joint names that refer to joints that are symmetrical (*left* or *right*), get the name
67  of the another joint.
68 
69  @param joint_name string: name of joint.
70 
71  @return name of the joint symmetrical to joint_name, or None, if such does not exist.
72  """
73  if joint_name.startswith('left'):
74  return 'right' + joint_name[4:]
75  elif joint_name.startswith('right'):
76  return 'left' + joint_name[5:]
77  return None
78 
80  """!
81  Get configuration based on the input configuration such that all joint positions are symmetrical.
82 
83  @param q_map Dictionary: configuration {joint_name:joint_position}.
84 
85  @return Dictionary with symmetrical configuration.
86  """
87  result = {}
88  for joint_name in q_map:
89  assert not joint_name in result
90  result[joint_name] = q_map[joint_name]
91  sym_joint_name = getSymmetricalJointName(joint_name)
92  if not sym_joint_name is None:
93  assert not sym_joint_name in result
94  result[sym_joint_name] = -q_map[joint_name]
95  return result
96 
97 def isConfigurationClose(q_map1, q_map2, tolerance=0.1, allow_subset=False):
98  """!
99  Check if two configurations of robot body are close within tolerance.
100 
101  @param q_map1 dictionary: Dictionary {name:position} that maps joint names to their positions.
102  @param q_map2 dictionary: Dictionary {name:position} that maps joint names to their positions.
103 
104  @return True if two configurations are close within tolerance (for every joint), False otherwise.
105 
106  @exception KeyError: Either q_map1 or q_map2 dictionaries does not contain required key, i.e. one
107  of robot body joint names.
108  """
109  joint_names = ['torso_0_joint', 'right_arm_0_joint', 'right_arm_1_joint',
110  'right_arm_2_joint', 'right_arm_3_joint', 'right_arm_4_joint', 'right_arm_5_joint',
111  'right_arm_6_joint', 'left_arm_0_joint', 'left_arm_1_joint', 'left_arm_2_joint',
112  'left_arm_3_joint', 'left_arm_4_joint', 'left_arm_5_joint', 'left_arm_6_joint']
113 
114  for joint_name in joint_names:
115  if allow_subset and (not joint_name in q_map1 or not joint_name in q_map2):
116  continue
117  if abs(q_map1[joint_name] - q_map2[joint_name]) > tolerance:
118  return False
119  return True
120 
121 def isHeadConfigurationClose(q1, q2, tolerance=0.1):
122  """!
123  Check if two configurations of robot neck are close within tolerance.
124 
125  @param q1 tuple: 2-tuple of neck joints positions.
126  @param q2 tuple: 2-tuple of neck joints positions.
127 
128  @return True if two configurations are close within tolerance (for every joint), False otherwise.
129  """
130  return abs(q1[0]-q2[0]) < tolerance and abs(q1[1]-q2[1]) < tolerance
131 
132 def isHandConfigurationClose(current_q, dest_q, tolerance=0.1):
133  """!
134  Check if two configurations of robot hand are close within tolerance.
135 
136  @param current_q tuple: 8-tuple of hand joints positions.
137  @param dest_q tuple: 4-tuple of hand DOFs positions.
138 
139  @return True if two configurations are close within tolerance (for every joint), False otherwise.
140  """
141  return abs(current_q[0]-dest_q[3]) < tolerance and\
142  abs(current_q[1]-dest_q[0]) < tolerance and\
143  abs(current_q[4]-dest_q[1]) < tolerance and\
144  abs(current_q[6]-dest_q[2]) < tolerance
145 
146 def splitTrajectory(joint_trajectory, max_traj_len):
147  """!
148  Split a long trajectory into a number of shorter trajectories.
149 
150  @param joint_trajectory trajectory_msgs.msg.JointTrajectory: A joint trajectory to be splitted.
151  @param max_traj_len int: Maximum number of nodes in the result trajectory.
152  @return Returns list of trajectory_msgs.msg.JointTrajectory -- the input trajectory split
153  into a number of trajectories of length not greater than max_traj_len.
154  """
155  assert isinstance(joint_trajectory, JointTrajectory)
156  if len(joint_trajectory.points) > max_traj_len:
157  result = []
158  #for idx in range(0, len(traj.trajectory.joint_trajectory.points), max_traj_len):
159  idx = 0
160  new_traj = JointTrajectory()
161  new_traj.header = joint_trajectory.header
162  new_traj.joint_names = joint_trajectory.joint_names
163  time_base = rospy.Duration(0.0)
164  for idx in range(len(joint_trajectory.points)):
165  point = copy.copy( joint_trajectory.points[idx] )
166  point.time_from_start = point.time_from_start - time_base
167  new_traj.points.append( point )
168  if len(new_traj.points) >= max_traj_len:
169  result.append( new_traj )
170  new_traj = JointTrajectory()
171  new_traj.header = joint_trajectory.header
172  new_traj.joint_names = joint_trajectory.joint_names
173  point = copy.copy( joint_trajectory.points[idx] )
174  time_base = point.time_from_start - rospy.Duration(0.5)
175  point.time_from_start = point.time_from_start - time_base
176  new_traj.points.append( point )
177 
178  if len(new_traj.points) > 0:
179  result.append( new_traj )
180 
181  return result
182  # else
183  return [joint_trajectory]
184 
186  """!
187  ROS-based, Python interface class for WUT Velma Robot.
188 
189  This class implements methods that use ROS topics, actions and services
190  to communicate with velma_task_cs_ros_interface subsystem of velma_task
191  agent.
192  """
193 
194  #
195  # Classes
196  #
197  class VisualMesh:
198  """!
199  This class contains information about geometric object: mesh.
200  """
201  def __init__(self):
202  self.type = "mesh"
203  self.origin = None
204  self.filename = None
205 
206  class Link:
207  """!
208  This class contains information about single link of robot.
209  """
210  def __init__(self):
211  self.name = None
212  self.visuals = []
213 
214  #
215  # Private data
216  #
217  _frames = {
218  'Wo':'world',
219  'B':'torso_base',
220  'Wr':'right_arm_7_link',
221  'wrist_right':'right_arm_7_link',
222  'Wl':'left_arm_7_link',
223  'wrist_left':'left_arm_7_link',
224  'Er':'right_arm_7_link',
225  'El':'left_arm_7_link',
226  'Wright':'right_arm_7_link',
227  'Wleft':'left_arm_7_link',
228  'Gr':'right_HandGripLink',
229  'grip_right':'right_HandGripLink',
230  'Gl':'left_HandGripLink',
231  'grip_left':'left_HandGripLink',
232  'Pr':'right_HandPalmLink',
233  'Pl':'left_HandPalmLink',
234  'Tr':'right_arm_tool',
235  'Tl':'left_arm_tool',
236  'Tright':'right_arm_tool',
237  'Tleft':'left_arm_tool',
238  'Fr00':'right_HandFingerOneKnuckleOneLink',
239  'Fr01':'right_HandFingerOneKnuckleTwoLink',
240  'Fr02':'right_HandFingerOneKnuckleThreeLink',
241  'Fr10':'right_HandFingerTwoKnuckleOneLink',
242  'Fr11':'right_HandFingerTwoKnuckleTwoLink',
243  'Fr12':'right_HandFingerTwoKnuckleThreeLink',
244  'Fr21':'right_HandFingerThreeKnuckleTwoLink',
245  'Fr22':'right_HandFingerThreeKnuckleThreeLink',
246  'Fl00':'left_HandFingerOneKnuckleOneLink',
247  'Fl01':'left_HandFingerOneKnuckleTwoLink',
248  'Fl02':'left_HandFingerOneKnuckleThreeLink',
249  'Fl10':'left_HandFingerTwoKnuckleOneLink',
250  'Fl11':'left_HandFingerTwoKnuckleTwoLink',
251  'Fl12':'left_HandFingerTwoKnuckleThreeLink',
252  'Fl21':'left_HandFingerThreeKnuckleTwoLink',
253  'Fl22':'left_HandFingerThreeKnuckleThreeLink',
254  }
255 
256  _cartesian_trajectory_result_names = {
257  CartImpResult.SUCCESSFUL:'SUCCESSFUL',
258  CartImpResult.INVALID_GOAL:'INVALID_GOAL',
259  CartImpResult.OLD_HEADER_TIMESTAMP:'OLD_HEADER_TIMESTAMP',
260  CartImpResult.PATH_TOLERANCE_VIOLATED:'PATH_TOLERANCE_VIOLATED',
261  CartImpResult.GOAL_TOLERANCE_VIOLATED:'GOAL_TOLERANCE_VIOLATED',
262  CartImpResult.UNKNOWN_ERROR:'UNKNOWN_ERROR' }
263 
264  _joint_trajectory_result_names = {
265  FollowJointTrajectoryResult.SUCCESSFUL:"SUCCESSFUL",
266  FollowJointTrajectoryResult.INVALID_GOAL:"INVALID_GOAL",
267  FollowJointTrajectoryResult.INVALID_JOINTS:"INVALID_JOINTS",
268  FollowJointTrajectoryResult.OLD_HEADER_TIMESTAMP:"OLD_HEADER_TIMESTAMP",
269  FollowJointTrajectoryResult.PATH_TOLERANCE_VIOLATED:"PATH_TOLERANCE_VIOLATED",
270  FollowJointTrajectoryResult.GOAL_TOLERANCE_VIOLATED:"GOAL_TOLERANCE_VIOLATED" }
271 
272  _look_at_result_names = {
273  LookAtResult.SUCCESSFUL:'SUCCESSFUL',
274  LookAtResult.OUT_OF_RANGE:'OUT_OF_RANGE',
275  LookAtResult.WRONG_BEHAVIOUR:'WRONG_BEHAVIOUR',
276  LookAtResult.MOTION_FAILED:'MOTION_FAILED' }
277 
278  _moveHand_action_error_codes_names = {
279  0:"SUCCESSFUL",
280  -1:"INVALID_DOF_NAME",
281  -2:"INVALID_GOAL",
282  -3:"CURRENT_LIMIT",
283  -4:"PRESSURE_LIMIT",
284  -5:"RESET_IS_ACTIVE"}
285 
286  _core_ve_name = "/velma_core_ve_body"
287  _core_cs_name = "/velma_core_cs"
288  _task_cs_name = "/velma_task_cs_ros_interface"
289 
290  _joint_groups = {
291  "impedance_joints":['torso_0_joint', 'right_arm_0_joint', 'right_arm_1_joint',
292  'right_arm_2_joint', 'right_arm_3_joint', 'right_arm_4_joint', 'right_arm_5_joint',
293  'right_arm_6_joint', 'left_arm_0_joint', 'left_arm_1_joint', 'left_arm_2_joint',
294  'left_arm_3_joint', 'left_arm_4_joint', 'left_arm_5_joint', 'left_arm_6_joint'],
295  "right_arm":['right_arm_0_joint', 'right_arm_1_joint', 'right_arm_2_joint',
296  'right_arm_3_joint', 'right_arm_4_joint', 'right_arm_5_joint', 'right_arm_6_joint'],
297  "right_arm_torso":['torso_0_joint', 'right_arm_0_joint', 'right_arm_1_joint',
298  'right_arm_2_joint', 'right_arm_3_joint', 'right_arm_4_joint', 'right_arm_5_joint',
299  'right_arm_6_joint'],
300  "left_arm":['left_arm_0_joint', 'left_arm_1_joint', 'left_arm_2_joint', 'left_arm_3_joint',
301  'left_arm_4_joint', 'left_arm_5_joint', 'left_arm_6_joint'],
302  "left_arm_torso":['torso_0_joint', 'left_arm_0_joint', 'left_arm_1_joint',
303  'left_arm_2_joint', 'left_arm_3_joint', 'left_arm_4_joint', 'left_arm_5_joint',
304  'left_arm_6_joint'],
305  "head":["head_pan_joint", "head_tilt_joint"]
306  }
307 
308  def getLastJointState(self):
309  """!
310  Get the newest joint state.
311 
312  @return (rospy.Time, dictionary): A Pair of timestamp of the newest joint state and dictionary
313  (with key=joint_name, value=joint_position), or None if there is no joint state data yet.
314 
315  """
316  with self._joint_states_lock:
317  if self._js_pos_history_idx >= 0:
318  return copy.copy(self._js_pos_history[self._js_pos_history_idx])
319  return None
320 
321  def getJointStateAtTime(self, time):
322  """!
323  Get interpolated joint state at a given time.
324 
325  @param time rospy.Time: Time of joint state to be computed.
326 
327  @return dictionary: A dictionary (with key=joint_name, value=joint_position) of interpolated joint positions
328  or None, if time is not within current joint state history.
329 
330  """
331  with self._joint_states_lock:
332  if self._js_pos_history_idx < 0:
333  return None
334 
335  hist_len = len(self._js_pos_history)
336  for step in range(hist_len-1):
337  h1_idx = (self._js_pos_history_idx - step - 1) % hist_len
338  h2_idx = (self._js_pos_history_idx - step) % hist_len
339  if self._js_pos_history[h1_idx] == None or self._js_pos_history[h2_idx] == None:
340  return None
341 
342  time1 = self._js_pos_history[h1_idx][0]
343  time2 = self._js_pos_history[h2_idx][0]
344  if time > time1 and time <= time2:
345  factor = (time - time1).to_sec() / (time2 - time1).to_sec()
346  js_pos = {}
347  for joint_name in self._js_pos_history[h1_idx][1]:
348  js_pos[joint_name] = self._js_pos_history[h1_idx][1][joint_name] * (1.0 - factor) + self._js_pos_history[h2_idx][1][joint_name] * factor
349  return js_pos
350  return None
351 
352  # Private method used as callback for joint_states ROS topic.
353  def _jointStatesCallback(self, data):
354  with self._joint_states_lock:
355  js_pos = {}
356  for joint_idx, joint_name in enumerate(data.name):
357  js_pos[joint_name] = data.position[joint_idx]
358 
359  self._js_pos_history_idx = (self._js_pos_history_idx + 1) % len(self._js_pos_history)
360  self._js_pos_history[self._js_pos_history_idx] = (data.header.stamp, copy.copy(js_pos))
361 
362  def getHandCurrentConfiguration(self, prefix):
363  """!
364  Get current configuration of a specified hand.
365 
366  @param prefix string: Hand name, can be one of two values ('left' or 'right').
367 
368  @return An 8-tuple of positions of all joints of the specified hand,
369  or None if there is no valid joint state data. The sequence
370  of joint positions is: FingerOneKnuckleOneJoint, FingerOneKnuckleTwoJoint,
371  FingerOneKnuckleThreeJoint, FingerTwoKnuckleOneJoint, FingerTwoKnuckleTwoJoint,
372  FingerTwoKnuckleThreeJoint, FingerThreeKnuckleTwoJoint,
373  FingerThreeKnuckleThreeJoint.
374 
375  @exception NameError: If prefix is not 'left' or 'right'.
376  """
377  if prefix != 'left' and prefix != 'right':
378  raise NameError('wrong prefix: ' + str(prefix))
379  js = self.getLastJointState()
380  if js == None:
381  return None
382  q = ( js[1][prefix+'_HandFingerOneKnuckleOneJoint'],
383  js[1][prefix+'_HandFingerOneKnuckleTwoJoint'],
384  js[1][prefix+'_HandFingerOneKnuckleThreeJoint'],
385  js[1][prefix+'_HandFingerTwoKnuckleOneJoint'],
386  js[1][prefix+'_HandFingerTwoKnuckleTwoJoint'],
387  js[1][prefix+'_HandFingerTwoKnuckleThreeJoint'],
388  js[1][prefix+'_HandFingerThreeKnuckleTwoJoint'],
389  js[1][prefix+'_HandFingerThreeKnuckleThreeJoint'] )
390  return q
391 
393  """!
394  Get current configuration of left hand.
395 
396  @return tuple: An 8-tuple of positions of all joints of left hand,
397  or None if there is no valid joint state data.
398 
399  @see getHandCurrentConfiguration
400  """
401  return self.getHandCurrentConfiguration("left")
402 
404  """!
405  Get current configuration of right hand.
406 
407  @return tuple: An 8-tuple of positions of all joints of right hand,
408  or None if there is no valid joint state data.
409 
410  @see getHandCurrentConfiguration
411 
412  """
413  return self.getHandCurrentConfiguration("right")
414 
416  """!
417  Get current configuration of neck.
418 
419  @return tuple: A 2-tuple of positions of neck joints,
420  or None if there is no valid joint state data.
421  """
422  js = self.getLastJointState()
423  if js == None:
424  return None
425  q = ( js[1]["head_pan_joint"],
426  js[1]["head_tilt_joint"] )
427  return q
428 
429  def __isActionConnected(self, action_name):
430  self.dbgPrint('__isActionConnected: "{}"'.format(action_name))
431 
432  with self.__action_is_connected_lock:
433  if action_name in self.__action_is_connected:
434  is_connected = self.__action_is_connected[action_name]
435  else:
436  is_connected = False
437  return is_connected
438 
439  def __connectAction(self, action_name, action, timeout_s):
440  self.dbgPrint('__connectAction: wait for server "{}"'.format(action_name))
441  is_connected = action.wait_for_server(rospy.Duration(timeout_s))
442  self.dbgPrint('__connectAction: "{}", connected: {}'.format(action_name, is_connected))
443  with self.__action_is_connected_lock:
444  self.__action_is_connected[action_name] = is_connected
445 
446  def __getDiagInfo(self, timeout_s):
447  self.__received_diag_info = False
448  time_start = time.time()
449  while not rospy.is_shutdown():
450  try:
451  diag = self.getCoreCsDiag()
452  if len(diag.history) > 0:
453  self.__received_diag_info = True
454  return
455  except:
456  pass
457  time.sleep(0.1)
458  time_now = time.time()
459  if timeout_s and (time_now-time_start) > timeout_s:
460  break
461 
462  def __isInitialized(self):
463  for action_name in self.__action_map:
464  if not self.__action_obligatory_map[action_name]:
465  continue
466  if not self.__isActionConnected(action_name):
467  return False
468  if not self.__received_diag_info:
469  return False
470  if self._js_pos_history_idx < 0:
471  return False
472  return True
473 
474  def waitForInit(self, timeout_s=None):
475  """!
476  Wait for the interface until it is initialized.
477 
478  @param timeout_s float: Timeout in seconds.
479 
480  @return True if the interface was succesfully initialized within timeout, False otherwise.
481  """
482  self.dbgPrint('Waiting for init')
483 
484  self.dbgPrint('Getting ROS parameters')
485  if not self.__tryGetRosParams():
486  self.dbgPrint('Could not get all ROS parameters')
487  return False
488  self.dbgPrint('Got all ROS parameters')
489 
490  time_start = time.time()
491  if timeout_s is None:
492  timeout_s = 10.0
493 
494  self.__action_is_connected_lock = threading.Lock()
495  self.__action_is_connected = {}
496  threads = []
497  for action_name, action in self.__action_map.iteritems():
498  self.dbgPrint('Running thread for connecting action "{}"'.format(action_name))
499 
500  t = threading.Thread(name='action-{}'.format(action_name),
501  target=self.__connectAction, args=(action_name, action, timeout_s))
502  t.daemon = True # thread dies with the program
503  t.start()
504  threads.append( (action_name, t) )
505 
506  t = threading.Thread(name='get-diag-info',
507  target=self.__getDiagInfo, args=(timeout_s,))
508  t.start()
509  threads.append( (None, t) )
510 
511  for action_name, t in threads:
512  self.dbgPrint('Joining thread for connecting action "{}"'.format(action_name))
513  if action_name is None or self.__action_obligatory_map[action_name]:
514  t.join()
515 
516  self.dbgPrint('Waiting for full initialization')
517  while (time.time()-time_start) < timeout_s:
518  if self.__isInitialized():
519  break
520  time.sleep(0.1)
521 
522  if not self.__isInitialized():
523  print("ERROR: waitForInit: timeout")
524  for action_name in self.__action_map:
525  if not action_name in self.__action_is_connected:
526  print(' is_action_connected({}): information is missing'.format(action_name))
527  else:
528  print(' is_action_connected({}): {}'.format(action_name,
529  self.__action_is_connected[action_name]))
530 
531  print(' joint_state_received: {}'.format(self._js_pos_history_idx >= 0))
532  print(' received_diag_info: {}'.format(self.__received_diag_info))
533  self.dbgPrint('Failed to initialize')
534  return False
535  self.dbgPrint('Initialized')
536  return True
537 
538  def waitForJointState(self, abs_time):
539  """!
540  Wait for reception of joint state ROS msg with time stamp greater or equal abs_time
541 
542  @param abs_time rospy.Time: absolute time.
543 
544  @return Returns True.
545  """
546  while not rospy.is_shutdown():
547  js = self.getLastJointState()
548  if (js[0] - abs_time).to_sec() > 0:
549  break
550  time.sleep(0.1)
551  return True
552 
554  """!
555  Gets limits of joints of both arms and torso.
556  Joints of neck and grippers are not included.
557  The joints are used in impedance control (both joint and cartesian).
558 
559  @return dictionary: Returns a dictionary {name:(lower_limit, upper_limit)} that maps joint name to
560  a 2-tupe with lower and upper joint limit.
561  """
562  return self._body_joint_limits
563 
565  """!
566  Gets limits of joints of both arms and torso in cart_imp mode.
567  Joints of neck and grippers are not included.
568  The joints are used in impedance control (cart_imp mode).
569 
570  @return dictionary: Returns a dictionary {name:(lower_limit, upper_limit, [lower_limit, upper_limit)])} that maps joint name to
571  a 2-tupe or 4-tupe with lower and upper joint limit.
572  """
573  return self._cimp_joint_limits_map
574 
576  """!
577  Gets limits of joints of neck.
578 
579  @return dictionary: Returns a dictionary {name:(lower_limit, upper_limit)} that maps joint name to
580  a 2-tupe with lower and upper joint limit.
581  """
582  return self._head_joint_limits
583 
584  def __tryGetRosParams(self):
585  try:
586  if self._body_joint_names is None:
587  self.dbgPrint('Getting ROS parameter: {}/JntImpAction/joint_names'.format(self._task_cs_name))
588  self._body_joint_names = rospy.get_param(self._task_cs_name+"/JntImpAction/joint_names")
589  if len(self._body_joint_names) != 15:
590  raise RuntimeError("Wrong number of joints")
591 
592  if self._body_joint_limits is None:
593  # body_joint_lower_limits = rospy.get_param(self._task_cs_name+"/JntImpAction/lower_limits")
594  # body_joint_upper_limits = rospy.get_param(self._task_cs_name+"/JntImpAction/upper_limits")
595  # if not body_joint_lower_limits is None and not body_joint_upper_limits is None:
596  # self._body_joint_limits = {}
597  # for i in range(len(self._body_joint_names)):
598  # self._body_joint_limits[self._body_joint_names[i]] = (body_joint_lower_limits[i], body_joint_upper_limits[i])
599 
600  # TODO: read limits from URDF
601  self._body_joint_limits = {
602  "torso_0_joint": (-1.57, 1.57),
603  "right_arm_0_joint": (-2.96706, 2.96706),
604  "right_arm_1_joint": (-2.0944, 2.0944),
605  "right_arm_2_joint": (-2.96706, 2.96706),
606  "right_arm_3_joint": (-2.0944, 2.0944),
607  "right_arm_4_joint": (-2.96706, 2.96706),
608  "right_arm_5_joint": (-2.0944, 2.0944),
609  "right_arm_6_joint": (-2.96706, 2.96706),
610  "left_arm_0_joint": (-2.96706, 2.96706),
611  "left_arm_1_joint": (-2.0944, 2.0944),
612  "left_arm_2_joint": (-2.96706, 2.96706),
613  "left_arm_3_joint": (-2.0944, 2.0944),
614  "left_arm_4_joint": (-2.96706, 2.96706),
615  "left_arm_5_joint": (-2.0944, 2.0944),
616  "left_arm_6_joint": (-2.96706, 2.96706),
617  }
618 
619  if self._cimp_joint_limits_map is None:
620  self.dbgPrint('Getting ROS parameter: {}/JntLimit/joint_names'.format(self._core_cs_name))
621  joint_names = rospy.get_param(self._core_cs_name+"/JntLimit/joint_names")
622  if not joint_names is None:
623  self._cimp_joint_limits_map = {}
624  for idx, joint_name in enumerate(joint_names):
625  self.dbgPrint('Getting ROS parameter: {}/JntLimit/limits_{}'.format(self._core_cs_name, idx))
626  jnt_limits = rospy.get_param('{}/JntLimit/limits_{}'.format(self._core_cs_name, idx))
627  self._cimp_joint_limits_map[joint_name] = []
628  for lim in jnt_limits:
629  self._cimp_joint_limits_map[joint_name].append( float(lim) )
630 
631  if self._head_joint_names is None:
632  self.dbgPrint('Getting ROS parameter: {}/HeadAction/joint_names'.format(self._task_cs_name))
633  self._head_joint_names = rospy.get_param(self._task_cs_name+"/HeadAction/joint_names")
634 
635  if self._head_joint_limits is None:
636  # head_joint_lower_limits = rospy.get_param(self._task_cs_name+"/HeadAction/lower_limits")
637  # head_joint_upper_limits = rospy.get_param(self._task_cs_name+"/HeadAction/upper_limits")
638  # if not head_joint_lower_limits is None and not head_joint_upper_limits is None:
639  # self._head_joint_limits = {}
640  # for i in range(len(self._head_joint_names)):
641  # self._head_joint_limits[self._head_joint_names[i]] = (head_joint_lower_limits[i], head_joint_upper_limits[i])
642 
643  # TODO: read limits from URDF
644  self._head_joint_limits = {
645  "head_pan_joint": (-1.57, 1.57),
646  "head_tilt_joint": (-1, 1.3),
647  }
648 
649  if self._all_joint_names is None:
650  self.dbgPrint('Getting ROS parameter: {}/JntPub/joint_names'.format(self._task_cs_name))
651  self._all_joint_names = rospy.get_param(self._task_cs_name+"/JntPub/joint_names")
652 
653  if self._all_links is None:
654  self._all_links = []
655 
656  self.dbgPrint('Getting ROS parameter: /robot_description')
657  robot_description_xml = rospy.get_param("/robot_description")
658  #print robot_description_xml
659 
660  self.dbgPrint('parsing robot_description')
661  dom = minidom.parseString(robot_description_xml)
662  robot = dom.getElementsByTagName("robot")
663  if len(robot) != 1:
664  raise Exception("Could not parse robot_description xml: wrong number of 'robot' elements.")
665  links = robot[0].getElementsByTagName("link")
666  for l in links:
667  name = l.getAttribute("name")
668  if name == None:
669  raise Exception("Could not parse robot_description xml: link element has no name.")
670 
671  self.dbgPrint('parsing link "{}"'.format(name))
672 
673  obj_link = self.Link()
674  obj_link.name = name
675 
676  visual = l.getElementsByTagName("visual")
677  for v in visual:
678  origin = v.getElementsByTagName("origin")
679  if len(origin) != 1:
680  raise Exception("Could not parse robot_description xml: wrong number of origin elements in link " + name)
681  rpy = origin[0].getAttribute("rpy").split()
682  xyz = origin[0].getAttribute("xyz").split()
683  frame = PyKDL.Frame(PyKDL.Rotation.RPY(float(rpy[0]), float(rpy[1]), float(rpy[2])), PyKDL.Vector(float(xyz[0]), float(xyz[1]), float(xyz[2])))
684  geometry = v.getElementsByTagName("geometry")
685  if len(geometry) != 1:
686  raise Exception("Could not parse robot_description xml: wrong number of geometry elements in link " + name)
687  mesh = geometry[0].getElementsByTagName("mesh")
688  if len(mesh) == 1:
689  obj_visual = self.VisualMesh()
690  obj_visual.filename = mesh[0].getAttribute("filename")
691  #print "link:", name, " mesh:", obj_visual.filename
692  obj_visual.origin = frame
693  obj_link.visuals.append( obj_visual )
694  else:
695  pass
696  #print "link:", name, " other visual"
697 
698  self._all_links.append(obj_link)
699 
700  if self.__wcc_l_poly is None:
701  self.dbgPrint('Getting ROS parameter: {}/wcc_l/constraint_polygon'.format(self._core_cs_name))
702  self.__wcc_l_poly = rospy.get_param(self._core_cs_name+"/wcc_l/constraint_polygon")
703  if self.__wcc_r_poly is None:
704  self.dbgPrint('Getting ROS parameter: {}/wcc_r/constraint_polygon'.format(self._core_cs_name))
705  self.__wcc_r_poly = rospy.get_param(self._core_cs_name+"/wcc_r/constraint_polygon")
706  except Exception as e:
707  self.dbgPrint('Exception on getting ROS parameters: {}'.format(e))
708 
709  pass
710 
711  if self._body_joint_names is None or\
712  self._body_joint_limits is None or\
713  self._cimp_joint_limits_map is None or\
714  self._head_joint_names is None or\
715  self._head_joint_limits is None or\
716  self._all_joint_names is None or\
717  self._all_links is None or\
718  self.__wcc_l_poly is None or\
719  self.__wcc_r_poly is None:
720  #self.dbgPrint('Getting ROS parameter: {}/wcc_r/constraint_polygon'.format(_core_cs_name))
721 
722  return False
723  return True
724 
725  def dbgPrint(self, s):
726  if self.__debug:
727  print('VelmaInterface: {}'.format(s))
728  time.sleep(0.01)
729 
730  def __init__(self, debug=False):
731  """!
732  Initialization of the interface.
733  """
734  self.__debug = debug
735  self.dbgPrint('Running initializer')
736 
737  self._body_joint_names = None
738  self._body_joint_limits = None
739  self._cimp_joint_limits_map = None
740  self._head_joint_names = None
741  self._head_joint_limits = None
742  self._all_joint_names = None
743  self._all_links = None
744  self.__wcc_l_poly = None
745  self.__wcc_r_poly = None
746 
747  self.dbgPrint('Creating tf listener')
748  self._listener = tf.TransformListener()
749 
750  # read the joint information from the ROS parameter server
751 
752  self._js_pos_history = []
753  for i in range(200):
754  self._js_pos_history.append( None )
755  self._js_pos_history_idx = -1
756 
757  self._joint_states_lock = threading.Lock()
758 
759  # The map of ROS actions:
760  # self.__action_map[name] = (is_obligatory, action_client)
761  self.__action_map = {
762  'jimp':
763  actionlib.SimpleActionClient(
764  "/velma_task_cs_ros_interface/spline_trajectory_action_joint",
765  FollowJointTrajectoryAction),
766  'head':
767  actionlib.SimpleActionClient(
768  "/velma_task_cs_ros_interface/head_spline_trajectory_action_joint",
769  FollowJointTrajectoryAction),
770  'relax':
771  actionlib.SimpleActionClient(
772  "/velma_task_cs_ros_interface/relax_action",
773  BehaviorSwitchAction),
774  'grasped_right':
775  actionlib.SimpleActionClient(
776  "/velma_task_cs_ros_interface/right_arm/grasped_action",
777  GraspedAction),
778  'grasped_left':
779  actionlib.SimpleActionClient(
780  "/velma_task_cs_ros_interface/left_arm/grasped_action",
781  GraspedAction),
782  'identification_right':
783  actionlib.SimpleActionClient(
784  "/velma_task_cs_ros_interface/right_arm/identification_action",
785  IdentificationAction),
786  'identification_left':
787  actionlib.SimpleActionClient(
788  "/velma_task_cs_ros_interface/left_arm/identification_action",
789  IdentificationAction),
790  'hp':
791  actionlib.SimpleActionClient(
792  "/velma_task_cs_ros_interface/motors/hp",
793  MotorAction),
794  'ht':
795  actionlib.SimpleActionClient(
796  "/velma_task_cs_ros_interface/motors/ht",
797  MotorAction),
798  't':
799  actionlib.SimpleActionClient(
800  "/velma_task_cs_ros_interface/motors/t",
801  MotorAction),
802  'hand_right':
803  actionlib.SimpleActionClient(
804  "/velma_task_cs_ros_interface/right_hand/move_hand",
805  BHMoveAction),
806  'hand_left':
807  actionlib.SimpleActionClient(
808  "/velma_task_cs_ros_interface/left_hand/move_hand",
809  BHMoveAction),
810  'cimp_right':
811  actionlib.SimpleActionClient(
812  "/velma_task_cs_ros_interface/right_arm/cartesian_trajectory",
813  CartImpAction),
814  'cimp_left':
815  actionlib.SimpleActionClient(
816  "/velma_task_cs_ros_interface/left_arm/cartesian_trajectory",
817  CartImpAction),
818  'look_at':
819  actionlib.SimpleActionClient(
820  '/velma_look_at_action',
821  LookAtAction),
822  }
823  self.__action_obligatory_map = {}
824  for name in self.__action_map:
825  self.__action_obligatory_map[name] = True
826  self.__action_obligatory_map['look_at'] = False
827 
828  time.sleep(1.0)
829 
830  self.dbgPrint('Creating publisher /velma_task_cs_ros_interface/allow_hands_col_in')
831  self.__pub_allow_hands_col = rospy.Publisher('/velma_task_cs_ros_interface/allow_hands_col_in', Int32, queue_size=10)
832 
833  #self.wrench_tab = []
834  #self.wrench_tab_index = 0
835  #self.wrench_tab_len = 4000
836  #for i in range(0,self.wrench_tab_len):
837  # self.wrench_tab.append( Wrench(Vector3(), Vector3()) )
838 
839  self.dbgPrint('Creating subscriber /joint_states')
840  self._listener_joint_states = rospy.Subscriber('/joint_states', JointState, self._jointStatesCallback)
841 
842  subscribed_topics_list = [
843  ('/right_arm/transformed_wrench', geometry_msgs.msg.Wrench),
844  ('/left_arm/transformed_wrench', geometry_msgs.msg.Wrench),
845  ('/right_arm/wrench', geometry_msgs.msg.Wrench),
846  ('/left_arm/wrench', geometry_msgs.msg.Wrench),
847  ('/right_arm/ft_sensor/wrench', geometry_msgs.msg.Wrench),
848  ('/left_arm/ft_sensor/wrench', geometry_msgs.msg.Wrench),
849  (self._core_ve_name + "/diag", diagnostic_msgs.msg.DiagnosticArray),
850  (self._core_cs_name + "/diag", diagnostic_msgs.msg.DiagnosticArray),]
851 
852  self._subscribed_topics = {}
853 
854  for topic_name, topic_type in subscribed_topics_list:
855  self.dbgPrint('Creating subscriber {}'.format(topic_name))
857  topic_name, topic_type, debug=self.__debug)
858 
859  self.dbgPrint('Initializer function is done')
860 
862  """!
863  Class used for subscription for various ROS topics from the VelmaInterface class.
864 
865  """
866 
867  def dbgPrint(self, s):
868  if self.__debug:
869  print('SubscribedTopic({}): {}'.format(self.__topic_name, s))
870  time.sleep(0.1)
871 
872  def __init__(self, topic_name, topic_type, debug=False):
873  self.__debug = debug
874  self.__mutex = threading.Lock()
875  self.__topic_name = topic_name
876  self.__data = None
877  self.sub = rospy.Subscriber(self.__topic_name, topic_type, self.__callback)
878 
879  def __callback(self, data):
880  #self.dbgPrint('new data')
881  with self.__mutex:
882  self.__data = data
883 
884  def getData(self, timeout_s=None):
885  """!
886  Get the newest topic data.
887 
888  @param timeout_s float: timeout in seconds or None for no timeout. Default is None (no
889  timeout, return immediately).
890 
891  @return Returns the newest data read on topic if it is available, or None otherwise.
892 
893  """
894  #self.dbgPrint('get data')
895 
896  if not timeout_s is None:
897  end_time = rospy.Time.now() + rospy.Duration(timeout_s)
898  result = None
899  while not rospy.is_shutdown():
900  with self.__mutex:
901  if self.__data:
902  result = copy.copy( self.__data )
903  if not result is None or timeout_s is None or rospy.Time.now() >= end_time:
904  return result
905  try:
906  time.sleep(0.1)
907  except:
908  return None
909  return None
910 
911  def _getSubsystemDiag(self, subsystem_name, timeout_s=None):
912  data = self._getTopicData(subsystem_name + "/diag", timeout_s=timeout_s)
913  if data == None:
914  return None
915  for v in data.status[1].values:
916  if v.key == "master_component":
917  mcd = subsystem_common.parseMasterComponentDiag(v.value)
918  return mcd
919  return None
920 
921  class CoreVeBodyDiag(subsystem_common.SubsystemDiag):
922  """!
923  This class contains subsystem-specific diagnostic information for velma_core_cs.
924  """
925  def __init__(self, parent):
926  """!
927  Initialization of diagnostics data using subsystem-independent diagnostics object.
928 
929  @param parent subsystem_common.SubsystemDiag: subsystem-independent diagnostics object.
930  @exception AssertionError Raised when current state name cannot be obtained or state history is not present.
931  """
932 
933  assert (len(parent.history) > 0)
934 
935  self.history = parent.history
936  self.current_predicates = parent.current_predicates
937  self.current_period = parent.current_period
938 
939  self.__current_state = parent.history[0].state_name
940  assert (self.__current_state == "idle" or self.__current_state == "transp" or
941  self.__current_state == "transp_st" or self.__current_state == "safe" or
942  self.__current_state == "safe_st" or self.__current_state == "safe_st_ok")
943 
945  return self.__current_state
946 
948  if self.__current_state == 'idle':
949  return 'idle'
950  elif self.__current_state == 'safe' or self.__current_state == 'safe_st' or\
951  self.__current_state == 'safe_st_ok':
952  return 'safe / safe_st / safe_st_ok'
953  elif self.__current_state == 'transp' or self.__current_state == 'transp_st':
954  return 'transp / transp_st'
955  else:
956  raise Exception()
957 
958  def getCoreVeDiag(self, timeout_s=None):
959  """!
960  Get diagnostic information for core VE.
961 
962  @return Returns object of type subsystem_common.SubsystemDiag, with
963  diagnostic information about subsystem.
964  """
965  return self.CoreVeBodyDiag(self._getSubsystemDiag(self._core_ve_name, timeout_s=timeout_s))
966 
967  class CoreCsDiag(subsystem_common.SubsystemDiag):
968  """!
969  This class contains subsystem-specific diagnostic information for velma_core_cs.
970  """
971  def __init__(self, parent):
972  """!
973  Initialization of diagnostics data using subsystem-independent diagnostics object.
974 
975  @param parent subsystem_common.SubsystemDiag: subsystem-independent diagnostics object.
976  @exception AssertionError Raised when current state name cannot be obtained or state history is not present.
977  """
978  assert (len(parent.history) > 0)
979 
980  self.history = parent.history
981  self.current_predicates = parent.current_predicates
982  self.current_period = parent.current_period
983 
984  self.__current_state = parent.history[0].state_name
985  assert (self.__current_state == "idle" or self.__current_state == "safe" or
986  self.__current_state == "cart_imp" or self.__current_state == "jnt_imp" or
987  self.__current_state == "relax")
988 
990  return self.__current_state
991 
992  def inStateIdle(self):
993  """!
994  Information about current state.
995  @return True if the subsystem is in 'idle' state, False otherwise.
996  """
997  return self.__current_state == "idle"
998 
999  def inStateSafe(self):
1000  """!
1001  Information about current state.
1002  @return True if the subsystem is in 'safe' state, False otherwise.
1003  """
1004  return self.__current_state == "safe"
1005 
1006  def inStateCartImp(self):
1007  """!
1008  Information about current state.
1009  @return True if the subsystem is in 'cart_imp' state, False otherwise.
1010  """
1011  return self.__current_state == "cart_imp"
1012 
1013  def inStateJntImp(self):
1014  """!
1015  Information about current state.
1016  @return True if the subsystem is in 'jnt_imp' state, False otherwise.
1017  """
1018  return self.__current_state == "jnt_imp"
1019 
1020  def inStateRelax(self):
1021  """!
1022  Information about current state.
1023  @return True if the subsystem is in 'relax' state, False otherwise.
1024  """
1025  return self.__current_state == "relax"
1026 
1028  """!
1029  Information about reason for entering 'safe' state.
1030  @return True if the subsystem entered 'safe' state due to possibility of self-collision,
1031  False otherwise.
1032  @exception AssertionError Raised when current state is not 'safe'.
1033  @exception KeyError Raised when 'inSelfCollision' predicate cannot be obtained.
1034  """
1035  assert (self.__current_state == "safe" and self.history[0].state_name == "safe")
1036  for pv in self.history[0].predicates:
1037  if pv.name == "inSelfCollision":
1038  return pv.value
1039  raise KeyError("Could not obtain 'inSelfCollision' predicate value.")
1040 
1041  def isSafeReasonIdle(self):
1042  """!
1043  Information about reason for entering 'safe' state.
1044  @return True if the subsystem entered 'safe' state just after 'idle' state.
1045  @exception AssertionError Raised when current state is not 'safe' or history contain only one entry.
1046  """
1047  assert (self.__current_state == "safe" and self.history[0].state_name == "safe" and len(self.history) >= 2)
1048 
1049  return (self.history[1].state_name == "idle")
1050 
1051  def motorsReady(self):
1052  """!
1053  Information about state of head and torso motors.
1054  @return True if all motors are homed and ready to use, False otherwise.
1055  @exception KeyError Raised when 'motorsReady' predicate cannot be obtained.
1056  """
1057  for pv in self.current_predicates:
1058  if pv.name == "motorsReady":
1059  return pv.value
1060  raise KeyError("Could not obtain current 'motorsReady' predicate value.")
1061 
1062  def getCoreCsDiag(self, timeout_s=None):
1063  """!
1064  Get diagnostic information for core CS.
1065 
1066  @return Returns object of type VelmaInterface.CoreCsDiag, with
1067  diagnostic information about control subsystem.
1068  """
1069  return self.CoreCsDiag(self._getSubsystemDiag(self._core_cs_name, timeout_s=timeout_s))
1070 
1071  # Private method
1072  def _getTopicData(self, topic, timeout_s=None):
1073  return self._subscribed_topics[topic].getData(timeout_s=timeout_s)
1074 
1076  """!
1077  Allow self-collisions of hands.
1078 
1079  @return None
1080  """
1081  data = Int32()
1082  data.data = 1
1083  self.__pub_allow_hands_col.publish( data )
1084 
1086  """!
1087  Disallow self-collisions of hands.
1088 
1089  @return None
1090  """
1091  data = Int32()
1092  data.data = 0
1093  self.__pub_allow_hands_col.publish( data )
1094 
1095  def getRawFTr(self):
1096  """!
1097  Gets right F/T sensor raw reading.
1098 
1099  @return PyKDL.Wrench: Returns KDL wrench.
1100  """
1101  return self._wrenchROStoKDL( self._getTopicData('/right_arm/ft_sensor/wrench') )
1102 
1103  def getRawFTl(self):
1104  """!
1105  Gets left F/T sensor raw reading.
1106 
1107  @return PyKDL.Wrench: Returns KDL wrench.
1108  """
1109  return self._wrenchROStoKDL( self._getTopicData('/left_arm/ft_sensor/wrench') )
1110 
1112  """!
1113  Gets right F/T sensor transformed reading.
1114 
1115  @return PyKDL.Wrench: Returns KDL wrench.
1116  """
1117  return self._wrenchROStoKDL( self._getTopicData('/right_arm/transformed_wrench') )
1118 
1120  """!
1121  Gets left F/T sensor transformed reading.
1122 
1123  @return PyKDL.Wrench: Returns KDL wrench.
1124  """
1125  return self._wrenchROStoKDL( self._getTopicData('/left_arm/transformed_wrench') )
1126 
1127  def getWristWrenchr(self):
1128  """!
1129  Gets estimated wrench for the right end effector.
1130 
1131  @return PyKDL.Wrench: Returns KDL wrench.
1132  """
1133  return self._wrenchROStoKDL( self._getTopicData('/right_arm/wrench') )
1134 
1135  def getWristWrenchl(self):
1136  """!
1137  Gets estimated wrench for the left end effector.
1138 
1139  @return PyKDL.Wrench: Returns KDL wrench.
1140  """
1141  return self._wrenchROStoKDL( self._getTopicData('/left_arm/wrench') )
1142 
1144  """!
1145  Get Polygon that defines wrist collision constraints for joints 5 and 6 of the left arm.
1146 
1147  @return list: Returns wrist collision constraint polygon as [x0, y0, x1, y1, x2, y2, ...].
1148  """
1149  return self.__wcc_l_poly
1150 
1152  """!
1153  Get Polygon that defines wrist collision constraints for joints 5 and 6 of the right arm.
1154 
1155  @return list: Returns wrist collision constraint polygon as [x0, y0, x1, y1, x2, y2, ...].
1156  """
1157  return self.__wcc_r_poly
1158 
1159  # Private method
1160  def _action_right_cart_traj_feedback_cb(self, feedback):
1161  self._action_right_cart_traj_feedback = copy.deepcopy(feedback)
1162 
1163  # Private method
1164  def _wrenchKDLtoROS(self, wrKDL):
1165  return geometry_msgs.msg.Wrench(Vector3( wrKDL.force.x(), wrKDL.force.y(), wrKDL.force.z() ), Vector3( wrKDL.torque.x(), wrKDL.torque.y(), wrKDL.torque.z() ))
1166 
1167  # Private method
1168  def _wrenchROStoKDL(self, wrROS):
1169  return PyKDL.Wrench( PyKDL.Vector(wrROS.force.x, wrROS.force.y, wrROS.force.z), PyKDL.Vector(wrROS.torque.x, wrROS.torque.y, wrROS.torque.z) )
1170 
1172  """!
1173  Switches the robot to relax behavior.
1174  """
1175  goal = BehaviorSwitchGoal()
1176  goal.command = 1
1177  self.__action_map['relax'].send_goal(goal)
1178 
1179  def enableMotor(self, motor):
1180  """!
1181  Enable motor.
1182 
1183  @param motor string: Name of motor to enable: 'hp', 'ht' or 't'
1184 
1185  @exception NameError: Parameter motor has invalid value.
1186  """
1187  if motor != 'hp' and motor != 'ht' and motor != 't':
1188  raise NameError(motor)
1189  goal = MotorGoal()
1190  goal.action = MotorGoal.ACTION_ENABLE
1191  self.__action_map[motor].send_goal(goal)
1192 
1193  def startHomingMotor(self, motor):
1194  """!
1195  Start homing procedure for specified motor.
1196 
1197  @param motor string: Name of motor to enable: 'hp' or 'ht'
1198 
1199  @exception NameError: Parameter motor has invalid value.
1200  """
1201  if motor != 'hp' and motor != 'ht':
1202  raise NameError(motor)
1203  goal = MotorGoal()
1204  goal.action = MotorGoal.ACTION_START_HOMING
1205  self.__action_map[motor].send_goal(goal)
1206 
1207  def waitForMotor(self, motor, timeout_s=0):
1208  """!
1209  Wait for an action for a motor to complete.
1210 
1211  @param motor string: Name of motor to enable: 'hp', 'ht' or 't'
1212  @param timeout_s float: Timeout in seconds.
1213 
1214  @return Returns error code or None if timed out.
1215 
1216  @exception NameError: Parameter motor has invalid value.
1217  """
1218  if motor != 'hp' and motor != 'ht' and motor != 't':
1219  raise NameError(motor)
1220 
1221  if not self.__action_map[motor].wait_for_result(timeout=rospy.Duration(timeout_s)):
1222  return None
1223  result = self.__action_map[motor].get_result()
1224 
1225  error_code = result.error_code
1226 
1227  if error_code == MotorResult.ERROR_ALREADY_ENABLED:
1228  print "waitForMotor('" + motor + "'): ERROR_ALREADY_ENABLED (no error)"
1229  error_code = 0
1230  elif error_code == MotorResult.ERROR_HOMING_DONE:
1231  print "waitForMotor('" + motor + "'): ERROR_HOMING_DONE (no error)"
1232  error_code = 0
1233  if error_code != 0:
1234  print "waitForMotor('" + motor + "'): action failed with error_code=" + str(result.error_code)
1235  return error_code
1236 
1237  def enableMotors(self, timeout=0):
1238  """!
1239  Enable all motors and wait.
1240 
1241  @param timeout_s float: Timeout in seconds.
1242 
1243  @see enableMotor
1244  """
1245  self.enableMotor("hp")
1246  r_hp = self.waitForMotor("hp", timeout_s=timeout)
1247  self.enableMotor("ht")
1248  r_ht = self.waitForMotor("ht", timeout_s=timeout)
1249  self.enableMotor("t")
1250  r_t = self.waitForMotor("t", timeout_s=timeout)
1251  if r_hp != 0:
1252  return r_hp
1253  if r_ht != 0:
1254  return r_ht
1255  return r_t
1256 
1257  def startHomingHP(self):
1258  """!
1259  Start homing procedure for head pan motor.
1260 
1261  @see startHomingMotor
1262  """
1263  self.startHomingMotor("hp")
1264 
1265  def startHomingHT(self):
1266  """!
1267  Start homing procedure for head tilt motor.
1268 
1269  @see startHomingMotor
1270  """
1271  self.startHomingMotor("hp")
1272  self.startHomingMotor("ht")
1273 
1274  def waitForHP(self, timeout_s=0):
1275  """!
1276  Wait for head pan motor.
1277 
1278  @param timeout_s float: Timeout in seconds.
1279 
1280  @see waitForMotor
1281  """
1282  return self.waitForMotor("hp", timeout_s=timeout_s)
1283 
1284  def waitForHT(self, timeout_s=0):
1285  """!
1286  Wait for head tilt motor.
1287 
1288  @param timeout_s float: Timeout in seconds.
1289 
1290  @see waitForMotor
1291  """
1292  return self.waitForMotor("ht", timeout_s=timeout_s)
1293 
1294  def waitForT(self, timeout_s=0):
1295  """!
1296  Wait for torso motor.
1297 
1298  @param timeout_s float: Timeout in seconds.
1299 
1300  @see waitForMotor
1301  """
1302  return self.waitForMotor("t", timeout_s=timeout_s)
1303 
1304  def getCartImpMvTime(self, side, T_B_T, max_vel_lin, max_vel_rot, current_T_B_T=None):
1305  """!
1306  Calculate movement time for a given destination pose of end effector tool, given maximum
1307  allowed linear and rotational velocities.
1308 
1309  @param side string: side: 'left' or 'right'.
1310  @param T_B_T PyKDL.Frame: destination pose.
1311  @param max_vel_lin float: maximum linear velocity.
1312  @param max_vel_rot float: maximum rotational velocity.
1313  @param current_T_B_T PyKDL.Frame: (optional) current pose. If ommited, the current pose
1314  from tf is considered.
1315 
1316  @return Returns float: movement time in seconds.
1317 
1318  @exception AssertionError Raised when prefix is neither 'left' nor 'right'.
1319  """
1320  if current_T_B_T is None:
1321  if side == 'left':
1322  current_T_B_T = self.getTf('B', 'Tl', time=None, timeout_s=0.1)
1323  if current_T_B_T is None:
1324  current_T_B_T = self.getTf('B', 'Wl', time=None, timeout_s=0.1)
1325  elif side == 'right':
1326  current_T_B_T = self.getTf('B', 'Tr', time=None, timeout_s=0.1)
1327  if current_T_B_T is None:
1328  current_T_B_T = self.getTf('B', 'Wr', time=None, timeout_s=0.1)
1329  else:
1330  raise Exception('Wrong side: "{}"'.format(side))
1331  twist = PyKDL.diff(current_T_B_T, T_B_T, 1.0)
1332  return max( twist.vel.Norm()/max_vel_lin, twist.rot.Norm()/max_vel_rot )
1333 
1334  def moveCartImp(self, prefix, pose_list_T_B_Td, pose_times, tool_list_T_W_T, tool_times, imp_list, imp_times, max_wrench, start_time=0.01, stamp=None, damping=PyKDL.Wrench(PyKDL.Vector(0.35, 0.35, 0.35),PyKDL.Vector(0.35, 0.35, 0.35)), path_tol=None):
1335  """!
1336  Execute motion in cartesian impedance mode.
1337 
1338  @param prefix string: name of end-effector: 'left' or 'right'.
1339  @param pose_list_T_B_Td list of PyKDL.Frame: Poses of end-effector tool wrt. base frame. This is a path for the end-effector.
1340  @param pose_times list of float: Times of the poses in pose_list_T_B_Td wrt. start_time.
1341  @param tool_list_T_W_T list of PyKDL.Frame: Poses of tool frame wrt. wrist frame. This is a path for the tool of end-effector.
1342  @param tool_times list of float: Times of the tool poses in tool_list_T_W_T wrt. start_time.
1343  @param imp_list list of PyKDL.Wrench: Tool impedance values expressed in tool frame. This is a path for the impedance of end-effector.
1344  @param imp_times list of float: Times of the impedance values in imp_list wrt. start_time.
1345  @param max_wrench PyKDL.Wrench: Maximum allowed wrench during the motion expressed in tool frame.
1346  @param start_time float: Relative start time for the movement.
1347  @param stamp rospy.Time: Absolute start time for the movement. If both start_time and stamp arguments are set, only stamp is taken into account.
1348  @param damping PyKDL.Wrench: Damping for the tool expressed in tool frame.
1349  @param path_tol PyKDL.Twist: Maximum allowed error of tool pose expressed in the tool frame. Error of tool pose is a difference between desired tool equilibrium pose and measured tool pose.
1350 
1351  @return Returns True.
1352 
1353  @exception AssertionError Raised when prefix is neither 'left' nor 'right'.
1354  """
1355 
1356  assert (prefix=="left" or prefix=="right")
1357  assert ((pose_list_T_B_Td == None and pose_times == None) or len(pose_list_T_B_Td) == len(pose_times))
1358  assert ((tool_list_T_W_T == None and tool_times == None) or len(tool_list_T_W_T) == len(tool_times))
1359  assert ((imp_list == None and imp_times == None) or len(imp_list) == len(imp_times))
1360 
1361  action_trajectory_goal = CartImpGoal()
1362  if stamp == None:
1363  stamp = rospy.Time.now() + rospy.Duration(start_time)
1364 
1365  action_trajectory_goal.pose_trj.header.stamp = stamp
1366  action_trajectory_goal.tool_trj.header.stamp = stamp
1367  action_trajectory_goal.imp_trj.header.stamp = stamp
1368 
1369  if pose_list_T_B_Td != None:
1370  for i in range(len(pose_list_T_B_Td)):
1371  wrist_pose = pm.toMsg(pose_list_T_B_Td[i])
1372  action_trajectory_goal.pose_trj.points.append(CartesianTrajectoryPoint(
1373  rospy.Duration(pose_times[i]),
1374  wrist_pose,
1375  Twist()))
1376 
1377  if tool_list_T_W_T != None:
1378  for i in range(len(tool_list_T_W_T)):
1379  tool_pose = pm.toMsg(tool_list_T_W_T[i])
1380  action_trajectory_goal.tool_trj.points.append(CartesianTrajectoryPoint(
1381  rospy.Duration(tool_times[i]),
1382  tool_pose,
1383  Twist()))
1384 
1385  if imp_list != None:
1386  for i in range(len(imp_list)):
1387  action_trajectory_goal.imp_trj.points.append(CartesianImpedanceTrajectoryPoint(
1388  rospy.Duration(imp_times[i]),
1389  CartesianImpedance(self._wrenchKDLtoROS(imp_list[i]), self._wrenchKDLtoROS(damping))))
1390 
1391  if path_tol != None:
1392  action_trajectory_goal.path_tolerance.position = geometry_msgs.msg.Vector3( path_tol.vel.x(), path_tol.vel.y(), path_tol.vel.z() )
1393  action_trajectory_goal.path_tolerance.rotation = geometry_msgs.msg.Vector3( path_tol.rot.x(), path_tol.rot.y(), path_tol.rot.z() )
1394  action_trajectory_goal.goal_tolerance.position = geometry_msgs.msg.Vector3( path_tol.vel.x(), path_tol.vel.y(), path_tol.vel.z() )
1395  action_trajectory_goal.goal_tolerance.rotation = geometry_msgs.msg.Vector3( path_tol.rot.x(), path_tol.rot.y(), path_tol.rot.z() )
1396 
1397  action_trajectory_goal.wrench_constraint = self._wrenchKDLtoROS(max_wrench)
1398  self.__action_map['cimp_'+prefix].send_goal(action_trajectory_goal)
1399 
1400  return True
1401 
1402  def moveCartImpRight(self, pose_list_T_B_Td, pose_times, tool_list_T_W_T, tool_times, imp_list, imp_times, max_wrench, start_time=0.01, stamp=None, damping=PyKDL.Wrench(PyKDL.Vector(0.35, 0.35, 0.35),PyKDL.Vector(0.35, 0.35, 0.35)), path_tol=None):
1403  """!
1404  Execute motion in cartesian impedance mode for the right end-effector.
1405  @see moveCartImp
1406  """
1407  return self.moveCartImp("right", pose_list_T_B_Td, pose_times, tool_list_T_W_T, tool_times, imp_list, imp_times, max_wrench, start_time=start_time, stamp=stamp, damping=damping, path_tol=path_tol)
1408 
1409  def moveCartImpLeft(self, pose_list_T_B_Td, pose_times, tool_list_T_W_T, tool_times, imp_list, imp_times, max_wrench, start_time=0.01, stamp=None, damping=PyKDL.Wrench(PyKDL.Vector(0.35, 0.35, 0.35),PyKDL.Vector(0.35, 0.35, 0.35)), path_tol=None):
1410  """!
1411  Execute motion in cartesian impedance mode for the left end-effector.
1412  @see moveCartImp
1413  """
1414  return self.moveCartImp("left", pose_list_T_B_Td, pose_times, tool_list_T_W_T, tool_times, imp_list, imp_times, max_wrench, start_time=start_time, stamp=stamp, damping=damping, path_tol=path_tol)
1415 
1416  def moveCartImpCurrentPos(self, side, start_time=0.2, stamp=None):
1417  """!
1418  Move right end-effector to current position. Switch core_cs to cart_imp mode.
1419  @return Returns True.
1420  """
1421  return self.moveCartImp(side, None, None, None, None, None, None, PyKDL.Wrench(PyKDL.Vector(5,5,5), PyKDL.Vector(5,5,5)), start_time=start_time, stamp=stamp)
1422 
1423  def moveCartImpRightCurrentPos(self, start_time=0.2, stamp=None):
1424  """!
1425  Move right end-effector to current position. Switch core_cs to cart_imp mode.
1426  @return Returns True.
1427  """
1428  return self.moveCartImpCurrentPos('right', start_time=start_time, stamp=stamp)
1429 
1430  def moveCartImpLeftCurrentPos(self, start_time=0.2, stamp=None):
1431  """!
1432  Move left end-effector to current position. Switch core_cs to cart_imp mode.
1433  @return Returns True.
1434  """
1435  return self.moveCartImpCurrentPos('left', start_time=start_time, stamp=stamp)
1436 
1437  def waitForEffector(self, prefix, timeout_s=None):
1438  """!
1439  Wait for completion of end-effector motion in cartesian impedance mode.
1440 
1441  @param prefix string: name of end-effector: 'left' or 'right'.
1442  @param timeout_s float: timeout in seconds.
1443 
1444  @return Returns error code.
1445 
1446  @exception AssertionError Raised when prefix is neither 'left' nor 'right'
1447  """
1448  assert (prefix=="left" or prefix=="right")
1449 
1450  if timeout_s == None:
1451  timeout_s = 0
1452  if not self.__action_map['cimp_'+prefix].wait_for_result(timeout=rospy.Duration(timeout_s)):
1453  return None
1454  result = self.__action_map['cimp_'+prefix].get_result()
1455  if result.error_code != 0:
1456  error_str = "UNKNOWN"
1457  if result.error_code in self._cartesian_trajectory_result_names:
1458  error_str = self._cartesian_trajectory_result_names[result.error_code]
1459  print "waitForEffector(" + prefix + "): action failed with error_code=" + str(result.error_code) + " (" + error_str + ")"
1460 
1461  self.waitForJointState( self.__action_map['cimp_'+prefix].gh.comm_state_machine.latest_result.header.stamp )
1462 
1463  return result.error_code
1464 
1465  def waitForEffectorLeft(self, timeout_s=None):
1466  """!
1467  Wait for completion of left end-effector motion in cartesian impedance mode.
1468  @param timeout_s float: Timeout in seconds.
1469  @return Returns error code.
1470  """
1471  return self.waitForEffector("left", timeout_s=timeout_s)
1472 
1473  def waitForEffectorRight(self, timeout_s=None):
1474  """!
1475  Wait for completion of right end-effector motion in cartesian impedance mode.
1476  @param timeout_s float: Timeout in seconds.
1477  @return Returns error code.
1478  """
1479  return self.waitForEffector("right", timeout_s=timeout_s)
1480 
1481 
1482 
1483  def lookAt(self, point, frame_id='torso_base'):
1484  """!
1485  Execute look at motion of head.
1486 
1487  @return Returns True
1488 
1489  """
1490 
1491  assert self.__isActionConnected('look_at')
1492 
1493  goal = LookAtGoal()
1494  goal.frame_id = frame_id
1495  goal.target = geometry_msgs.msg.Point(point.x(), point.y(), point.z())
1496  self.__action_map['look_at'].send_goal(goal)
1497 
1498  return True
1499 
1500  def cancelLookAt(self):
1501  """!
1502  Cancel look at motion of head.
1503 
1504  @return Returns True.
1505 
1506  """
1507 
1508  assert self.__isActionConnected('look_at')
1509 
1511  """!
1512  Check if look at action is connected.
1513 
1514  @return True if look at action is connected, False otherwise.
1515 
1516  """
1517  return self.__isActionConnected('look_at')
1518 
1519  def waitForLookAt(self, timeout_s=None):
1520  """!
1521  Wait for completion of look at motion.
1522 
1523  @param timeout_s float: timeout in seconds.
1524 
1525  @return Returns error code.
1526 
1527  """
1528 
1529  assert self.__isActionConnected('look_at')
1530 
1531  if timeout_s == None:
1532  timeout_s = 0
1533  if not self.__action_map['look_at'].wait_for_result(timeout=rospy.Duration(timeout_s)):
1534  return None
1535  result = self.__action_map['look_at'].get_result()
1536  if result.error_code != 0:
1537  error_str = "UNKNOWN"
1538  if result.error_code in self._look_at_result_names:
1539  error_str = self._look_at_result_names[result.error_code]
1540  print('waitForLookAt(): action failed with error_code={} ({})'.format(
1541  result.error_code, error_str))
1542  self.waitForJointState( self.__action_map['look_at'].gh.comm_state_machine.latest_result.header.stamp )
1543  return result.error_code
1544 
1545  def maxJointTrajLen(self):
1546  """!
1547  Get maximum number of nodes in single joint trajectory.
1548  @return Maximum number of nodes.
1549  """
1550  return 50
1551 
1552  def maxHeadTrajLen(self):
1553  """!
1554  Get maximum number of nodes in single head trajectory.
1555  @return Maximum number of nodes.
1556  """
1557  return 50
1558 
1559  @staticmethod
1560  def getJointGroup(group_name):
1561  """!
1562  Get names of all joints in group.
1563  @param group_name string: name of group.
1564  @return Returns list of names of joints in group.
1565  """
1566  return VelmaInterface._joint_groups[group_name]
1567 
1568  def moveJointTrajAndWait(self, traj, start_time=0.2, stamp=None, position_tol=5.0/180.0 * math.pi, velocity_tol=5.0/180.0*math.pi):
1569  """!
1570  Execute joint space trajectory in joint impedance mode. Trajectories of any length are allowed.
1571  This method blocks the executing thread until trajectory is completed, or error occures.
1572  @param traj trajectory_msgs.msg.JointTrajectory: joint trajectory.
1573  @param start_time float: relative start time.
1574  @param stamp rospy.Time: absolute start time.
1575  @position_tol float: position tolerance.
1576  @velocity_tol float: velocity tolerance.
1577  @return Returns True.
1578  """
1579 
1580  q_end_traj = {}
1581  for q_idx, joint_name in enumerate(traj.joint_names):
1582  q_end_traj[joint_name] = traj.points[-1].positions[q_idx]
1583 
1584  traj_list = splitTrajectory(traj, self.maxJointTrajLen())
1585  for traj_idx, traj_part in enumerate(traj_list):
1586  print('Executing trajectory {}...'.format(traj_idx))
1587  if not self.moveJointTraj(traj_part, start_time=0.5,
1588  position_tol=position_tol, velocity_tol=velocity_tol):
1589  exitError(5)
1590  if self.waitForJoint() != 0:
1591  print('VelmaInterface.moveJointTraj(): The trajectory could not be completed')
1592  return False
1593  rospy.sleep(0.5)
1594  js = self.getLastJointState()
1595  if not isConfigurationClose(q_end_traj, js[1], tolerance=position_tol, allow_subset=True):
1596  print('VelmaInterface.moveJointTraj(): the goal configuration could not be reached')
1597  return False
1598  # else:
1599  return True
1600 
1601  def moveJointTraj(self, traj, start_time=0.2, stamp=None, position_tol=5.0/180.0 * math.pi, velocity_tol=5.0/180.0*math.pi):
1602  """!
1603  Execute joint space trajectory in joint impedance mode. Trajectories of length up to 50 nodes are allowed.
1604  This method does not block the executing thread.
1605  @param traj trajectory_msgs.msg.JointTrajectory: joint trajectory.
1606  @param start_time float: relative start time.
1607  @param stamp rospy.Time: absolute start time.
1608  @position_tol float: position tolerance.
1609  @velocity_tol float: velocity tolerance.
1610  @return Returns True.
1611  @exception AssertionError Raised when trajectory has too many nodes.
1612  """
1613  assert (len(traj.points) <= self.maxJointTrajLen())
1614 
1615  goal = FollowJointTrajectoryGoal()
1616  goal.trajectory.joint_names = self._body_joint_names
1617 
1618  js = self.getLastJointState()
1619  assert (js != None)
1620 
1621  for node_idx in range(len(traj.points)):
1622  q_dest_all = []
1623  vel_dest_all = []
1624 
1625  for joint_name in self._body_joint_names:
1626  if joint_name in traj.joint_names:
1627  q_idx = traj.joint_names.index(joint_name)
1628  q_dest_all.append(traj.points[node_idx].positions[q_idx])
1629  if len(traj.points[node_idx].velocities) > 0:
1630  vel_dest_all.append(traj.points[node_idx].velocities[q_idx])
1631  else:
1632  vel_dest_all.append(0)
1633  else:
1634  q_dest_all.append(js[1][joint_name])
1635  vel_dest_all.append(0)
1636  goal.trajectory.points.append(JointTrajectoryPoint(q_dest_all, vel_dest_all, [], [], traj.points[node_idx].time_from_start))
1637 
1638  for joint_name in goal.trajectory.joint_names:
1639  goal.path_tolerance.append(JointTolerance(joint_name, position_tol, velocity_tol, 0.0))
1640  if stamp != None:
1641  goal.trajectory.header.stamp = stamp
1642  else:
1643  goal.trajectory.header.stamp = rospy.Time.now() + rospy.Duration(start_time)
1644  self.__action_map['jimp'].send_goal(goal)
1645  return True
1646 
1647  def calculateJointTrajTime(self, q_map_start, traj_in, max_vel):
1648  if q_map_start is None:
1649  q_map_start = self.getLastJointState()[1]
1650 
1651  pt_idx = 0
1652  q_map_prev = q_map_start
1653 
1654  #print('VelmaInterface.calculateJointTrajTime()')
1655  traj_out = JointTrajectory()
1656  traj_out.header = traj_in.header
1657  traj_out.joint_names = traj_in.joint_names
1658  time_from_start = 0.0
1659  for pt_idx in range(0, len(traj_in.points)):
1660  q_map = {}
1661  for joint_idx, joint_name in enumerate(traj_in.joint_names):
1662  q_map[joint_name] = traj_in.points[pt_idx].positions[joint_idx]
1663  time_from_start = time_from_start + self.getJntImpMovementTime2(q_map_prev, q_map, max_vel)
1664  #print(' idx: {}, time_from_start: {}'.format(pt_idx, time_from_start))
1665  q_map_prev = q_map
1666  point_out = JointTrajectoryPoint()
1667  point_out.positions = traj_in.points[pt_idx].positions
1668  point_out.velocities = traj_in.points[pt_idx].velocities
1669  point_out.time_from_start = rospy.Duration(time_from_start)
1670  traj_out.points.append( point_out )
1671  return traj_out
1672 
1673  def getJntImpMovementTime(self, q_dest_map, max_vel):
1674  js = self.getLastJointState()[1]
1675  return self.getJntImpMovementTime2(js, q_dest_map, max_vel)
1676 
1677  def getJntImpMovementTime2(self, q_dest_map_1, q_dest_map_2, max_vel):
1678  max_dist = 0.0
1679  for joint_name in q_dest_map_1:
1680  if not joint_name in q_dest_map_2:
1681  continue
1682  dist = abs(q_dest_map_1[joint_name] - q_dest_map_2[joint_name])
1683  max_dist = max(max_dist, dist)
1684  return max_dist / max_vel
1685 
1686  def moveJoint(self, q_dest_map, time, max_vel=None, start_time=0.2, stamp=None, position_tol=5.0/180.0 * math.pi, velocity_tol=5.0/180.0*math.pi):
1687  """!
1688  Execute simple joint space motion in joint impedance mode.
1689  @param q_dest_map dictionary: dictionary {name:position} of goal configuration
1690  @param start_time float: relative start time.
1691  @param stamp rospy.Time: absolute start time.
1692  @position_tol float: position tolerance.
1693  @velocity_tol float: velocity tolerance.
1694  @return Returns True.
1695  """
1696  if time is None:
1697  assert not max_vel is None
1698  time = max(0.1, self.getJntImpMovementTime(q_dest_map, max_vel))
1699  print('moveJoint calculated time: {}'.format(time))
1700  traj = JointTrajectory()
1701  pt = JointTrajectoryPoint()
1702  for name in q_dest_map:
1703  traj.joint_names.append(name)
1704  pt.positions.append(q_dest_map[name])
1705  pt.velocities.append(0)
1706  pt.time_from_start = rospy.Duration(time)
1707  traj.points.append(pt)
1708  return self.moveJointTraj(traj, start_time=start_time, stamp=stamp, position_tol=position_tol, velocity_tol=velocity_tol)
1709 
1710  def moveJointImpToCurrentPos(self, start_time=0.2, stamp=None):
1711  """!
1712  Switch core_cs to jnt_imp mode.
1713  @return Returns True.
1714  """
1715  traj = JointTrajectory()
1716  return self.moveJointTraj(traj, start_time=start_time, stamp=stamp)
1717 
1718  def waitForJoint(self, timeout_s=None):
1719  """!
1720  Wait for joint space movement to complete.
1721  @return Returns error code.
1722  """
1723  if timeout_s == None:
1724  timeout_s = 0
1725  if not self.__action_map['jimp'].wait_for_result(timeout=rospy.Duration(timeout_s)):
1726  return None
1727  result = self.__action_map['jimp'].get_result()
1728  if result.error_code != 0:
1729  error_str = "UNKNOWN"
1730  if result.error_code in self._joint_trajectory_result_names:
1731  error_str = self._joint_trajectory_result_names[result.error_code]
1732  print "waitForJoint(): action failed with error_code=" + str(result.error_code) + " (" + error_str + ")"
1733 
1734  self.waitForJointState( self.__action_map['jimp'].gh.comm_state_machine.latest_result.header.stamp )
1735 
1736  return result.error_code
1737 
1738  def moveHeadTraj(self, traj, start_time=0.2, stamp=None, position_tol=5.0/180.0 * math.pi, velocity_tol=5.0/180.0*math.pi):
1739  """!
1740  Execute head trajectory in joint space.
1741  @param traj trajectory_msgs.msg.JointTrajectory: joint trajectory.
1742  @param start_time float: relative start time.
1743  @param stamp rospy.Time: absolute start time.
1744  @position_tol float: position tolerance.
1745  @velocity_tol float: velocity tolerance.
1746  @return Returns True.
1747  @exception AssertionError Raised when trajectory has too many nodes or not all joints are
1748  included in trajectory.
1749  """
1750  assert (len(traj.points) <= self.maxHeadTrajLen())
1751 
1752  goal = FollowJointTrajectoryGoal()
1753  goal.trajectory.joint_names = ["head_pan_joint", "head_tilt_joint"]
1754 
1755  for node_idx in range(len(traj.points)):
1756  q_dest_all = []
1757  vel_dest_all = []
1758  for joint_name in goal.trajectory.joint_names:
1759  assert (joint_name in traj.joint_names)
1760  q_idx = traj.joint_names.index(joint_name)
1761  q_dest_all.append(traj.points[node_idx].positions[q_idx])
1762  if len(traj.points[node_idx].velocities) > 0:
1763  vel_dest_all.append(traj.points[node_idx].velocities[q_idx])
1764  else:
1765  vel_dest_all.append(0)
1766  goal.trajectory.points.append(JointTrajectoryPoint(q_dest_all, vel_dest_all, [], [], traj.points[node_idx].time_from_start))
1767 
1768  for joint_name in goal.trajectory.joint_names:
1769  goal.path_tolerance.append(JointTolerance(joint_name, position_tol, velocity_tol, 0))
1770  if stamp != None:
1771  goal.trajectory.header.stamp = stamp
1772  else:
1773  goal.trajectory.header.stamp = rospy.Time.now() + rospy.Duration(start_time)
1774  self.__action_map['head'].cancel_goal()
1775  self.__action_map['head'].send_goal(goal)
1776  return True
1777 
1778  def __getHeadMovementTime(self, q_dest, max_vel):
1779  js = self.getLastJointState()[1]
1780  dist1 = abs(q_dest[0] - js["head_pan_joint"])
1781  dist2 = abs(q_dest[1] - js["head_tilt_joint"])
1782  max_dist = max(dist1, dist2)
1783  return max_dist / max_vel
1784 
1785  def moveHead(self, q_dest, time, max_vel=None, start_time=0.2, stamp=None, position_tol=5.0/180.0 * math.pi, velocity_tol=5.0/180.0*math.pi):
1786  """!
1787  Execute simple head motion in joint space.
1788  @param q_dest 2-tuple: goal configuration of head ('head_pan_joint', 'head_tilt_joint')
1789  @param start_time float: relative start time.
1790  @param stamp rospy.Time: absolute start time.
1791  @position_tol float: position tolerance.
1792  @velocity_tol float: velocity tolerance.
1793  @return Returns True.
1794  @exception AssertionError When q_dest has wrong length.
1795  """
1796  assert (len(q_dest) == 2)
1797 
1798  if time is None:
1799  assert not max_vel is None
1800  time = max(0.1, self.__getHeadMovementTime(q_dest, max_vel))
1801  print('moveHead calculated time: {}'.format(time))
1802 
1803  traj = JointTrajectory()
1804  traj.joint_names = ["head_pan_joint", "head_tilt_joint"]
1805  pt = JointTrajectoryPoint()
1806  pt.positions = q_dest
1807  pt.velocities = [0.0, 0.0]
1808  pt.time_from_start = rospy.Duration(time)
1809  traj.points.append(pt)
1810  return self.moveHeadTraj(traj, start_time=start_time, stamp=stamp, position_tol=position_tol, velocity_tol=velocity_tol)
1811 
1812  def waitForHead(self, timeout_s=None):
1813  """!
1814  Wait for head movement to complete.
1815  @return Returns error code.
1816  """
1817  if timeout_s == None:
1818  timeout_s = 0
1819 
1820  if not self.__action_map['head'].wait_for_result(timeout=rospy.Duration(timeout_s)):
1821  return None
1822  result = self.__action_map['head'].get_result()
1823  if result.error_code != 0:
1824  print "waitForHead(): action failed with error_code=" + str(result.error_code)
1825 
1826  self.waitForJointState( self.__action_map['head'].gh.comm_state_machine.latest_result.header.stamp )
1827 
1828  return result.error_code
1829 
1830  def moveHand(self, prefix, q, v, t, maxPressure, hold=False):
1831  """!
1832  Executes hand motion with trapezoidal velocity profile.
1833 
1834  @param prefix string: name of hand, either 'left' or 'right'
1835  @param q 4-tuple of float: desired configuration for hand DOFs:
1836  [FingerOneKnuckleTwo, FingerTwoKnuckleTwo, FingerThreeKnuckleTwo, Spread]
1837  @param v 4-tuple of float: maximum velocities
1838  @param t 4-tuple of float: maximum current in motors
1839  @param maxPressure float: maximum pressure for tactile sensors
1840  @param hold bool: True if spread joint should hold its position after completion of motion
1841  @exception AssertionError when prefix is neither 'left' nor 'right'
1842  """
1843  assert (prefix == 'left' or prefix == 'right')
1844  action_goal = BHMoveGoal()
1845  action_goal.name = [prefix+"_HandFingerOneKnuckleTwoJoint", prefix+"_HandFingerTwoKnuckleTwoJoint",
1846  prefix+"_HandFingerThreeKnuckleTwoJoint", prefix+"_HandFingerOneKnuckleOneJoint"]
1847  action_goal.q = q
1848  action_goal.v = v
1849  action_goal.t = t
1850  action_goal.maxPressure = maxPressure
1851  action_goal.reset = False
1852  action_goal.hold = 1 if hold else 0
1853  self.__action_map['hand_'+prefix].send_goal(action_goal)
1854 
1855  def moveHandLeft(self, q, v, t, maxPressure, hold=False):
1856  """!
1857  Executes motion with trapezoidal velocity profile for left hand.
1858  @see moveHand
1859  """
1860  self.moveHand("left", q, v, t, maxPressure, hold=hold)
1861 
1862  def moveHandRight(self, q, v, t, maxPressure, hold=False):
1863  """!
1864  Executes motion with trapezoidal velocity profile for right hand.
1865  @see moveHand
1866  """
1867  self.moveHand("right", q, v, t, maxPressure, hold=hold)
1868 
1869  def resetHand(self, prefix):
1870  """!
1871  Executes reset command for hand.
1872  @param prefix string: name of hand, either 'left' or 'right'
1873  @exception AssertionError when prefix is neither 'left' nor 'right'
1874  """
1875  assert (prefix == 'left' or prefix == 'right')
1876  action_goal = BHMoveGoal()
1877  action_goal.reset = True
1878  self.__action_map['hand_'+prefix].send_goal(action_goal)
1879 
1880  def resetHandLeft(self):
1881  """!
1882  Executes reset command for left hand.
1883  @see resetHand
1884  """
1885  self.resetHand("left")
1886 
1887  def resetHandRight(self):
1888  """!
1889  Executes reset command for right hand.
1890  @see resetHand
1891  """
1892  self.resetHand("right")
1893 
1894  def waitForHand(self, prefix, timeout_s=None):
1895  """!
1896  Wait for completion of hand movement.
1897  @param prefix string: name of hand, either 'left' or 'right'
1898  @exception AssertionError when prefix is neither 'left' nor 'right'
1899  """
1900  assert (prefix == 'left' or prefix == 'right')
1901 
1902  if timeout_s == None:
1903  timeout_s = 0
1904 
1905  if not self.__action_map['hand_'+prefix].wait_for_result(timeout=rospy.Duration(timeout_s)):
1906  return None
1907 
1908  result = self.__action_map['hand_'+prefix].get_result()
1909  if result.error_code != 0:
1910  print "waitForHand(" + prefix + "): action failed with error_code=" + str(result.error_code) + " (" + self._moveHand_action_error_codes_names[result.error_code] + ")"
1911  return result.error_code
1912 
1913  def waitForHandLeft(self):
1914  """!
1915  Wait for completion of left hand movement.
1916  @see waitForHand
1917  """
1918  return self.waitForHand("left")
1919 
1920  def waitForHandRight(self):
1921  """!
1922  Wait for completion of right hand movement.
1923  @see waitForHand
1924  """
1925  return self.waitForHand("right")
1926 
1927  def _getKDLtf(self, base_frame, frame, time=None, timeout_s=1.0):
1928  """!
1929  Lookup tf transform and convert it to PyKDL.Frame.
1930  @param base_frame string: name of base frame
1931  @param frame string: name of target frame
1932  @param time rospy.Time: time at which transform should be interpolated
1933  @param timeout_s float: timeout in seconds
1934  @return PyKDL.Frame transformation from base frame to target frame.
1935  @exception tf2_ros.TransformException when the transform for the specified time
1936  is not avaible during the timeout_s.
1937  """
1938  if time == None:
1939  time = rospy.Time.now()
1940  try:
1941  self._listener.waitForTransform(base_frame, frame, time, rospy.Duration(timeout_s))
1942  pose = self._listener.lookupTransform(base_frame, frame, time)
1943  except (tf.LookupException, tf.ConnectivityException, tf.ExtrapolationException,
1944  tf2_ros.TransformException):
1945  return None
1946  return pm.fromTf(pose)
1947 
1948  def getAllLinksTf(self, base_frame, time=None, timeout_s=1.0):
1949  """!
1950  Lookup transformations for all links.
1951 
1952  @param base_frame string: name of base frame
1953  @param time rospy.Time: time at which transform should be interpolated
1954  @param timeout_s float: timeout in seconds
1955  @return dictionary {string:PyKDL.Frame} Returns dictionary that maps link names
1956  to their poses wrt. the base frame.
1957  @exception tf2_ros.TransformException when the transform for the specified time
1958  is not avaible during the timeout_s.
1959  """
1960  if time == None:
1961  time = rospy.Time.now()
1962  result = {}
1963  for l in self._all_links:
1964  try:
1965  result[l.name] = self._getKDLtf(base_frame, l.name, time, timeout_s)
1966  except:
1967  result[l.name] = None
1968  return result
1969 
1970  def getTf(self, frame_from, frame_to, time=None, timeout_s=1.0):
1971  """!
1972  Lookup tf transform and convert it to PyKDL.Frame. Frame names can be the full names
1973  or the following simplified names can be used:
1974  - 'Wo' - world frame ('world')
1975  - 'B' - robot base frame ('torso_base')
1976  - 'Wr' - right wrist ('right_arm_7_link')
1977  - 'Wl' - left wrist ('left_arm_7_link')
1978  - 'Er' - same as 'Wr'
1979  - 'El' - same as 'Wl'
1980  - 'Gr' - right grip frame ('right_HandGripLink')
1981  - 'Gl' - left grip frame ('left_HandGripLink')
1982  - 'Pr' - right palm frame ('right_HandPalmLink')
1983  - 'Pl' - left palm frame ('left_HandPalmLink')
1984  - 'Tr' - right tool frame ('right_arm_tool')
1985  - 'Tl' - left tool frame ('left_arm_tool')
1986  - 'Fr00' - 'right_HandFingerOneKnuckleOneLink'
1987  - 'Fr01' - 'right_HandFingerOneKnuckleTwoLink'
1988  - 'Fr02' - 'right_HandFingerOneKnuckleThreeLink'
1989  - 'Fr10' - 'right_HandFingerTwoKnuckleOneLink'
1990  - 'Fr11' - 'right_HandFingerTwoKnuckleTwoLink'
1991  - 'Fr12' - 'right_HandFingerTwoKnuckleThreeLink'
1992  - 'Fr21' - 'right_HandFingerThreeKnuckleTwoLink'
1993  - 'Fr22' - 'right_HandFingerThreeKnuckleThreeLink'
1994  - 'Fl00' - 'left_HandFingerOneKnuckleOneLink'
1995  - 'Fl01' - 'left_HandFingerOneKnuckleTwoLink'
1996  - 'Fl02' - 'left_HandFingerOneKnuckleThreeLink'
1997  - 'Fl10' - 'left_HandFingerTwoKnuckleOneLink'
1998  - 'Fl11' - 'left_HandFingerTwoKnuckleTwoLink'
1999  - 'Fl12' - 'left_HandFingerTwoKnuckleThreeLink'
2000  - 'Fl21' - 'left_HandFingerThreeKnuckleTwoLink'
2001  - 'Fl22' - 'left_HandFingerThreeKnuckleThreeLink'
2002 
2003  @param frame_from string: simplified name of base frame
2004  @param frame_to string: simplified name of target frame
2005  @param time rospy.Time: time at which transform should be interpolated
2006  @param timeout_s float: timeout in seconds
2007  @return PyKDL.Frame transformation from base frame to target frame.
2008  @exception tf2_ros.TransformException when the transform for the specified time
2009  is not avaible during the timeout_s.
2010  """
2011  if time == None:
2012  time = rospy.Time.now()
2013  if frame_from in self._frames:
2014  frame_from_name = self._frames[frame_from]
2015  else:
2016  frame_from_name = frame_from
2017 
2018  if frame_to in self._frames:
2019  frame_to_name = self._frames[frame_to]
2020  else:
2021  frame_to_name = frame_to
2022 
2023  return self._getKDLtf( frame_from_name, frame_to_name, time, timeout_s )
2024 
2025  def setGraspedFlag(self, side, status):
2026  """!
2027  Inform control system about grasped object.
2028 
2029  @param side string: Hand name, can be one of two values ('left' or 'right').
2030  @param status bool: True when object is grasped and gravity compensation is active, False
2031  otherwise.
2032 
2033  @exception NameError: If side is not 'left' or 'right'.
2034  """
2035  if side != 'left' and side != 'right':
2036  raise NameError('wrong side name: ' + str(side))
2037 
2038  goal = GraspedGoal()
2039  if status == True:
2040  goal.action = GraspedGoal.ACTION_OBJECT_GRASPED
2041  elif status == False:
2042  goal.action = GraspedGoal.ACTION_NOTHING_GRASPED
2043 
2044  self.__action_map['grasped_'+side].send_goal(goal)
2045 
2046  print "Manipulator:", side, "--> object_grasped_flag_status:", status
2047 
2048  self.__action_map['grasped_'+side].wait_for_result(timeout=rospy.Duration(0))
2049  result = self.__action_map['grasped_'+side].get_result()
2050  error_code = result.error_code
2051  if error_code != 0:
2052  print "setGraspedFlag: action failed (error)"
2053 
2054  def sendIdentificationMeasurementCommand(self, side, command_index):
2055  """!
2056  Make measurement for gravity compensation. This identification action requires four
2057  measurements: two before and two after object is grasped.
2058 
2059  @param side string: Hand name, can be one of two values ('left' or 'right').
2060  @param command_index int: measurement index - one of the following values: 1 - the first
2061  measurement before the object is grasped, 2 - the second measurement before the object
2062  is grasped, 3 - the first measurement after the object is grasped (in the same pose
2063  as for measurement 1), 4 - the second measurement after the object is grasped (in the same
2064  pose as for measurement 2).
2065 
2066  @exception NameError: If side is not 'left' or 'right'.
2067  """
2068  if side != 'left' and side != 'right':
2069  raise NameError('wrong side name: ' + str(side))
2070 
2071  goal = IdentificationGoal()
2072  if command_index == 1:
2073  goal.action = IdentificationGoal.ACTION_FIRST_MEASUREMENT_BEFORE_OBJECT_IS_GRASPED
2074  elif command_index == 2:
2075  goal.action = IdentificationGoal.ACTION_SECOND_MEASUREMENT_BEFORE_OBJECT_IS_GRASPED
2076  elif command_index == 3:
2077  goal.action = IdentificationGoal.ACTION_FIRST_MEASUREMENT_AFTER_OBJECT_IS_GRASPED
2078  elif command_index == 4:
2079  goal.action = IdentificationGoal.ACTION_SECOND_MEASUREMENT_AFTER_OBJECT_IS_GRASPED
2080 
2081  self.__action_map['identification_'+side].send_goal(goal)
2082 
2083  print "Manipulator:", side, "--> identification_command:", command_index
2084 
2085  self.__action_map['identification_'+side].wait_for_result(timeout=rospy.Duration(0))
2086  result = self.__action_map['identification_'+side].get_result()
2087  error_code = result.error_code
2088  if error_code != 0:
2089  print "sendIdentificationMeasurementCommand: action failed (error)"
def waitForHead(self, timeout_s=None)
Wait for head movement to complete.
def startHomingHT(self)
Start homing procedure for head tilt motor.
def moveCartImpRightCurrentPos(self, start_time=0.2, stamp=None)
Move right end-effector to current position.
def enableMotor(self, motor)
Enable motor.
def moveCartImpLeft(self, pose_list_T_B_Td, pose_times, tool_list_T_W_T, tool_times, imp_list, imp_times, max_wrench, start_time=0.01, stamp=None, damping=PyKDL.Wrench(PyKDL.Vector(0.35, 0.35, 0.35), PyKDL.Vector(0.35, 0.35, 0.35)), path_tol=None)
Execute motion in cartesian impedance mode for the left end-effector.
def __init__(self, parent)
Initialization of diagnostics data using subsystem-independent diagnostics object.
def getTf(self, frame_from, frame_to, time=None, timeout_s=1.0)
Lookup tf transform and convert it to PyKDL.Frame.
def waitForJoint(self, timeout_s=None)
Wait for joint space movement to complete.
def resetHandLeft(self)
Executes reset command for left hand.
def waitForHandRight(self)
Wait for completion of right hand movement.
def inStateSafe(self)
Information about current state.
def waitForInit(self, timeout_s=None)
Wait for the interface until it is initialized.
def waitForEffectorRight(self, timeout_s=None)
Wait for completion of right end-effector motion in cartesian impedance mode.
def moveHand(self, prefix, q, v, t, maxPressure, hold=False)
Executes hand motion with trapezoidal velocity profile.
def getCartImpMvTime(self, side, T_B_T, max_vel_lin, max_vel_rot, current_T_B_T=None)
Calculate movement time for a given destination pose of end effector tool, given maximum allowed line...
def moveCartImpCurrentPos(self, side, start_time=0.2, stamp=None)
Move right end-effector to current position.
def isLookAtConnected(self)
Check if look at action is connected.
def isConfigurationClose(q_map1, q_map2, tolerance=0.1, allow_subset=False)
Check if two configurations of robot body are close within tolerance.
def moveHandLeft(self, q, v, t, maxPressure, hold=False)
Executes motion with trapezoidal velocity profile for left hand.
def inStateIdle(self)
Information about current state.
def waitForT(self, timeout_s=0)
Wait for torso motor.
def __init__(self, parent)
Initialization of diagnostics data using subsystem-independent diagnostics object.
def waitForEffectorLeft(self, timeout_s=None)
Wait for completion of left end-effector motion in cartesian impedance mode.
def getBodyJointLimits(self)
Gets limits of joints of both arms and torso.
def moveCartImp(self, prefix, pose_list_T_B_Td, pose_times, tool_list_T_W_T, tool_times, imp_list, imp_times, max_wrench, start_time=0.01, stamp=None, damping=PyKDL.Wrench(PyKDL.Vector(0.35, 0.35, 0.35), PyKDL.Vector(0.35, 0.35, 0.35)), path_tol=None)
Execute motion in cartesian impedance mode.
def startHomingMotor(self, motor)
Start homing procedure for specified motor.
def waitForLookAt(self, timeout_s=None)
Wait for completion of look at motion.
def maxJointTrajLen(self)
Get maximum number of nodes in single joint trajectory.
def isHeadConfigurationClose(q1, q2, tolerance=0.1)
Check if two configurations of robot neck are close within tolerance.
def allowHandsCollisions(self)
Allow self-collisions of hands.
def getCoreCsDiag(self, timeout_s=None)
Get diagnostic information for core CS.
def getRightWccPolygon(self)
Get Polygon that defines wrist collision constraints for joints 5 and 6 of the right arm...
def lookAt(self, point, frame_id='torso_base')
Execute look at motion of head.
def moveCartImpRight(self, pose_list_T_B_Td, pose_times, tool_list_T_W_T, tool_times, imp_list, imp_times, max_wrench, start_time=0.01, stamp=None, damping=PyKDL.Wrench(PyKDL.Vector(0.35, 0.35, 0.35), PyKDL.Vector(0.35, 0.35, 0.35)), path_tol=None)
Execute motion in cartesian impedance mode for the right end-effector.
def waitForHand(self, prefix, timeout_s=None)
Wait for completion of hand movement.
def motorsReady(self)
Information about state of head and torso motors.
def getWristWrenchl(self)
Gets estimated wrench for the left end effector.
def getAllLinksTf(self, base_frame, time=None, timeout_s=1.0)
Lookup transformations for all links.
def moveJoint(self, q_dest_map, time, max_vel=None, start_time=0.2, stamp=None, position_tol=5.0/180.0 *math.pi, velocity_tol=5.0/180.0 *math.pi)
Execute simple joint space motion in joint impedance mode.
def inStateRelax(self)
Information about current state.
def moveJointTraj(self, traj, start_time=0.2, stamp=None, position_tol=5.0/180.0 *math.pi, velocity_tol=5.0/180.0 *math.pi)
Execute joint space trajectory in joint impedance mode.
def waitForHP(self, timeout_s=0)
Wait for head pan motor.
def cancelLookAt(self)
Cancel look at motion of head.
def getHandCurrentConfiguration(self, prefix)
Get current configuration of a specified hand.
def isHandConfigurationClose(current_q, dest_q, tolerance=0.1)
Check if two configurations of robot hand are close within tolerance.
def moveJointTrajAndWait(self, traj, start_time=0.2, stamp=None, position_tol=5.0/180.0 *math.pi, velocity_tol=5.0/180.0 *math.pi)
Execute joint space trajectory in joint impedance mode.
def getJntImpMovementTime(self, q_dest_map, max_vel)
def getHandRightCurrentConfiguration(self)
Get current configuration of right hand.
def waitForEffector(self, prefix, timeout_s=None)
Wait for completion of end-effector motion in cartesian impedance mode.
ROS-based, Python interface class for WUT Velma Robot.
Class used for subscription for various ROS topics from the VelmaInterface class. ...
def moveHandRight(self, q, v, t, maxPressure, hold=False)
Executes motion with trapezoidal velocity profile for right hand.
def getJointStateAtTime(self, time)
Get interpolated joint state at a given time.
def moveHead(self, q_dest, time, max_vel=None, start_time=0.2, stamp=None, position_tol=5.0/180.0 *math.pi, velocity_tol=5.0/180.0 *math.pi)
Execute simple head motion in joint space.
def getData(self, timeout_s=None)
Get the newest topic data.
def getSymmetricalJointName(joint_name)
For joint names that refer to joints that are symmetrical (left or right), get the name of the anothe...
def __getHeadMovementTime(self, q_dest, max_vel)
def getHeadJointLimits(self)
Gets limits of joints of neck.
def resetHand(self, prefix)
Executes reset command for hand.
def getHeadCurrentConfiguration(self)
Get current configuration of neck.
def switchToRelaxBehavior(self)
Switches the robot to relax behavior.
def inStateJntImp(self)
Information about current state.
def sendIdentificationMeasurementCommand(self, side, command_index)
Make measurement for gravity compensation.
def _getKDLtf(self, base_frame, frame, time=None, timeout_s=1.0)
Lookup tf transform and convert it to PyKDL.Frame.
def getTransformedFTr(self)
Gets right F/T sensor transformed reading.
def waitForMotor(self, motor, timeout_s=0)
Wait for an action for a motor to complete.
def moveCartImpLeftCurrentPos(self, start_time=0.2, stamp=None)
Move left end-effector to current position.
def moveHeadTraj(self, traj, start_time=0.2, stamp=None, position_tol=5.0/180.0 *math.pi, velocity_tol=5.0/180.0 *math.pi)
Execute head trajectory in joint space.
def waitForJointState(self, abs_time)
Wait for reception of joint state ROS msg with time stamp greater or equal abs_time.
def __connectAction(self, action_name, action, timeout_s)
def getJointGroup(group_name)
Get names of all joints in group.
def __init__(self, topic_name, topic_type, debug=False)
def getCartImpJointLimits(self)
Gets limits of joints of both arms and torso in cart_imp mode.
def inStateCartImp(self)
Information about current state.
def setGraspedFlag(self, side, status)
Inform control system about grasped object.
This class contains information about geometric object: mesh.
def resetHandRight(self)
Executes reset command for right hand.
def startHomingHP(self)
Start homing procedure for head pan motor.
def getWristWrenchr(self)
Gets estimated wrench for the right end effector.
def isSafeReasonIdle(self)
Information about reason for entering &#39;safe&#39; state.
def getLastJointState(self)
Get the newest joint state.
def moveJointImpToCurrentPos(self, start_time=0.2, stamp=None)
Switch core_cs to jnt_imp mode.
def enableMotors(self, timeout=0)
Enable all motors and wait.
def calculateJointTrajTime(self, q_map_start, traj_in, max_vel)
def __init__(self, debug=False)
Initialization of the interface.
def getRawFTr(self)
Gets right F/T sensor raw reading.
This class contains subsystem-specific diagnostic information for velma_core_cs.
def maxHeadTrajLen(self)
Get maximum number of nodes in single head trajectory.
def _getSubsystemDiag(self, subsystem_name, timeout_s=None)
def waitForHT(self, timeout_s=0)
Wait for head tilt motor.
def waitForHandLeft(self)
Wait for completion of left hand movement.
def getRawFTl(self)
Gets left F/T sensor raw reading.
def getTransformedFTl(self)
Gets left F/T sensor transformed reading.
def disallowHandsCollisions(self)
Disallow self-collisions of hands.
def getHandLeftCurrentConfiguration(self)
Get current configuration of left hand.
This class contains subsystem-specific diagnostic information for velma_core_cs.
def getCoreVeDiag(self, timeout_s=None)
Get diagnostic information for core VE.
def isSafeReasonSelfCol(self)
Information about reason for entering &#39;safe&#39; state.
def symmetricalConfiguration(q_map)
Get configuration based on the input configuration such that all joint positions are symmetrical...
def getLeftWccPolygon(self)
Get Polygon that defines wrist collision constraints for joints 5 and 6 of the left arm...
def splitTrajectory(joint_trajectory, max_traj_len)
Split a long trajectory into a number of shorter trajectories.
def getJntImpMovementTime2(self, q_dest_map_1, q_dest_map_2, max_vel)
def _getTopicData(self, topic, timeout_s=None)