|
14 | 14 | __status__ = 'Development' |
15 | 15 |
|
16 | 16 | import sys, copy, threading, time, signal, math, traceback, timeit, numbers, logging |
| 17 | +from collections import defaultdict |
17 | 18 | import rospy, tf |
18 | 19 | from tf2_msgs.msg import TFMessage |
19 | 20 | import moveit_commander |
|
26 | 27 | from controller_manager_msgs.srv import SwitchController |
27 | 28 |
|
28 | 29 | from arm_commander.tools.moveit_tools import MOVEIT_ERROR_CODE_MAP, GOAL_STATUS_MAP |
| 30 | +from arm_commander.tools.rospkg_tools import PackageFile |
29 | 31 | from arm_commander.states import GeneralCommanderStates, ControllerState |
30 | 32 |
|
| 33 | + |
31 | 34 | class GeneralCommander(): |
32 | 35 | """ |
33 | 36 | GeneralCommander: an interface for robot commander, with this class specifically interfacing |
@@ -93,6 +96,8 @@ def __init__(self, moveit_group_name:str, world_link:str=None) -> None: |
93 | 96 | self.wall_name_list = [] |
94 | 97 | # record the collision objects, including the walls, added to the commander and their color |
95 | 98 | self.object_name_color_list = {} |
| 99 | + # setup custom transforms |
| 100 | + self.custom_transform_object_dict = defaultdict(lambda: None) |
96 | 101 | # publisher for the planning scene |
97 | 102 | self.scene_pub = rospy.Publisher('planning_scene', PlanningScene, queue_size=10) |
98 | 103 | self.tf_pub = tf.TransformBroadcaster() |
@@ -124,14 +129,20 @@ def _pub_objects_color(self): |
124 | 129 | color = self._set_object_color(object_name, *rgba) |
125 | 130 | p.object_colors.append(color) |
126 | 131 | self.scene_pub.publish(p) |
127 | | - |
| 132 | + |
128 | 133 | # publish the transform of the collision objects |
129 | 134 | def _pub_transform_all_objects(self): |
| 135 | + # publish the collision objects |
130 | 136 | objects = self.scene.get_objects() |
131 | 137 | for object_name in objects.keys(): |
132 | 138 | pose_of_object = objects[object_name].pose |
133 | 139 | frame = objects[object_name].header.frame_id |
134 | 140 | self._pub_transform_object(object_name, pose_of_object, frame) |
| 141 | + # publish the custom transform objects |
| 142 | + for name in self.custom_transform_object_dict: |
| 143 | + the_transform = self.custom_transform_object_dict[name] |
| 144 | + xyzrpy = the_transform['xyzrpy'] |
| 145 | + self._pub_transform_object(name, xyzrpy, the_transform['frame']) |
135 | 146 |
|
136 | 147 | # publish the transform of a specific named object |
137 | 148 | def _pub_transform_object(self, name, pose, frame=None) -> None: |
@@ -1084,6 +1095,11 @@ def add_object_to_scene(self, object_name:str, model_file:str, object_scale:list |
1084 | 1095 | reference_frame = self.WORLD_REFERENCE_LINK if reference_frame is None else reference_frame |
1085 | 1096 | self.scene.remove_world_object(object_name) |
1086 | 1097 | object_pose = conversions.list_to_pose_stamped(xyz + rpy, reference_frame) |
| 1098 | + try: |
| 1099 | + model_file = PackageFile.resolve_to_path(model_file) |
| 1100 | + except Exception as ex: |
| 1101 | + logger.warning(f'SceneToRViz (display_objects): Invalid model_file for object ({model_file}): {ex}') |
| 1102 | + return |
1087 | 1103 | self.scene.add_mesh( |
1088 | 1104 | object_name, object_pose, |
1089 | 1105 | model_file, object_scale |
@@ -1297,6 +1313,49 @@ def _set_object_color(self, name, r, g, b, a = 0.9) -> ObjectColor: |
1297 | 1313 | color.color.a = a |
1298 | 1314 | return color |
1299 | 1315 |
|
| 1316 | + # -------------------------------- |
| 1317 | + # functions for adding custom transforms |
| 1318 | + def add_custom_transform(self, name, xyz, rpy, parent_frame=None) -> None: |
| 1319 | + """ Add a custom transform to the rviz visualizer, which is broadcast regularly |
| 1320 | +
|
| 1321 | + :param name: the name of the transform |
| 1322 | + :param xyz: the xyz pose |
| 1323 | + :param rpy: the rpy pose |
| 1324 | + :param parent_frame: the reference frame |
| 1325 | + """ |
| 1326 | + if name is None or xyz is None or rpy is None: |
| 1327 | + logger.error(f'SceneToRViz (add_custom_transform): No parameter can be None') |
| 1328 | + raise AssertionError('A parameter is none') |
| 1329 | + self.custom_transform_object_dict[name] = {'xyzrpy': xyz + rpy, 'frame': parent_frame} |
| 1330 | + |
| 1331 | + def update_custom_transform_pose(self, name, xyz=None, rpy=None, parent_frame=None) -> None: |
| 1332 | + """ Update the pose of a custom transform |
| 1333 | +
|
| 1334 | + :param name: the name of the transform to be updated |
| 1335 | + :param xyz: the updated xyz, defaults to None meaning unchanged |
| 1336 | + :param rpy: the updated rpy, defaults to None meaning unchanged |
| 1337 | + :param frame: the updated frame, defaults to None meaning unchanged |
| 1338 | + """ |
| 1339 | + transform_object = self.custom_transform_object_dict[name] |
| 1340 | + if transform_object is None: |
| 1341 | + logger.warning(f'__name__ (update_custom_transform_pose): the custom transform name {name} is not found') |
| 1342 | + return False |
| 1343 | + xyz = xyz if xyz is not None else transform_object['xyzrpy'][:3] |
| 1344 | + rpy = rpy if rpy is not None else transform_object['xyzrpy'][3:] |
| 1345 | + parent_frame = parent_frame if xyz is not None else transform_object['frame'] |
| 1346 | + self.add_custom_transform(name, xyz, rpy, parent_frame) |
| 1347 | + |
| 1348 | + def remove_custom_transform(self, name=None): |
| 1349 | + """ Clear a custom transform or all if name is None |
| 1350 | +
|
| 1351 | + :param name: the name of the transform to be removed, or None to remove all |
| 1352 | + """ |
| 1353 | + if name is None: |
| 1354 | + self.custom_transform_object_dict.clear() |
| 1355 | + elif name in self.custom_transform_object_dict: |
| 1356 | + del self.custom_transform_object_dict[name] |
| 1357 | + |
| 1358 | + |
1300 | 1359 | # -------------------------------- |
1301 | 1360 | # functions for setting path constraints |
1302 | 1361 |
|
|
0 commit comments