@@ -940,7 +940,7 @@ def ensure_geometry(self):
940940 # constraints
941941 # ==========================================================================
942942
943- def orientation_constraint_from_frame (self , frame_WCF , tolerances_axes , group = None ):
943+ def orientation_constraint_from_frame (self , frame_WCF , tolerances_axes , group = None , use_attached_tool_frame = True ):
944944 r"""Create an orientation constraint from a frame on the group's end-effector link.
945945
946946 Parameters
@@ -953,6 +953,9 @@ def orientation_constraint_from_frame(self, frame_WCF, tolerances_axes, group=No
953953 group: :obj:`str`, optional
954954 The planning group for which we specify the constraint. Defaults to
955955 the robot's main planning group.
956+ use_attached_tool_frame : :obj:`bool`, optional
957+ If ``True`` and there is a tool attached to the planning group, it will use its TCF
958+ instead of the T0CF to create the constraints. Defaults to ``True``.
956959
957960 Returns
958961 -------
@@ -982,16 +985,21 @@ def orientation_constraint_from_frame(self, frame_WCF, tolerances_axes, group=No
982985 OrientationConstraint('ee_link', [0.5, 0.5, 0.5, 0.5], [0.017453292519943295, 0.017453292519943295, 0.017453292519943295], 1.0)
983986 """
984987
988+ attached_tool = self .attached_tools .get (group )
989+ if use_attached_tool_frame and attached_tool :
990+ frame_WCF = self .from_tcf_to_t0cf ([frame_WCF ], group )[0 ]
991+
985992 ee_link = self .get_end_effector_link_name (group )
986993
987994 tolerances_axes = list (tolerances_axes )
988995 if len (tolerances_axes ) == 1 :
989996 tolerances_axes *= 3
990997 elif len (tolerances_axes ) != 3 :
991998 raise ValueError ("Must give either one or 3 values" )
999+
9921000 return OrientationConstraint (ee_link , frame_WCF .quaternion , tolerances_axes )
9931001
994- def position_constraint_from_frame (self , frame_WCF , tolerance_position , group = None ):
1002+ def position_constraint_from_frame (self , frame_WCF , tolerance_position , group = None , use_attached_tool_frame = True ):
9951003 """Create a position constraint from a frame on the group's end-effector link.
9961004
9971005 Parameters
@@ -1004,6 +1012,9 @@ def position_constraint_from_frame(self, frame_WCF, tolerance_position, group=No
10041012 group: :obj:`str`, optional
10051013 The planning group for which we specify the constraint. Defaults to
10061014 the robot's main planning group.
1015+ use_attached_tool_frame : :obj:`bool`, optional
1016+ If ``True`` and there is a tool attached to the planning group, it will use its TCF
1017+ instead of the T0CF to create the constraints. Defaults to ``True``.
10071018
10081019 Returns
10091020 -------
@@ -1032,11 +1043,15 @@ def position_constraint_from_frame(self, frame_WCF, tolerance_position, group=No
10321043 PositionConstraint('ee_link', BoundingVolume(2, Sphere(Point(0.400, 0.300, 0.400), 0.001)), 1.0)
10331044 """
10341045
1046+ attached_tool = self .attached_tools .get (group )
1047+ if use_attached_tool_frame and attached_tool :
1048+ frame_WCF = self .from_tcf_to_t0cf ([frame_WCF ], group )[0 ]
1049+
10351050 ee_link = self .get_end_effector_link_name (group )
10361051 sphere = Sphere (frame_WCF .point , tolerance_position )
10371052 return PositionConstraint .from_sphere (ee_link , sphere )
10381053
1039- def constraints_from_frame (self , frame_WCF , tolerance_position , tolerances_axes , group = None ):
1054+ def constraints_from_frame (self , frame_WCF , tolerance_position , tolerances_axes , group = None , use_attached_tool_frame = True ):
10401055 r"""Create a position and an orientation constraint from a frame calculated for the group's end-effector link.
10411056
10421057 Parameters
@@ -1052,6 +1067,9 @@ def constraints_from_frame(self, frame_WCF, tolerance_position, tolerances_axes,
10521067 group: :obj:`str`, optional
10531068 The planning group for which we specify the constraint. Defaults to
10541069 the robot's main planning group.
1070+ use_attached_tool_frame : :obj:`bool`, optional
1071+ If ``True`` and there is a tool attached to the planning group, it will use its TCF
1072+ instead of the T0CF to create the constraints. Defaults to ``True``.
10551073
10561074 Returns
10571075 -------
@@ -1084,8 +1102,8 @@ def constraints_from_frame(self, frame_WCF, tolerance_position, tolerances_axes,
10841102 [PositionConstraint('ee_link', BoundingVolume(2, Sphere(Point(0.400, 0.300, 0.400), 0.001)), 1.0),
10851103 OrientationConstraint('ee_link', [0.5, 0.5, 0.5, 0.5], [0.017453292519943295, 0.017453292519943295, 0.017453292519943295], 1.0)]
10861104 """
1087- pc = self .position_constraint_from_frame (frame_WCF , tolerance_position , group )
1088- oc = self .orientation_constraint_from_frame (frame_WCF , tolerances_axes , group )
1105+ pc = self .position_constraint_from_frame (frame_WCF , tolerance_position , group , use_attached_tool_frame )
1106+ oc = self .orientation_constraint_from_frame (frame_WCF , tolerances_axes , group , use_attached_tool_frame )
10891107 return [pc , oc ]
10901108
10911109 def constraints_from_configuration (self , configuration , tolerances_above , tolerances_below , group = None ):
@@ -1164,7 +1182,7 @@ def constraints_from_configuration(self, configuration, tolerances_above, tolera
11641182 # services
11651183 # ==========================================================================
11661184
1167- def inverse_kinematics (self , frame_WCF , start_configuration = None , group = None , return_full_configuration = False , options = None ):
1185+ def inverse_kinematics (self , frame_WCF , start_configuration = None , group = None , return_full_configuration = False , use_attached_tool_frame = True , options = None ):
11681186 """Calculate the robot's inverse kinematic for a given frame.
11691187
11701188 The inverse kinematic solvers are implemented as generators in order to fit both analytic
@@ -1190,6 +1208,9 @@ def inverse_kinematics(self, frame_WCF, start_configuration=None, group=None, re
11901208 return_full_configuration : :obj:`bool`, optional
11911209 If ``True``, returns a full configuration with all joint values
11921210 specified, including passive ones if available. Defaults to ``False``.
1211+ use_attached_tool_frame : :obj:`bool`, optional
1212+ If ``True`` and there is a tool attached to the planning group, it will use its TCF
1213+ instead of the T0CF to calculate IK. Defaults to ``True``.
11931214 options: :obj:`dict`, optional
11941215 Dictionary containing the key-value pairs of additional options.
11951216 The valid options are specific to the backend in use.
@@ -1221,13 +1242,13 @@ def inverse_kinematics(self, frame_WCF, start_configuration=None, group=None, re
12211242 if solution is not None :
12221243 return solution
12231244
1224- solutions = self .iter_inverse_kinematics (frame_WCF , start_configuration , group , return_full_configuration , options )
1245+ solutions = self .iter_inverse_kinematics (frame_WCF , start_configuration , group , return_full_configuration , use_attached_tool_frame , options )
12251246 self ._current_ik ["request_id" ] = request_id
12261247 self ._current_ik ["solutions" ] = solutions
12271248
12281249 return next (solutions )
12291250
1230- def iter_inverse_kinematics (self , frame_WCF , start_configuration = None , group = None , return_full_configuration = False , options = None ):
1251+ def iter_inverse_kinematics (self , frame_WCF , start_configuration = None , group = None , return_full_configuration = False , use_attached_tool_frame = True , options = None ):
12311252 """Iterate over the inverse kinematic solutions of a robot.
12321253
12331254 This method exposes the generator-based inverse kinematic solvers. Analytics solvers will return
@@ -1250,6 +1271,9 @@ def iter_inverse_kinematics(self, frame_WCF, start_configuration=None, group=Non
12501271 return_full_configuration : :obj:`bool`, optional
12511272 If ``True``, returns a full configuration with all joint values
12521273 specified, including passive ones if available. Defaults to ``False``.
1274+ use_attached_tool_frame : :obj:`bool`, optional
1275+ If ``True`` and there is a tool attached to the planning group, it will use its TCF
1276+ instead of the T0CF to calculate IK. Defaults to ``True``.
12531277 options: :obj:`dict`, optional
12541278 Dictionary containing the key-value pairs of additional options.
12551279 The valid options are specific to the backend in use.
@@ -1281,6 +1305,10 @@ def iter_inverse_kinematics(self, frame_WCF, start_configuration=None, group=Non
12811305
12821306 start_configuration , start_configuration_scaled = self ._check_full_configuration_and_scale (start_configuration )
12831307
1308+ attached_tool = self .attached_tools .get (group )
1309+ if use_attached_tool_frame and attached_tool :
1310+ frame_WCF = self .from_tcf_to_t0cf ([frame_WCF ], group )[0 ]
1311+
12841312 frame_WCF_scaled = frame_WCF .copy ()
12851313 frame_WCF_scaled .point /= self .scale_factor # must be in meters
12861314
@@ -1329,7 +1357,7 @@ def inverse_kinematics_deprecated(
13291357 ),
13301358 )
13311359
1332- def forward_kinematics (self , configuration , group = None , options = None ):
1360+ def forward_kinematics (self , configuration , group = None , use_attached_tool_frame = True , options = None ):
13331361 """Calculate the robot's forward kinematic.
13341362
13351363 Parameters
@@ -1341,6 +1369,9 @@ def forward_kinematics(self, configuration, group=None, options=None):
13411369 group: obj:`str`, optional
13421370 The planning group used for the calculation. Defaults to the robot's
13431371 main planning group.
1372+ use_attached_tool_frame : :obj:`bool`, optional
1373+ If ``True`` and there is a tool attached to the planning group, FK will return
1374+ the TCF of the attached tool instead of the T0CF. Defaults to ``True``.
13441375 options: obj:`dict`, optional
13451376 Dictionary containing the following key-value pairs:
13461377
@@ -1409,12 +1440,17 @@ def forward_kinematics(self, configuration, group=None, options=None):
14091440
14101441 # Scale and return
14111442 frame_WCF .point *= self .scale_factor
1443+
1444+ attached_tool = self .attached_tools .get (group )
1445+ if use_attached_tool_frame and attached_tool :
1446+ frame_WCF = self .from_t0cf_to_tcf ([frame_WCF ], group )[0 ]
1447+
14121448 return frame_WCF
14131449
14141450 def forward_kinematics_deprecated (self , configuration , group = None , backend = None , ee_link = None ):
14151451 return self .forward_kinematics (configuration , group , options = dict (solver = backend , link = ee_link ))
14161452
1417- def plan_cartesian_motion (self , frames_WCF , start_configuration = None , group = None , options = None ):
1453+ def plan_cartesian_motion (self , frames_WCF , start_configuration = None , group = None , use_attached_tool_frame = True , options = None ):
14181454 """Calculate a cartesian motion path (linear in tool space).
14191455
14201456 Parameters
@@ -1428,6 +1464,9 @@ def plan_cartesian_motion(self, frames_WCF, start_configuration=None, group=None
14281464 group : :obj:`str`, optional
14291465 The planning group used for calculation. Defaults to the robot's
14301466 main planning group.
1467+ use_attached_tool_frame : :obj:`bool`, optional
1468+ If ``True`` and there is a tool attached to the planning group, it will use its TCF
1469+ instead of the T0CF to calculate cartesian paths. Defaults to ``True``.
14311470 options : :obj:`dict`, optional
14321471 Dictionary containing the following key-value pairs:
14331472
@@ -1484,6 +1523,10 @@ def plan_cartesian_motion(self, frames_WCF, start_configuration=None, group=None
14841523 # that all configurable joints of the whole robot are defined for planning.
14851524 start_configuration , start_configuration_scaled = self ._check_full_configuration_and_scale (start_configuration )
14861525
1526+ attached_tool = self .attached_tools .get (group )
1527+ if use_attached_tool_frame and attached_tool :
1528+ frames_WCF = self .from_tcf_to_t0cf (frames_WCF , group )
1529+
14871530 frames_WCF_scaled = []
14881531 for frame in frames_WCF :
14891532 frames_WCF_scaled .append (Frame (frame .point * 1.0 / self .scale_factor , frame .xaxis , frame .yaxis ))
0 commit comments