1515
1616import sys , copy , threading , time , signal , math , traceback , timeit , numbers , logging
1717from collections import defaultdict
18+ import numpy as np
19+ from scipy .spatial .transform import Rotation as R
20+ import tf .transformations
1821import rospy , tf , tf2_ros , tf2_geometry_msgs
1922from tf2_msgs .msg import TFMessage
2023import moveit_commander
3437
3538from moveit_calibration_detector .srv import TargetDimension , IsTargetDetected
3639
40+ from .tank_least_squares import TankLeastSquares
41+
3742class GeneralCommander ():
3843 """
3944 GeneralCommander: an interface for robot commander, with this class specifically interfacing
@@ -1253,7 +1258,72 @@ def is_target_visible(self, timeout:float=10.0) -> bool:
12531258 time .sleep (0.5 )
12541259 return False
12551260
1256- def capture_target_sequence (self , script_file :str ) -> bool :
1261+ def init_transform_listener (self ):
1262+ print ("Setting up (inside) the listener..." )
1263+ if self .tf_buffer is None :
1264+ print ("The listener is not set up" )
1265+ self .tf_buffer = tf2_ros .Buffer ()
1266+ self .tf_listener = tf2_ros .TransformListener (self .tf_buffer )
1267+ print ("The listener is NOW set up" )
1268+
1269+ def get_transform_as_pose (self , tf_buffer , from_frame , to_frame ):
1270+ try :
1271+ transform = tf_buffer .lookup_transform (from_frame , to_frame , rospy .Time (0 ), rospy .Duration (1 ))
1272+ if transform is None :
1273+ return None
1274+
1275+ pose = Pose ()
1276+ pose .position .x = transform .transform .translation .x
1277+ pose .position .y = transform .transform .translation .y
1278+ pose .position .z = transform .transform .translation .z
1279+ pose .orientation .x = transform .transform .rotation .x
1280+ pose .orientation .y = transform .transform .rotation .y
1281+ pose .orientation .z = transform .transform .rotation .z
1282+ pose .orientation .w = transform .transform .rotation .w
1283+ print (f"The position between ({ from_frame } and { to_frame } ) is: { pose .position } " )
1284+ except tf2_ros .LookupException as e :
1285+ rospy .logerr (f'Lookup exception received: { e } ' )
1286+ return None
1287+ except tf .ExtrapolationException as e :
1288+ rospy .logerr (f'Extrapolation exception received: { e } ' )
1289+ return None
1290+ return pose
1291+
1292+ def capture_joints (self ):
1293+ print ("Setting up the listener..." )
1294+ self .init_transform_listener ()
1295+ try :
1296+ object_pose = self .get_transform_as_pose (self .tf_buffer , 'camera_color_optical_frame' , 'handeye_target' )
1297+ effector_pose = self .get_transform_as_pose (self .tf_buffer , 'base_link' , 'tool0' )
1298+ except tf .ExtrapolationException as e :
1299+ rospy .logerr (f'Extrapolation exception received: { e } ' )
1300+ return
1301+
1302+ if object_pose is None or effector_pose is None :
1303+ return
1304+
1305+ T_obj_xyz = np .array ([object_pose .position .x , object_pose .position .y , object_pose .position .z ])
1306+ obj_rpy = tf .transformations .euler_from_quaternion ([object_pose .orientation .x , object_pose .orientation .y , object_pose .orientation .z , object_pose .orientation .w ])
1307+ T_obj_rpy = np .array (obj_rpy )
1308+ T_obj = np .eye (4 )
1309+ T_obj [:3 , 3 ] = T_obj_xyz
1310+ r = R .from_euler ('xyz' , T_obj_rpy )
1311+ T_obj [:3 , :3 ] = r .as_matrix ()
1312+
1313+ T_eff_xyz = np .array ([effector_pose .position .x , effector_pose .position .y , effector_pose .position .z ])
1314+ eff_rpy = tf .transformations .euler_from_quaternion ([effector_pose .orientation .x , effector_pose .orientation .y , effector_pose .orientation .z , effector_pose .orientation .w ])
1315+ T_eff_rpy = np .array (eff_rpy )
1316+ T_eff = np .eye (4 )
1317+ T_eff [:3 , 3 ] = T_eff_xyz
1318+ r = R .from_euler ('xyz' , T_eff_rpy )
1319+ T_eff [:3 , :3 ] = r .as_matrix ()
1320+
1321+ # list of rows of T_obj
1322+ object_pose_list = T_obj .flatten ().tolist ()
1323+ effector_pose_list = T_eff .flatten ().tolist ()
1324+ self .capture_results .append ({'effector_wrt_world' : effector_pose_list , 'object_wrt_sensor' : object_pose_list })
1325+
1326+ def capture_target_sequence (self , script_file :str ):
12571327
12581328 import yaml
12591329 # Read
@@ -1263,6 +1333,7 @@ def capture_target_sequence(self, script_file:str) -> bool:
12631333 joint_values = joint_state_dict ['joint_values' ]
12641334 print (f"Number of locations read: { len (joint_values )} " )
12651335
1336+ self .capture_results = []
12661337 for idx , joint_position in enumerate (joint_values ):
12671338 print (f"Moving to joint position { idx + 1 } /{ len (joint_values )} : { joint_position } \n " )
12681339
@@ -1272,13 +1343,12 @@ def capture_target_sequence(self, script_file:str) -> bool:
12721343 except Exception as e :
12731344 print (f"Failed to move to joint position { idx + 1 } /{ len (joint_values )} : { joint_position } " )
12741345 print (e )
1275- return False
1346+ return []
12761347
12771348 time .sleep (1 )
1349+ self .capture_joints ()
12781350
1279- return True
1280-
1281-
1351+ return self .capture_results
12821352
12831353 def calibrate_tank (self , reference_frame :str = None , reference_pose :Pose = None ) -> Pose :
12841354 self .move_to_named_pose ('named_poses.stow' , True )
@@ -1301,8 +1371,13 @@ def calibrate_tank(self, reference_frame:str=None, reference_pose:Pose=None) ->
13011371 tag_1_script = ''
13021372 tag_2_script = ''
13031373 tag_3_script = ''
1374+ tag_1_samples = []
1375+ tag_2_samples = []
1376+ tag_3_samples = []
1377+ tank_id = ''
13041378
13051379 if reference_frame .endswith ('0' ):
1380+ tank_id = '0'
13061381 tank_ready_named_pose = 'named_poses.tank-0'
13071382 tag_1 = 'named_poses.tag-D'
13081383 tag_2 = 'named_poses.tag-E'
@@ -1313,6 +1388,7 @@ def calibrate_tank(self, reference_frame:str=None, reference_pose:Pose=None) ->
13131388 tag_3_script = tag_F_script
13141389
13151390 elif reference_frame .endswith ('1' ):
1391+ tank_id = '1'
13161392 tank_ready_named_pose = 'named_poses.tank-1'
13171393 tag_1 = 'named_poses.tag-A'
13181394 tag_2 = 'named_poses.tag-B'
@@ -1337,91 +1413,65 @@ def calibrate_tank(self, reference_frame:str=None, reference_pose:Pose=None) ->
13371413 # Move to Tag 1
13381414 self .move_to_named_pose (tag_1 , True )
13391415 # -- Ensure tag is visible
1340- self .is_target_visible (timeout = 10.0 )
1416+ if self .is_target_visible (timeout = 10.0 ) == False :
1417+ rospy .logerr ('The commander (calibrate_tank): tag 1 not visible' )
1418+ return center
13411419 # -- Calibration sequence for tag_1
1342- sequence_result = self .capture_target_sequence (tag_1_script )
1343- if not sequence_result :
1420+ tag_1_samples = self .capture_target_sequence (tag_1_script )
1421+ if len ( tag_1_samples ) == 0 :
13441422 rospy .logerr ('The commander (calibrate_tank): failed to capture the target sequence for tag 1' )
1345- # TODO: return to safe pose
1423+ self .move_to_named_pose (tank_ready_named_pose , True )
1424+ self .move_to_named_pose ('named_poses.ready' , True )
13461425 return center
13471426
13481427 # Move to Tag 2
1428+ self .move_to_named_pose (tank_ready_named_pose , True )
13491429 self .move_to_named_pose (tag_2 , True )
13501430 # -- Ensure tag is visible
1351- self .is_target_visible (timeout = 10.0 )
1431+ if self .is_target_visible (timeout = 10.0 ) == False :
1432+ rospy .logerr ('The commander (calibrate_tank): tag 2 not visible' )
1433+ return center
13521434 # -- Calibration sequence for tag_2
1353- sequence_result = self .capture_target_sequence (tag_2_script )
1354- if not sequence_result :
1435+ tag_2_samples = self .capture_target_sequence (tag_2_script )
1436+ if len ( tag_2_samples ) == 0 :
13551437 rospy .logerr ('The commander (calibrate_tank): failed to capture the target sequence for tag 1' )
1356- # TODO: return to safe pose
1438+ self .move_to_named_pose (tank_ready_named_pose , True )
1439+ self .move_to_named_pose ('named_poses.ready' , True )
13571440 return center
13581441
13591442 # Move to Tag 3
1443+ self .move_to_named_pose (tank_ready_named_pose , True )
13601444 self .move_to_named_pose (tag_3 , True )
13611445 # -- Ensure tag is visible
1362- self .is_target_visible (timeout = 10.0 )
1446+ if self .is_target_visible (timeout = 10.0 ) == False :
1447+ rospy .logerr ('The commander (calibrate_tank): tag 3 not visible' )
1448+ return center
13631449 # -- Calibration sequence for tag_3
1364- sequence_result = self .capture_target_sequence (tag_3_script )
1365- if not sequence_result :
1450+ tag_3_samples = self .capture_target_sequence (tag_3_script )
1451+ if len ( tag_3_samples ) == 0 :
13661452 rospy .logerr ('The commander (calibrate_tank): failed to capture the target sequence for tag 1' )
1367- # TODO: return to safe pose
1453+ self .move_to_named_pose (tank_ready_named_pose , True )
1454+ self .move_to_named_pose ('named_poses.ready' , True )
13681455 return center
13691456
1457+ # -- Process the captured samples
1458+ why = TankLeastSquares (tank_id , tag_1_samples , tag_2_samples , tag_3_samples )
1459+ center = why .get_tank_center_pose ()
1460+ # transform center to world_tf
1461+ center_posestamped = PoseStamped ()
1462+ center_posestamped .header .frame_id = 'base_link'
1463+ center_posestamped .header .stamp = rospy .Time .now ()
1464+ center_posestamped .pose = center
1465+
1466+ self .init_transform_listener ()
1467+ transformed_pose = self .tf_buffer .transform (center_posestamped , self .WORLD_REFERENCE_LINK , rospy .Duration (1 ))
1468+ center = transformed_pose .pose
1469+
13701470 # Move to Tank Ready Pose
13711471 self .move_to_named_pose (tank_ready_named_pose , True )
13721472 self .move_to_named_pose ('named_poses.stow' , True )
13731473
1374- if reference_frame .endswith ('0' ):
1375- # lookup transform from /robot_footprint to /tank_center
1376- center_tf = self .tf_buffer .lookup_transform (self .WORLD_REFERENCE_LINK , 'tank_center' , rospy .Time (0 ), rospy .Duration (4.0 ))
1377- center .position .x = center_tf .transform .translation .x
1378- center .position .y = center_tf .transform .translation .y
1379- center .position .z = center_tf .transform .translation .z
1380- center .orientation .x = center_tf .transform .rotation .x
1381- center .orientation .y = center_tf .transform .rotation .y
1382- center .orientation .z = center_tf .transform .rotation .z
1383- center .orientation .w = center_tf .transform .rotation .w
1384-
1385- print (f'Calibrating tank { reference_frame } with WORLD_REFERENCE_LINK { self .WORLD_REFERENCE_LINK } and center: { center } ' )
1386- #input('Press Enter to continue...')
1387-
1388- #center.position.x = -0.029
1389- #center.position.y = -1.184
1390- #center.position.z = 0.197
1391- #center.orientation.x = 0.009
1392- #center.orientation.y = 0.003
1393- #center.orientation.z = 0.999
1394- #center.orientation.w = -0.036
1395- #- Rotation: in Quaternion [0.009, 0.003, 0.999, -0.036]
1396- elif reference_frame .endswith ('1' ):
1397- # lookup transform from /robot_footprint to /tank_center
1398- center_tf = self .tf_buffer .lookup_transform (self .WORLD_REFERENCE_LINK , 'tank_center' , rospy .Time (0 ), rospy .Duration (4.0 ))
1399- center .position .x = center_tf .transform .translation .x
1400- center .position .y = center_tf .transform .translation .y
1401- center .position .z = center_tf .transform .translation .z
1402- center .orientation .x = center_tf .transform .rotation .x
1403- center .orientation .y = center_tf .transform .rotation .y
1404- center .orientation .z = center_tf .transform .rotation .z
1405- center .orientation .w = center_tf .transform .rotation .w
1406-
1407- print (f'Calibrating tank { reference_frame } with WORLD_REFERENCE_LINK { self .WORLD_REFERENCE_LINK } and center: { center } ' )
1408- #input('Press Enter to continue...')
1409-
1410- #center.position.x = -0.006
1411- #center.position.y = 1.188
1412- #center.position.z = 0.218
1413- #center.orientation.x = -0.000
1414- #center.orientation.y = 0.000
1415- #center.orientation.z = 0.007
1416- #center.orientation.w = 1.000
1417- #- Rotation: in Quaternion [-0.000, 0.000, 0.007, 1.000]
1418-
14191474 return center
1420-
1421-
1422- # returns a list of current objects that have been added to the commander
1423- """ Returns a list of current objects that have been added to the commander
1424- """
14251475
14261476 def list_object_names (self ) -> list :
14271477 return self .scene .get_known_object_names ()
0 commit comments