4 Copyright (c) 2016, Allgeyer Tobias, Aumann Florian, Borella Jocelyn, Hutmacher Robin, Karrenbauer Oliver, Marek Felix, Meissner Pascal, Trautmann Jeremias, Wittenbeck Valerij 8 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 10 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 12 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 14 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 from asr_next_best_view.msg
import RobotStateMessage, NormalsInfo
31 from asr_world_model.srv
import GetViewportList, FilterViewportDependingOnAlreadyVisitedViewports
32 from asr_msgs.msg
import (AsrAttributedPointCloud, AsrAttributedPoint, AsrViewport)
33 from geometry_msgs.msg
import (Pose, PoseWithCovariance,
34 PoseWithCovarianceStamped, Point, Quaternion, Twist)
36 from common.evaluation_decorators
import *
38 import common.state_acquisition
as state_acquisition
41 States and methods for using the Next-Best-View package. 44 global rejectedPointCloud
45 rejectedPointCloud = []
46 global numSetPointCloud
48 global useGoalCameraPoseAtNextNBVUpdatePointCloud
49 useGoalCameraPoseAtNextNBVUpdatePointCloud =
False 53 Initializes the point cloud for next_best_view. 54 If there is already a point cloud set, this state overwrites it. 59 self, outcomes=[
'succeeded',
'aborted',
'too_many_deactivated_normals'],
60 input_keys=[
'object_pointcloud'])
64 rospy.loginfo(
'Init NBV_SET_POINT_CLOUD')
68 if rospy.get_param(
"~SavePointClouds"):
69 os.makedirs(__builtin__.log_dir +
"/PointCloud")
74 rospy.loginfo(
'Executing NBV_SET_POINT_CLOUD')
79 rospy.wait_for_service(
'/nbv/set_point_cloud', timeout=5)
80 rospy.wait_for_service(
'/nbv/remove_objects', timeout=5)
81 rospy.wait_for_service(
'/env/asr_world_model/get_viewport_list', timeout=5)
82 except rospy.exceptions.ROSException, e:
83 rospy.loginfo(
"Couldn't reach service")
89 set_pc = rospy.ServiceProxy(
'/nbv/set_point_cloud', SetAttributedPointCloud)
90 invalidate_point_cloud = rospy.ServiceProxy(
'/nbv/remove_objects', RemoveObjects)
91 get_viewports = rospy.ServiceProxy(
'/env/asr_world_model/get_viewport_list', GetViewportList)
94 pointCloud = userdata.object_pointcloud
96 if rospy.get_param(
"~recoverLostHypothesis"):
97 global rejectedPointCloud
98 pointCloud.elements += rejectedPointCloud
99 if (len(rejectedPointCloud) > 0):
100 rospy.loginfo(
"added " + str(len(rejectedPointCloud)) +
" old points to pc")
101 rejectedPointCloud = []
102 viewports = get_viewports(
'all').viewport_list
103 set_pc_rsp = set_pc(pointCloud, viewports)
106 if rospy.get_param(
"~SavePointClouds"):
107 global numSetPointCloud
108 pointCloudFile = open(__builtin__.log_dir +
"/PointCloud/PointCloud_" + str(numSetPointCloud),
"wb")
109 viewportsFile = open(__builtin__.log_dir +
"/PointCloud/Viewports_" + str(numSetPointCloud),
"wb")
110 pickle.dump(pointCloud, pointCloudFile)
111 pickle.dump(viewports, viewportsFile)
112 pointCloudFile.close()
113 viewportsFile.close()
114 numSetPointCloud += 1
118 all_percentages_too_low =
True 120 for normalInfo
in set_pc_rsp.normals_per_object:
121 rospy.loginfo(
"Number of active object normals in original point cloud for type " + \
122 normalInfo.type +
" and id " + normalInfo.identifier +
": " + str(normalInfo.active_normals))
123 rospy.loginfo(
"Number of deactivated normals for type " + \
124 normalInfo.type +
" and id " + normalInfo.identifier +
": " + str(normalInfo.deactivated_object_normals))
126 if normalInfo.active_normals == 0:
129 quotient = 1.0 * normalInfo.deactivated_object_normals / normalInfo.active_normals
130 rospy.loginfo(
"Quotient of deactivated_object_normals / set_pc_rsp.active_normals for type " + \
131 normalInfo.type +
" and id " + normalInfo.identifier +
": " + str(quotient))
133 all_percentages_too_low =
False 137 if all_percentages_too_low ==
True:
138 rospy.logwarn(
"Percentage of active normals in cloud too low for all types and ids. " + \
139 "Calculating different point cloud for NBV estimation instead.")
140 if rospy.get_param(
"~recoverLostHypothesis"):
141 get_pc = rospy.ServiceProxy(
"/nbv/get_point_cloud", GetAttributedPointCloud)
142 rejectedPointCloud += get_pc().point_cloud.elements
143 return 'too_many_deactivated_normals' 146 if rospy.get_param(
"~recoverLostHypothesis"):
147 get_pc = rospy.ServiceProxy(
"/nbv/get_point_cloud", GetAttributedPointCloud)
148 filteredPC = get_pc()
149 for normalInfo
in set_pc_rsp.normals_per_object:
150 if normalInfo.active_normals == 0:
153 quotient = 1.0 * normalInfo.deactivated_object_normals / normalInfo.active_normals
156 rospy.logwarn(
"Percentage of active normals in cloud too low for type " + \
157 normalInfo.type +
" and id " + normalInfo.identifier +
". Erase all normals for type and id in point_cloud.")
160 if rospy.get_param(
"~recoverLostHypothesis"):
162 for obj
in filteredPC.point_cloud.elements:
163 if (obj.type == normalInfo.type
and obj.identifier == normalInfo.identifier):
164 rejectedPointCloud.append(obj)
166 result = invalidate_point_cloud(normalInfo.type, normalInfo.identifier)
167 if not result.is_valid:
169 return 'too_many_deactivated_normals' 171 if set_pc_rsp.is_valid ==
False:
176 except rospy.ServiceException, e:
177 rospy.logwarn(str(e))
183 Calculates NextBestView given a pose 187 smach.State.__init__(
189 outcomes=[
'found_next_best_view',
'aborted',
'no_nbv_found',
'nbv_update_point_cloud'],
190 output_keys=[
'goal_camera_pose',
'goal_robot_pose',
'goal_ptu_position',
'searched_object_types'])
195 rospy.loginfo(
'Executing NEXT_BEST_VIEW')
197 rospy.wait_for_service(
'/nbv/next_best_view')
201 get_nbv = rospy.ServiceProxy(
'/nbv/next_best_view', GetNextBestView)
202 min_utility_for_moving = rospy.get_param(
"/scene_exploration_sm/min_utility_for_moving")
205 current_camera_pose = state_acquisition.get_camera_pose_cpp()
206 rospy.loginfo(
"This is the current camera pose, given to NBV: " + str(current_camera_pose))
208 get_nbv_rsp = get_nbv(current_camera_pose)
211 if get_nbv_rsp.found ==
False:
212 rospy.logwarn(
"Could not find any pose with rating > 0 in next best view estimation, aborting...")
213 if rospy.get_param(
"~recoverLostHypothesis"):
214 get_pc = rospy.ServiceProxy(
"/nbv/get_point_cloud", GetAttributedPointCloud)
215 global rejectedPointCloud
216 rejectedPointCloud += get_pc().point_cloud.elements
217 return 'no_nbv_found' 219 rospy.loginfo(
"This is the camera pose, returned by NBV: " + str(get_nbv_rsp))
223 userdata.goal_camera_pose = get_nbv_rsp.viewport.pose
226 userdata.searched_object_types = get_nbv_rsp.viewport.object_type_name_list
230 quaternion = tf.transformations.quaternion_from_euler(0, 0, get_nbv_rsp.robot_state.rotation)
231 move_pose.position = Point(get_nbv_rsp.robot_state.x,
232 get_nbv_rsp.robot_state.y,
234 move_pose.orientation = Quaternion(*quaternion)
236 userdata.goal_robot_pose = move_pose
239 pan = math.trunc(get_nbv_rsp.robot_state.pan * (180 / numpy.pi))
240 tilt = math.trunc(get_nbv_rsp.robot_state.tilt * (180 / numpy.pi))
241 rospy.logdebug(
"PTU from nbv robot state in deg - pan: " + str(pan) +
"| tilt: " + str(tilt))
242 userdata.goal_ptu_position = [pan, tilt]
244 viewport = get_nbv_rsp.viewport
246 if rospy.get_param(
"/scene_exploration_sm/filter_viewports"):
247 rospy.wait_for_service(
'/env/asr_world_model/filter_viewport_depending_on_already_visited_viewports')
248 filterViewportServ = rospy.ServiceProxy(
'/env/asr_world_model/filter_viewport_depending_on_already_visited_viewports',
249 FilterViewportDependingOnAlreadyVisitedViewports)
250 filterViewportResp = filterViewportServ(viewport)
252 if filterViewportResp.isBeenFiltered:
253 rospy.logwarn(
"Viewport was already visited -> filtered objectTypes to search: " + str(filterViewportResp.filteredViewport.object_type_name_list))
254 if len(filterViewportResp.filteredViewport.object_type_name_list) == 0:
255 rospy.logwarn(
"No objects to search -> nbv_update_point_cloud")
256 global useGoalCameraPoseAtNextNBVUpdatePointCloud
257 useGoalCameraPoseAtNextNBVUpdatePointCloud =
True 259 return 'nbv_update_point_cloud' 261 viewport = filterViewportResp.filteredViewport
262 userdata.searched_object_types = filterViewportResp.filteredViewport.object_type_name_list
265 if (min_utility_for_moving > get_nbv_rsp.utility):
266 rospy.logwarn(
"Utility in found next best view estimate too low for moving to it, aborting...")
267 if rospy.get_param(
"~recoverLostHypothesis"):
268 get_pc = rospy.ServiceProxy(
"/nbv/get_point_cloud", GetAttributedPointCloud)
269 global rejectedPointCloud
270 rejectedPointCloud += get_pc().point_cloud.elements
271 return 'no_nbv_found' 274 trigger_nbv_vis = rospy.ServiceProxy(
'/nbv/trigger_frustums_and_point_cloud_visualization', TriggerFrustumsAndPointCloudVisualization)
275 trigger_nbv_vis(viewport)
278 if hasattr(__builtin__,
'log_dir'):
279 with open(__builtin__.log_dir +
'/nbv_results.csv',
'a')
as log:
280 logwriter = csv.writer(log, delimiter=
' ',
281 quotechar=
'|', quoting=csv.QUOTE_MINIMAL)
282 logwriter.writerow([time(), str(get_nbv_rsp)])
284 return 'found_next_best_view' 285 except rospy.ServiceException, e:
286 rospy.logwarn(
"ServiceException from NextBestView: " + str(e))
293 Updates the pointcloud for next_best_view with the actual pose. 295 Note that the actual pose differs from the calculated nbv pose, so 296 that we have to get the actual camera pose to update here. 300 smach.State.__init__(
302 outcomes=[
'succeeded',
'aborted',
'no_nbv_found'],
303 input_keys=[
'goal_camera_pose',
'searched_object_types'],
304 output_keys=[
'deactivated_object_normals_count'])
309 rospy.loginfo(
'Init NEXT_BEST_VIEW_UPDATE')
311 self.
mode = rospy.get_param(
"/scene_exploration_sm/mode")
332 rospy.loginfo(
'Executing NEXT_BEST_VIEW_UPDATE')
336 rospy.wait_for_service(
'/nbv/update_point_cloud')
340 if self.
mode == 5
or self.
mode == 6:
341 self.
searched_object_types = [rospy.get_param(
'/scene_exploration_sm/PlaceholderObjectTypeInCropboxSearch')]
344 if not isinstance(userdata.searched_object_types, list):
350 nbv_update = rospy.ServiceProxy(
'/nbv/update_point_cloud', UpdatePointCloud)
355 global useGoalCameraPoseAtNextNBVUpdatePointCloud
356 if useGoalCameraPoseAtNextNBVUpdatePointCloud:
357 useGoalCameraPoseAtNextNBVUpdatePointCloud =
False 358 current_camera_pose = userdata.goal_camera_pose
360 current_camera_pose = state_acquisition.get_camera_pose()
362 rospy.loginfo(
"Deactivating normals in predicted cloud based on camera pose : " + str(current_camera_pose) +
" and on objects " + str(list(self.
searched_object_types)))
364 rospy.loginfo(
"Number of deactivated normals: " + str(rsp.deactivated_object_normals))
365 userdata.deactivated_object_normals_count = rsp.deactivated_object_normals
368 if rsp.deactivated_object_normals == 0:
369 rospy.logwarn(
"View, reached by robot, differs from NBV and allows no update.")
371 if state_acquisition.approx_equal_pose(userdata.goal_camera_pose, self.
last_calculated_pose, 0.2):
372 rospy.loginfo(
"Robot did not move enough after NBV estimation. Updating cloud with NBV estimate: " + str(userdata.goal_camera_pose))
375 rospy.loginfo(
"Number of deactivated normals: " + str(rsp.deactivated_object_normals))
381 rospy.loginfo(
"Remaining attempts till no_nbv_found: " + str(self.
remaining_attempts))
385 rospy.loginfo(
"Two NBV estimations deactivated no normals. Aborting object search loop.")
387 if rospy.get_param(
"~recoverLostHypothesis"):
388 get_pc = rospy.ServiceProxy(
"/nbv/get_point_cloud", GetAttributedPointCloud)
389 global rejectedPointCloud
390 rejectedPointCloud += get_pc().point_cloud.elements
391 return 'no_nbv_found';
395 except rospy.ServiceException, e:
396 rospy.logwarn(str(e))
402 getRobotState = state_acquisition.GetRobotState()
403 robotState = getRobotState.get_robot_state()
404 rospy.loginfo(
"Transmitting current robot state to NBV: (Pan: " + str(robotState.pan) +
", Tilt: " + str(robotState.tilt) +
", Rotation: " + str(robotState.rotation) +
", X: " + str(robotState.x) +
", Y: " + str(robotState.y) +
")")
406 rospy.wait_for_service(
'/nbv/set_init_robot_state')
407 set_init_state = rospy.ServiceProxy(
'/nbv/set_init_robot_state', SetInitRobotState)
408 set_init_state(robotState)
def execute(self, userdata)
def resetRemainingAttempts(self)
percentage_too_many_deactivated
def execute(self, userdata)
def execute(self, userdata)