4141from tf2_ros import TransformException
4242from tf2_ros .buffer import Buffer
4343from tf2_ros .transform_listener import TransformListener
44+ import tf2_geometry_msgs # noqa: F401 # pylint: disable=unused-import
4445
46+ from builtin_interfaces .msg import Duration
47+ from control_msgs .action import FollowJointTrajectory
48+ from trajectory_msgs .msg import JointTrajectory , JointTrajectoryPoint
4549import std_msgs
4650from controller_manager_msgs .srv import SwitchController
4751from geometry_msgs .msg import (
5256 Twist ,
5357 Wrench ,
5458 Vector3 ,
59+ Vector3Stamped ,
5560)
5661
5762sys .path .append (os .path .dirname (__file__ ))
5863from test_common import ( # noqa: E402
64+ ActionInterface ,
5965 ControllerManagerInterface ,
6066 DashboardInterface ,
6167 ForceModeInterface ,
6268 IoStatusInterface ,
6369 ConfigurationInterface ,
6470 generate_driver_test_description ,
71+ ROBOT_JOINTS ,
6572)
6673
6774TIMEOUT_EXECUTE_TRAJECTORY = 30
@@ -101,6 +108,11 @@ def init_robot(self):
101108 self ._controller_manager_interface = ControllerManagerInterface (self .node )
102109 self ._io_status_controller_interface = IoStatusInterface (self .node )
103110 self ._configuration_controller_interface = ConfigurationInterface (self .node )
111+ self ._passthrough_forward_joint_trajectory = ActionInterface (
112+ self .node ,
113+ "/passthrough_trajectory_controller/follow_joint_trajectory" ,
114+ FollowJointTrajectory ,
115+ )
104116
105117 def setUp (self ):
106118 self ._dashboard_interface .start_robot ()
@@ -127,14 +139,12 @@ def run_force_mode(self, tf_prefix):
127139 self ._force_mode_controller_interface = ForceModeInterface (self .node )
128140
129141 # Create task frame for force mode
130- point = Point (x = 0.8 , y = 0.8 , z = 0.8 )
142+ point = Point (x = 0.0 , y = 0.0 , z = 0.0 )
131143 orientation = Quaternion (x = 0.7071 , y = 0.0 , z = 0.0 , w = 0.7071 )
132144 task_frame_pose = Pose ()
133145 task_frame_pose .position = point
134146 task_frame_pose .orientation = orientation
135- header = std_msgs .msg .Header (seq = 1 , frame_id = tf_prefix + "base" )
136- header .stamp .sec = int (time .time ()) + 1
137- header .stamp .nanosec = 0
147+ header = std_msgs .msg .Header (seq = 1 , frame_id = tf_prefix + "tool0_controller" )
138148 frame_stamp = PoseStamped ()
139149 frame_stamp .header = header
140150 frame_stamp .pose = task_frame_pose
@@ -144,7 +154,7 @@ def run_force_mode(self, tf_prefix):
144154
145155 # Create Wrench message for force mode
146156 wrench = Wrench ()
147- wrench .force = Vector3 (x = 0.0 , y = 0.0 , z = 5 .0 )
157+ wrench .force = Vector3 (x = 0.0 , y = 0.0 , z = 10 .0 )
148158 wrench .torque = Vector3 (x = 0.0 , y = 0.0 , z = 0.0 )
149159
150160 # Specify interpretation of task frame (no transform)
@@ -183,27 +193,46 @@ def run_force_mode(self, tf_prefix):
183193 time .sleep (5.0 )
184194
185195 trans_after = self .lookup_tcp_in_base (tf_prefix , self .node .get_clock ().now ())
196+ diff = Vector3Stamped (
197+ vector = Vector3 (
198+ x = (trans_after .transform .translation .x - trans_before .transform .translation .x ),
199+ y = (trans_after .transform .translation .y - trans_before .transform .translation .y ),
200+ z = (trans_after .transform .translation .z - trans_before .transform .translation .z ),
201+ ),
202+ header = trans_after .header ,
203+ )
204+ diff_in_tool0_controller = self .tf_buffer .transform (
205+ diff ,
206+ tf_prefix + "tool0_controller" ,
207+ timeout = rclpy .time .Duration (seconds = 1.0 ),
208+ )
186209
187210 # task frame and wrench determines the expected motion
188211 # In the example we used
189- # - a task frame rotated pi/2 deg around the base frame's x axis
212+ # - a task frame rotated pi/2 deg around the tcp frame's x axis
190213 # - a wrench with a positive z component for the force
191- # => we should expect a motion in negative y of the base frame
192- self .assertTrue (trans_after .transform .translation .y < trans_before .transform .translation .y )
214+ # => we should expect a motion in negative y of the tcp frame, since we didn't to any
215+ # rotation
216+ self .assertTrue (
217+ diff_in_tool0_controller .vector .y < - 0.03 ,
218+ )
193219 self .assertAlmostEqual (
194- trans_after . transform . translation .x ,
195- trans_before . transform . translation . x ,
220+ diff_in_tool0_controller . vector .x ,
221+ 0.0 ,
196222 delta = 0.001 ,
223+ msg = "X translation should not change" ,
197224 )
198225 self .assertAlmostEqual (
199- trans_after . transform . translation .z ,
200- trans_before . transform . translation . z ,
226+ diff_in_tool0_controller . vector .z ,
227+ 0.0 ,
201228 delta = 0.001 ,
229+ msg = "Z translation should not change" ,
202230 )
203231 self .assertTrue (
204232 are_quaternions_same (
205233 trans_after .transform .rotation , trans_before .transform .rotation , 0.001
206- )
234+ ),
235+ msg = "Rotation should not change" ,
207236 )
208237
209238 res = self ._force_mode_controller_interface .stop_force_mode ()
@@ -218,6 +247,39 @@ def run_force_mode(self, tf_prefix):
218247 )
219248
220249 def test_force_mode_controller (self , tf_prefix ):
250+ self .assertTrue (
251+ self ._controller_manager_interface .switch_controller (
252+ strictness = SwitchController .Request .BEST_EFFORT ,
253+ activate_controllers = [
254+ "passthrough_trajectory_controller" ,
255+ ],
256+ deactivate_controllers = [
257+ "scaled_joint_trajectory_controller" ,
258+ "joint_trajectory_controller" ,
259+ "force_mode_controller" ,
260+ ],
261+ ).ok
262+ )
263+ waypts = [[- 1.6 , - 1.55 , - 1.7 , - 1.0 , 2.05 , 0.5 ]]
264+ time_vec = [Duration (sec = 5 , nanosec = 0 )]
265+ test_trajectory = zip (time_vec , waypts )
266+ trajectory = JointTrajectory (
267+ points = [
268+ JointTrajectoryPoint (positions = pos , time_from_start = times )
269+ for (times , pos ) in test_trajectory
270+ ],
271+ joint_names = [tf_prefix + ROBOT_JOINTS [i ] for i in range (len (ROBOT_JOINTS ))],
272+ )
273+ goal_handle = self ._passthrough_forward_joint_trajectory .send_goal (
274+ trajectory = trajectory ,
275+ )
276+ self .assertTrue (goal_handle .accepted )
277+ if goal_handle .accepted :
278+ result = self ._passthrough_forward_joint_trajectory .get_result (
279+ goal_handle , TIMEOUT_EXECUTE_TRAJECTORY
280+ )
281+ self .assertEqual (result .error_code , FollowJointTrajectory .Result .SUCCESSFUL )
282+
221283 self .assertTrue (
222284 self ._controller_manager_interface .switch_controller (
223285 strictness = SwitchController .Request .BEST_EFFORT ,
@@ -227,6 +289,7 @@ def test_force_mode_controller(self, tf_prefix):
227289 deactivate_controllers = [
228290 "scaled_joint_trajectory_controller" ,
229291 "joint_trajectory_controller" ,
292+ "passthrough_trajectory_controller" ,
230293 ],
231294 ).ok
232295 )
0 commit comments