00001 '''Everything related to the state of actions and primitives
00002 in the current session
00003 '''
00004
00005
00006
00007
00008
00009
00010 import rospy
00011
00012
00013 import datetime
00014 import threading
00015 import couchdb
00016 import json
00017
00018
00019 from tf import TransformBroadcaster
00020 from std_srvs.srv import Empty as EmptySrv
00021 from std_msgs.msg import Empty as EmptyMsg
00022 from std_msgs.msg import String
00023 from rail_manipulation_msgs.srv import SuggestGrasps
00024 from geometry_msgs.msg import PoseStamped
00025
00026
00027 from fetch_pbd_interaction.action import Action
00028 from fetch_pbd_interaction.arm_target import ArmTarget
00029 from fetch_pbd_interaction.arm_trajectory import ArmTrajectory
00030 from fetch_pbd_interaction.grasp import Grasp
00031 from fetch_pbd_interaction.msg import SessionState, ExecutionStatus, \
00032 Landmark
00033 from fetch_pbd_interaction.srv import GetSessionState, \
00034 GetSessionStateResponse, \
00035 GetObjectList
00036
00037
00038
00039
00040
00041 class Session:
00042 '''Everything related to the state of actions and primitives
00043 in the current session
00044 '''
00045
00046 def __init__(self, robot, _tf_listener, im_server,
00047 from_file=None, to_file=None,
00048 grasp_suggestion_service_name=None,
00049 grasp_feedback_topic=None,
00050 external_ee_link=None):
00051 '''
00052 Args:
00053 robot (Robot) : interface to lower level robot functionality
00054 tf_listener (TransformListener)
00055 im_server (InteractiveMarkerSerever)
00056 '''
00057 self._lock = threading.Lock()
00058 self._from_file = from_file
00059 self._to_file = to_file
00060 self._grasp_suggestion_service = grasp_suggestion_service_name
00061 self._grasp_feedback_topic = grasp_feedback_topic
00062 self._external_ee_link = external_ee_link
00063
00064 self._json = {}
00065 self._robot = robot
00066 self._tf_listener = _tf_listener
00067 self._tf_broadcaster = TransformBroadcaster()
00068
00069 self._im_server = im_server
00070
00071 self._couch = couchdb.Server()
00072 try:
00073 self._db = self._couch['fetch_pbd']
00074 except:
00075 self._db = self._couch.create('fetch_pbd')
00076
00077
00078 self._actions = {}
00079
00080 self._action_ids = []
00081 self._current_action_id = None
00082
00083 self._selected_primitive = -1
00084 self._current_arm_trajectory = None
00085 self._marker_visibility = []
00086 self._head_busy = False
00087
00088 self._actions_disabled = []
00089
00090
00091 self._state_publisher = rospy.Publisher('/fetch_pbd/session_state',
00092 SessionState,
00093 queue_size=10)
00094 self._status_publisher = rospy.Publisher('/fetch_pbd/fetch_pbd_status',
00095 String,
00096 queue_size=10)
00097 rospy.Service('/fetch_pbd/get_session_state', GetSessionState,
00098 self._get_session_state_cb)
00099
00100 self._get_object_list_srv = rospy.ServiceProxy(
00101 '/fetch_pbd/get_object_list',
00102 GetObjectList)
00103 self._update_world_srv = rospy.ServiceProxy('/fetch_pbd/update_world',
00104 GetObjectList)
00105 rospy.wait_for_service('/fetch_pbd/update_world')
00106 rospy.loginfo("Got update_world service.")
00107
00108
00109 self._clear_world_objects_srv = \
00110 rospy.ServiceProxy('/fetch_pbd/clear_world_objects',
00111 EmptySrv)
00112 rospy.wait_for_service('/fetch_pbd/clear_world_objects')
00113 rospy.loginfo("Got clear_world_objects service.")
00114
00115 self._load_session_state()
00116 rospy.loginfo("Session state loaded.")
00117
00118
00119 self._update_session_state()
00120
00121
00122
00123
00124
00125 def head_busy(self):
00126 '''Returns true if head is busy
00127
00128 Returns:
00129 bool
00130 '''
00131 if self.n_actions() < 1 or self._current_action_id is None:
00132 return False or self._head_busy
00133 action = self._actions[self._current_action_id]
00134 return action.head_busy() or self._head_busy
00135
00136 def select_action_primitive(self, primitive_id):
00137 ''' Makes the interactive marker for the indicated action primitive
00138 selected by showing the 6D controls.
00139
00140 Args:
00141 primitive_id (int): ID of the primitive to select.
00142 '''
00143
00144 rospy.loginfo("new: {}, selected: {}".format(primitive_id,
00145 self._selected_primitive))
00146 if primitive_id == self._selected_primitive:
00147 is_selected = False
00148 else:
00149 is_selected = True
00150 self._actions[self._current_action_id].select_primitive(primitive_id,
00151 is_selected)
00152
00153 def new_action(self, name=None):
00154 '''Creates new action.'''
00155 self._clear_world_objects_srv()
00156 if self.n_actions() > 0:
00157 if not self._current_action_id is None:
00158 self.get_current_action().reset_viz()
00159 self._current_action_id = self.n_actions()
00160 else:
00161 self._current_action_id = 0
00162
00163
00164 action = Action(self._robot,
00165 self._tf_listener,
00166 self._im_server,
00167 self._selected_primitive_cb,
00168 self._action_change_cb,
00169 self._current_action_id,
00170 self._grasp_suggestion_service,
00171 self._grasp_feedback_topic,
00172 self._external_ee_link)
00173 if not name is None:
00174 action.set_name(name)
00175 else:
00176 time_str = datetime.datetime.now().strftime('%c')
00177 action.set_name("Untitled action {}".format(time_str))
00178
00179 self._actions.update({
00180 self._current_action_id: action
00181 })
00182 self._actions_disabled.append(False)
00183 self._action_ids.append(self._current_action_id)
00184 self._marker_visibility = [True] * self.n_primitives()
00185 self._update_session_state()
00186
00187 def n_actions(self):
00188 '''Returns the number of actions programmed so far.
00189
00190 Returns:
00191 int
00192 '''
00193 return len(self._actions)
00194
00195 def get_current_action(self):
00196 '''Returns the current action.
00197
00198 Returns:
00199 Action
00200 '''
00201 if self.n_actions() > 0 and not self._current_action_id is None:
00202 action = self._actions[self._current_action_id]
00203 return action
00204 else:
00205 return None
00206
00207 def clear_current_action(self):
00208 '''Removes all primitives in the current action.'''
00209 if self.n_actions() > 0:
00210 current_action = self._actions[self._current_action_id]
00211 current_action.clear()
00212 else:
00213 rospy.logwarn("Can't clear action: No actions created yet.")
00214 self._update_session_state()
00215
00216 def update_arm_trajectory(self):
00217 '''Saves current arm state into continuous trajectory.'''
00218 if self._current_arm_trajectory is not None:
00219 arm_state = self._robot.get_arm_state()
00220 gripper_state = self._robot.get_gripper_state()
00221 self._current_arm_trajectory.add_step(arm_state,
00222 gripper_state)
00223
00224 def start_recording_arm_trajectory(self):
00225 '''Creates ArmTrajectory primitive that will be updated
00226 by update_arm_trajectory
00227 '''
00228 current_action = self._actions[self._current_action_id]
00229 primitive_number = current_action.n_primitives()
00230 self._current_arm_trajectory = ArmTrajectory(self._robot,
00231 self._tf_listener, self._im_server, primitive_number)
00232
00233 def stop_recording_arm_trajectory(self):
00234 '''Finalises ArmTrajectory primitive.
00235 Updates the references frames and saves it to the db.
00236 '''
00237 if self.n_actions() > 0:
00238 current_action = self._actions[self._current_action_id]
00239 current_action.add_primitive(self._current_arm_trajectory, False)
00240 self.publish_primitive_tf()
00241 current_action.make_primitive_marker(-1)
00242 else:
00243 rospy.logwarn("Can't add primitive: No actions created yet.")
00244 self._update_session_state()
00245 self._current_arm_trajectory = None
00246
00247 def add_arm_target_to_action(self):
00248 '''Add a new ArmTarget primitive to the current action.'''
00249
00250 if self.n_actions() > 0:
00251 arm_state = self._robot.get_arm_state()
00252 gripper_state = self._robot.get_gripper_state()
00253 rospy.loginfo("gripper_state: {}".format(gripper_state))
00254 current_action = self._actions[self._current_action_id]
00255 primitive_number = current_action.n_primitives()
00256 arm_target = ArmTarget(self._robot, self._tf_listener,
00257 self._im_server, arm_state,
00258 gripper_state, primitive_number)
00259
00260 current_action.add_primitive(arm_target)
00261 else:
00262 rospy.logwarn("Can't add primitive: No actions created yet.")
00263 self._update_session_state()
00264
00265 def add_grasp_to_action(self, landmark):
00266 '''Add a grasp primitive to the current action.
00267
00268 Args:
00269 landmark (Landmark)
00270 '''
00271 if self.n_actions() > 0:
00272 current_action = self._actions[self._current_action_id]
00273 primitive_number = current_action.n_primitives()
00274 grasp = Grasp(self._robot, self._tf_listener,
00275 self._im_server,
00276 self._grasp_suggestion_service,
00277 self._grasp_feedback_topic,
00278 self._external_ee_link,
00279 landmark,
00280 primitive_number)
00281 current_action.add_primitive(grasp)
00282 else:
00283 rospy.logwarn("Can't add grasp: No actions created yet.")
00284 self._update_session_state()
00285
00286 def delete_last_primitive(self):
00287 '''Removes the last primitive of the action.'''
00288 if self.n_actions() > 0:
00289 current_action = self._actions[self._current_action_id]
00290 current_action.delete_last_primitive()
00291 else:
00292 rospy.logwarn("Can't delete last primitive:" +
00293 " No actions created yet.")
00294 self._update_session_state()
00295
00296 def switch_to_action_by_index(self, index):
00297 '''Switches to action with index
00298
00299 Args:
00300 index (int): The action id to switch to.
00301
00302 Returns:
00303 bool: Whether successfully switched to index action.
00304 '''
00305 self._im_server.clear()
00306 self._im_server.applyChanges()
00307 self._lock.acquire()
00308 self._selected_primitive = -1
00309
00310 if index < 0 or index >= len(self._actions):
00311 rospy.logwarn("Index out of bounds: {}".format(index))
00312 return False
00313
00314 if self.n_actions() > 0 and not self._current_action_id is None:
00315 self.get_current_action().reset_viz()
00316
00317 if not index in self._actions:
00318 rospy.logwarn(
00319 "Can't switch actions: failed to load action {}".format(
00320 index))
00321 return False
00322 else:
00323 rospy.loginfo(
00324 "Switching to action {}".format(
00325 index))
00326
00327 self._current_action_id = index
00328 self._clear_world_objects_srv()
00329 self._lock.release()
00330 try:
00331 rospy.wait_for_message('/fetch_pbd/action_loaded', EmptyMsg, timeout=1000)
00332 except Exception, e:
00333 rospy.logwarn("Timed out waiting for frontend to respond")
00334 self.get_current_action().initialize_viz()
00335 self._update_session_state()
00336 self.publish_primitive_tf()
00337 action = self._actions[self._current_action_id]
00338 for i in range(self.n_primitives()):
00339 try:
00340 self._tf_listener.waitForTransform("base_link",
00341 "primitive_" + str(i),
00342 rospy.Time.now(),
00343 rospy.Duration(5.0))
00344 rospy.loginfo("primitive: {}".format(action.get_primitive(i)))
00345 action.get_primitive(i).update_viz(False)
00346 except Exception, e:
00347 rospy.loginfo("Frame primitive_" + str(i) +
00348 " is not available.")
00349 return True
00350
00351 def switch_to_action_by_name(self, name):
00352 '''Switches to action with name
00353
00354 Args:
00355 name (str): The action name to switch to.
00356
00357 Returns:
00358 bool: Whether successfully switched to index action.
00359 '''
00360 names = self._get_action_names()
00361 if name in names:
00362 index = names.index(name)
00363 return self.switch_to_action_by_index(index)
00364 else:
00365 return False
00366
00367 def next_action(self):
00368 '''Switches to the next action.
00369
00370 Returns:
00371 bool: Whether successfully switched to the next action.
00372 '''
00373 index = self._action_ids.index(self._current_action_id)
00374 if index == len(self._actions) - 1:
00375 rospy.logerr("Already on the last action.")
00376 return False
00377 action_id = self._action_ids[index + 1]
00378 return self.switch_to_action_by_index(action_id)
00379
00380 def previous_action(self):
00381 '''Switches to the previous action.
00382
00383 Returns:
00384 bool: Whether successfully switched to the previous action.
00385 '''
00386 index = self._action_ids.index(self._current_action_id)
00387 if index == 0:
00388 rospy.logerr("Already on the first action.")
00389 return False
00390 action_id = self._action_ids[index - 1]
00391 return self.switch_to_action_by_index(action_id)
00392
00393 def n_primitives(self):
00394 '''Returns the number of primitives in the current action, or 0 if
00395 there is no current action.
00396
00397 Returns:
00398 int
00399 '''
00400 if self.n_actions() > 0 and not self._current_action_id is None:
00401 return self._actions[self._current_action_id].n_primitives()
00402 else:
00403 rospy.logwarn(
00404 "Can't get number of primitives: No actions created yet.")
00405 return 0
00406
00407 def update_action_name(self, name):
00408 '''Update name of current action
00409
00410 Args:
00411 name (string)
00412 '''
00413 if not self._current_action_id is None:
00414 self.get_current_action().set_name(name)
00415 self._update_session_state()
00416
00417 def copy_action(self, action_id):
00418 '''Make a copy of action
00419
00420 Args:
00421 action_id (int)
00422 '''
00423 self._clear_world_objects_srv()
00424
00425 new_id = self.n_actions()
00426
00427 map_fun = '''function(doc) {
00428 emit(doc.id, doc);
00429 }'''
00430
00431 results = self._db.query(map_fun)
00432
00433
00434 for result in results:
00435 if int(result.value['id']) == action_id:
00436 action = Action(self._robot, self._tf_listener, self._im_server,
00437 self._selected_primitive_cb, self._action_change_cb,
00438 grasp_suggestion_service=self._grasp_suggestion_service,
00439 grasp_feedback_topic=self._grasp_feedback_topic,
00440 external_ee_link=self._external_ee_link)
00441 result.value['id'] = new_id
00442 action.build_from_json(result.value)
00443 name = action.get_name()
00444 action.set_name("Copy of " + name)
00445 self._actions[new_id] = action
00446 self._action_ids.append(new_id)
00447
00448 self._current_action_id = new_id
00449 self._update_session_state()
00450
00451
00452 def copy_primitive(self, primitive_number):
00453 '''Make a copy of a primitive
00454
00455 Args:
00456 primitive (int)
00457 '''
00458
00459
00460 map_fun = '''function(doc) {
00461 emit(doc.id, doc);
00462 }'''
00463
00464 results = self._db.query(map_fun)
00465
00466
00467 new_num = self.n_primitives()
00468 for result in results:
00469 if int(result.value['id']) == self._current_action_id:
00470 for idx, primitive in enumerate(result.value['seq']):
00471 if idx == primitive_number:
00472 if primitive.has_key('arm_target'):
00473 target = primitive['arm_target']
00474 primitive_copy = ArmTarget(self._robot,
00475 self._tf_listener,
00476 self._im_server)
00477 primitive_copy.build_from_json(target)
00478 primitive_copy.set_primitive_number(new_num)
00479 break
00480
00481 elif primitive.has_key('arm_trajectory'):
00482 target = primitive['arm_trajectory']
00483 primitive_copy = ArmTrajectory(self._robot,
00484 self._tf_listener,
00485 self._im_server)
00486 primitive_copy.build_from_json(target)
00487 primitive_copy.set_primitive_number(new_num)
00488 break
00489 elif primitive.has_key('grasp'):
00490 target = primitive['grasp']
00491 primitive_copy = Grasp(self._robot,
00492 self._tf_listener,
00493 self._im_server,
00494 self._grasp_suggestion_service,
00495 self._grasp_feedback_topic,
00496 self._external_ee_link)
00497 primitive_copy.build_from_json(target)
00498 primitive_copy.set_primitive_number(new_num)
00499 break
00500
00501 self._actions[self._current_action_id].add_primitive(primitive_copy)
00502
00503 self._actions[self._current_action_id].update_viz()
00504
00505 self._update_session_state()
00506
00507 def delete_action_current_action(self):
00508 '''Delete current action'''
00509 self.delete_action(self._current_action_id)
00510
00511 def delete_action(self, action_id):
00512 '''Deletes action by id
00513
00514 Args:
00515 action_id (string|int)
00516 '''
00517 if self.n_actions > 0:
00518 self._lock.acquire()
00519 rospy.loginfo('Deleting action')
00520 if int(action_id) == self._current_action_id:
00521 if len(self._action_ids) == 1:
00522 self._current_action_id = None
00523 self._actions = {}
00524 self._action_ids = []
00525 action_id_str = str(action_id)
00526 if action_id_str in self._db:
00527 self._db.delete(self._db[action_id_str])
00528 self._lock.release()
00529 self._update_session_state()
00530 return
00531 else:
00532 self._current_action_id-=1
00533
00534 action_id_str = str(action_id)
00535
00536 if action_id in self._actions:
00537 del self._actions[int(action_id)]
00538 if action_id_str in self._db:
00539 self._db.delete(self._db[action_id_str])
00540
00541
00542 for a_id in range(int(action_id) + 1, len(self._actions)):
00543 action = self._actions[a_id]
00544 action.decrease_id()
00545 del self._actions[a_id]
00546 rospy.loginfo("id: {}".format(action.get_action_id()))
00547 self._actions[action.get_action_id()] = action
00548
00549 if str(a_id) in self._db:
00550 self._db.delete(self._db[str(a_id)])
00551
00552 self._update_db_with_action(action)
00553
00554 if len(self._action_ids) > 0:
00555 self._action_ids.pop()
00556 if int(action_id) == self._current_action_id:
00557 self._current_action_id = self._action_ids[-1]
00558 elif int(action_id) < self._current_action_id:
00559 self._current_action_id = self._current_action_id - 1
00560 self._lock.release()
00561 self._update_session_state()
00562
00563 def switch_primitive_order(self, old_index, new_index):
00564 '''Change the order of primitives in action
00565
00566 Args:
00567 old_index (int)
00568 new_index (int)
00569 '''
00570 rospy.loginfo("Switching primitive order")
00571
00572 self._lock.acquire()
00573 action = self._actions[self._current_action_id]
00574 action.switch_primitive_order(old_index, new_index)
00575 self._update_db_with_current_action()
00576 self._lock.release()
00577 self.publish_primitive_tf()
00578 action = self._actions[self._current_action_id]
00579 primitives = action.get_primitives()
00580 for primitive in primitives:
00581 primitive.show_marker()
00582 self._update_session_state()
00583
00584 def delete_primitive(self, primitive_number):
00585 '''Delete specified primitive
00586
00587 Args:
00588 primitive_number (int) : Number of primitive to be deleted
00589 '''
00590
00591 action = self._actions[self._current_action_id]
00592 action.delete_primitive(primitive_number)
00593
00594
00595
00596 def hide_primitive_marker(self, primitive_number):
00597 '''Hide marker with primitive_number
00598
00599 Args:
00600 primitive_number (int)
00601 '''
00602
00603
00604 action = self._actions[self._current_action_id]
00605 action.delete_primitive_marker(primitive_number)
00606 self._update_session_state()
00607
00608
00609 def show_primitive_marker(self, primitive_number):
00610 '''Show marker with primitive_number
00611
00612 Args:
00613 primitive_number (int)
00614 '''
00615
00616
00617 action = self._actions[self._current_action_id]
00618 action.make_primitive_marker(primitive_number)
00619 self._update_session_state()
00620
00621
00622 def execute_primitive(self, primitive_number):
00623 '''Execute primitive with number
00624
00625 Args:
00626 primitive_number (int)
00627 '''
00628 rospy.loginfo("Executing primitive")
00629
00630 action = self._actions[self._current_action_id]
00631 primitive = action.get_primitive(primitive_number)
00632 if primitive.is_object_required():
00633
00634 self._head_busy = True
00635 rospy.loginfo("Object required for execution")
00636 self._robot.look_down()
00637 resp = self._update_world_srv()
00638 if resp.object_list:
00639 rospy.loginfo("Object list not empty")
00640
00641 self.get_current_action().update_objects()
00642 success, msg = primitive.check_pre_condition()
00643 if not success:
00644 rospy.logwarn(
00645 "\tPreconditions of primitive " +
00646 str(primitive.get_name()) + " are not " +
00647 "satisfied. " + msg)
00648 self._status_publisher.publish(
00649 String("Preconditions of primitive " +
00650 str(primitive.get_name()) +
00651 " are not satisfied. " + msg))
00652 primitive.execute()
00653 else:
00654 rospy.logwarn("Needs object(s) but none available")
00655 self._status_publisher.publish(
00656 "Primitive {}".format(primitive.get_name()) +
00657 "requires an object but none are available")
00658 self._head_busy = False
00659 else:
00660 success, msg = primitive.check_pre_condition()
00661 if not success:
00662 rospy.logwarn(
00663 "\tPreconditions of primitive " +
00664 str(primitive.get_name()) + " are not " +
00665 "satisfied. " + msg)
00666 self._status_publisher.publish(
00667 String("Preconditions of primitive " +
00668 str(primitive.get_name()) +
00669 " are not satisfied. " + msg))
00670 primitive.execute()
00671 self._async_update_session_state()
00672
00673
00674 def record_objects(self):
00675 '''Records poses of objects
00676 '''
00677 self._robot.look_down()
00678 resp = self._update_world_srv()
00679 if resp.object_list:
00680 if self.n_actions() > 0:
00681 self.get_current_action().update_objects()
00682 self._async_update_session_state()
00683 self._robot.look_forward()
00684 return True
00685 else:
00686 self._async_update_session_state()
00687 self._robot.look_forward()
00688 return False
00689
00690 def execute_current_action(self):
00691 '''Executes current action
00692
00693 Returns:
00694 bool
00695 '''
00696 if self.n_actions() > 0 and not self._current_action_id is None:
00697
00698 if self.n_primitives() > 0:
00699
00700
00701
00702
00703 if self.get_current_action().is_object_required():
00704
00705 rospy.loginfo("An object is required for this action")
00706 self._robot.look_down()
00707 resp = self._update_world_srv()
00708 self._robot.look_forward()
00709
00710
00711 if resp.object_list:
00712
00713 action = self.get_current_action()
00714 action.update_objects()
00715 action.start_execution()
00716
00717 for i in range(1000):
00718 status = action.get_status()
00719 if status != ExecutionStatus.EXECUTING:
00720 break
00721 if i % 10 == 0:
00722 rospy.loginfo("Still executing")
00723 rospy.sleep(0.1)
00724 if status == ExecutionStatus.SUCCEEDED:
00725 action.end_execution()
00726 self._async_update_session_state()
00727 return True
00728 else:
00729 action.end_execution()
00730 self._async_update_session_state()
00731 return False
00732
00733 else:
00734
00735 rospy.logwarn("An object is required for" +
00736 " this action but none were found")
00737 self._async_update_session_state()
00738 return False
00739 else:
00740
00741 action = self.get_current_action()
00742 action.start_execution()
00743
00744 for i in range(1000):
00745
00746 status = action.get_status()
00747 if status != ExecutionStatus.EXECUTING:
00748 break
00749 if i % 10 == 0:
00750 rospy.loginfo("Still executing")
00751 rospy.sleep(0.1)
00752 if status == ExecutionStatus.SUCCEEDED:
00753 action.end_execution()
00754 self._async_update_session_state()
00755 return True
00756 else:
00757 rospy.logwarn("Execution failed, with status: {}".format(status))
00758 action.end_execution()
00759 self._async_update_session_state()
00760 return False
00761 else:
00762
00763 rospy.logwarn("No primitives recorded")
00764 self._async_update_session_state()
00765 return False
00766 else:
00767
00768 rospy.logwarn("No current action")
00769 self._async_update_session_state()
00770 return False
00771
00772 def publish_primitive_tf(self):
00773 '''Publish tf frame for each primitive of current action'''
00774 if not self._current_action_id is None:
00775
00776 action = self._actions[self._current_action_id]
00777 primitives = action.get_primitives()
00778
00779 for primitive in primitives:
00780 self._publish_primitive_tf(primitive)
00781
00782 def update_primitive_pose(self, primitive_number, position, orientation):
00783 '''Update pose of primitive given by primitive_number
00784
00785 Args:
00786 primitive_number (int)
00787 position (Point)
00788 orientation (OrientationRPY)
00789 '''
00790 action = self._actions[self._current_action_id]
00791 action.update_primitive_pose(primitive_number, position, orientation)
00792
00793
00794
00795
00796
00797 def _get_marker_visibility(self):
00798 '''Get the visibility of the markers
00799
00800 Returns:
00801 [bool]
00802 '''
00803 if self._current_action_id is None:
00804 return []
00805 return self._actions[self._current_action_id].get_marker_visibility()
00806
00807 def _update_db_with_action(self, action, db_file=None):
00808 '''Adds action to db if it does not already exist.
00809 Or if it exists, delete the existing entry and replace with
00810 update version
00811
00812 Args:
00813 action (Action)
00814 '''
00815 rospy.loginfo("Updating database")
00816 if db_file is None:
00817 db_file = self._to_file
00818 action_json = action.get_json()
00819
00820 action_id_str = str(action.get_action_id())
00821 if action_id_str in self._db:
00822
00823 self._db.delete(self._db[action_id_str])
00824 self._db[action_id_str] = action_json
00825 else:
00826 self._db[action_id_str] = action_json
00827 if db_file:
00828 self._json[action.get_action_id()] = action_json
00829 with open(db_file, 'w') as to_file:
00830 json.dump(self._json, to_file)
00831
00832 def _update_db_with_current_action(self):
00833 '''Adds current action to db if it does not already exist.
00834 Or if it exists, delete the existing entry and replace with
00835 update version
00836 '''
00837 action = self.get_current_action()
00838 if not action is None:
00839 self._update_db_with_action(action)
00840
00841
00842 def _selected_primitive_cb(self, selected_primitive):
00843 '''Updates the selected primitive when interactive markers are
00844 clicked on.
00845
00846 Args:
00847 selected_primitive (int): ID of the primitive selected.
00848 '''
00849 rospy.loginfo("Setting primitive to {}".format(selected_primitive))
00850 self._selected_primitive = selected_primitive
00851
00852 self._async_update_session_state()
00853 rospy.loginfo("Done setting primitive to {}".format(selected_primitive))
00854
00855 def _action_change_cb(self):
00856 '''Updates the db when primitive deleted.
00857 '''
00858 self.publish_primitive_tf()
00859 self._async_update_session_state()
00860 rospy.loginfo("Session state updates")
00861
00862 def _get_session_state_cb(self, req):
00863 '''Response to the experiment state service call.
00864
00865 Args:
00866 req (GetSessionStateRequest): Unused.
00867 Returns:
00868 GetSessionStateResponse
00869 '''
00870 return GetSessionStateResponse(self._get_session_state())
00871
00872 def _async_update_session_state(self):
00873 '''Launches a new thread to asynchronously update experiment
00874 state.'''
00875 threading.Thread(group=None,
00876 target=self._update_session_state,
00877 name='session_state_publish_thread').start()
00878
00879 def _update_session_state(self):
00880 '''Publishes a message with the latest state.'''
00881 rospy.loginfo("Session state update")
00882 if len(self._actions) > 0:
00883 self._lock.acquire()
00884 self._update_db_with_current_action()
00885 self._lock.release()
00886 state = self._get_session_state()
00887 self._state_publisher.publish(state)
00888 rospy.loginfo("Session state updated")
00889
00890 def _get_session_state(self):
00891 '''Creates and returns a message with the latest state.
00892
00893 Returns:
00894 SessionState
00895 '''
00896 rospy.loginfo("Getting session state")
00897 index = self._current_action_id
00898
00899
00900 object_list = self._get_object_list_srv().object_list
00901 positions, orientations = self._get_primitive_positions_orientations()
00902 rospy.loginfo("Got positions and orientations")
00903
00904 return SessionState(
00905 self.n_actions(),
00906 index,
00907 self.n_primitives(),
00908 self._selected_primitive,
00909 self._get_action_names(),
00910 self._get_ref_frame_names(),
00911 self._get_primitive_names(),
00912 self._get_actions_disabled(),
00913 self._get_marker_visibility(),
00914 self._get_primitives_editable(),
00915 [],
00916 object_list,
00917 positions,
00918 orientations)
00919
00920 def _get_action_names(self):
00921 '''Return the names of all of the actions in the session
00922
00923 Returns:
00924 [string]
00925 '''
00926 name_list = []
00927 for key in self._actions:
00928
00929 name_list.append(self._actions[key].get_name())
00930
00931 return name_list
00932
00933 def _get_ref_frame_names(self):
00934 '''Returns a list of the names of the reference frames for the
00935 primitives of the current action.
00936
00937 Returns:
00938 [str]
00939 '''
00940
00941 if self.n_actions() < 1 or self._current_action_id is None:
00942 return []
00943
00944 action = self._actions[self._current_action_id]
00945 return action.get_ref_frame_names()
00946
00947 def _get_primitive_positions_orientations(self):
00948 '''Returns positions and orientations of primitives
00949
00950 Returns:
00951 Point[], OrientationRPY[]
00952 '''
00953 if self.n_actions() < 1 or self._current_action_id is None:
00954 return [], []
00955
00956 action = self._actions[self._current_action_id]
00957 return action.get_primitive_positions_orientations()
00958
00959 def _get_primitive_names(self):
00960 '''Returns a list of the names of the
00961 primitives of the current action.
00962
00963 Returns:
00964 [str]
00965 '''
00966
00967 if self.n_actions() < 1 or self._current_action_id is None:
00968 return []
00969
00970 action = self._actions[self._current_action_id]
00971 return action.get_primitive_names()
00972
00973 def _get_actions_disabled(self):
00974 '''Returns whether each action is disabled currently
00975 (due to grasp suggestion not being available)
00976
00977 Returns:
00978 [bool]
00979 '''
00980 if not self._actions_disabled:
00981 return [True] * self.n_actions()
00982 return self._actions_disabled
00983
00984 def _get_primitives_editable(self):
00985 '''Returns list of whether primitive poses are editable
00986
00987 Returns:
00988 [bool]
00989 '''
00990 if self.n_actions() < 1 or self._current_action_id is None:
00991 return []
00992
00993 action = self._actions[self._current_action_id]
00994 return action.get_primitives_editable()
00995
00996 def _load_session_state(self):
00997 '''Loads the experiment state from couchdb database or json file.'''
00998
00999
01000 map_fun = '''function(doc) {
01001 emit(doc.id, doc);
01002 }'''
01003
01004 results = self._db.query(map_fun)
01005
01006
01007 for result in results:
01008 action = Action(self._robot, self._tf_listener, self._im_server,
01009 self._selected_primitive_cb, self._action_change_cb,
01010 grasp_suggestion_service=self._grasp_suggestion_service,
01011 grasp_feedback_topic=self._grasp_feedback_topic,
01012 external_ee_link=self._external_ee_link)
01013 success = action.build_from_json(result.value)
01014 self._actions_disabled.append(not success)
01015 self._actions[int(result.value['id'])] = action
01016 self._action_ids.append(int(result.value['id']))
01017 self._update_db_with_action(action)
01018
01019 if self._from_file:
01020 time_str = datetime.datetime.now().strftime('%c')
01021 for key in self._actions:
01022 action = self._actions[key]
01023 self._update_db_with_action(action, time_str + '.json')
01024
01025 del self._couch['fetch_pbd']
01026 self._db = self._couch.create('fetch_pbd')
01027 self._actions = {}
01028 self._action_ids = []
01029 with open(self._from_file) as json_file:
01030 self._json = json.load(json_file)
01031
01032 keys = self._json.keys()
01033 keys.sort()
01034 self._actions_disabled = []
01035 for key in keys:
01036 action = Action(self._robot, self._tf_listener, self._im_server,
01037 self._selected_primitive_cb, self._action_change_cb,
01038 grasp_suggestion_service=self._grasp_suggestion_service,
01039 grasp_feedback_topic=self._grasp_feedback_topic,
01040 external_ee_link=self._external_ee_link)
01041 success = action.build_from_json(self._json[key])
01042 self._actions_disabled.append(not success)
01043 self._actions[int(self._json[key]['id'])] = action
01044 self._action_ids.append(int(self._json[key]['id']))
01045 self._update_db_with_action(action)
01046
01047 if True in self._actions_disabled:
01048 self._status_publisher.publish(String("Some actions have been " +
01049 "disabled because they require grasp suggestion."))
01050
01051
01052
01053
01054
01055
01056
01057 def _publish_primitive_tf(self, primitive, parent="base_link"):
01058 ''' Publishes a TF for primitive
01059
01060 Args:
01061 primitive (Primitive)
01062 parent (str): The parent reference frame.
01063 '''
01064 try:
01065 marker_pose = primitive.get_absolute_marker_pose()
01066
01067 if marker_pose:
01068 pose = self._tf_listener.transformPose('base_link', marker_pose)
01069 position = pose.pose.position
01070 orientation = pose.pose.orientation
01071 pos = (position.x, position.y, position.z)
01072 rot = (orientation.x, orientation.y,
01073 orientation.z, orientation.w)
01074 name = "primitive_" + str(primitive.get_number())
01075
01076
01077 self._tf_broadcaster.sendTransform(
01078 pos, rot, rospy.Time.now(), name, parent)
01079 except Exception, e:
01080 rospy.logwarn(str(e))