@@ -104,6 +104,18 @@ def setUp(self):
104104 self .tf_buffer = Buffer ()
105105 self .tf_listener = TransformListener (self .tf_buffer , self .node )
106106
107+ def lookup_tcp_in_base (self , tf_prefix , timepoint ):
108+ trans = None
109+ while not trans :
110+ rclpy .spin_once (self .node )
111+ try :
112+ trans = self .tf_buffer .lookup_transform (
113+ tf_prefix + "base" , tf_prefix + "tool0" , timepoint
114+ )
115+ except TransformException :
116+ pass
117+ return trans
118+
107119 def test_force_mode_controller (self , tf_prefix ):
108120 self .assertTrue (
109121 self ._controller_manager_interface .switch_controller (
@@ -153,15 +165,7 @@ def test_force_mode_controller(self, tf_prefix):
153165 damping_factor = 0.1
154166 gain_scale = 0.8
155167
156- trans_before = None
157- while not trans_before :
158- rclpy .spin_once (self .node )
159- try :
160- trans_before = self .tf_buffer .lookup_transform (
161- tf_prefix + "base" , tf_prefix + "tool0" , rclpy .time .Time ()
162- )
163- except TransformException :
164- pass
168+ trans_before = self .lookup_tcp_in_base (tf_prefix , rclpy .time .Time ())
165169
166170 # Send request to controller
167171 res = self ._force_mode_controller_interface .start_force_mode (
@@ -183,16 +187,7 @@ def test_force_mode_controller(self, tf_prefix):
183187
184188 time .sleep (5.0 )
185189
186- trans_after = None
187- timepoint = self .node .get_clock ().now ()
188- while not trans_after :
189- rclpy .spin_once (self .node )
190- try :
191- trans_after = self .tf_buffer .lookup_transform (
192- tf_prefix + "base" , tf_prefix + "tool0" , timepoint
193- )
194- except TransformException :
195- pass
190+ trans_after = self .lookup_tcp_in_base (tf_prefix , self .node .get_clock ().now ())
196191
197192 # task frame and wrench determines the expected motion
198193 # In the example we used
@@ -326,3 +321,127 @@ def test_illegal_task_frame(self, tf_prefix):
326321 task_frame = frame_stamp ,
327322 )
328323 self .assertFalse (res .success )
324+
325+ def test_start_force_mode_on_inactive_controller_fails (self , tf_prefix ):
326+ self .assertTrue (
327+ self ._controller_manager_interface .switch_controller (
328+ strictness = SwitchController .Request .BEST_EFFORT ,
329+ activate_controllers = [],
330+ deactivate_controllers = [
331+ "force_mode_controller" ,
332+ "scaled_joint_trajectory_controller" ,
333+ "joint_trajectory_controller" ,
334+ ],
335+ ).ok
336+ )
337+ self ._force_mode_controller_interface = ForceModeInterface (self .node )
338+
339+ # Create task frame for force mode
340+ point = Point (x = 0.0 , y = 0.0 , z = 0.0 )
341+ orientation = Quaternion (x = 0.0 , y = 0.0 , z = 0.0 , w = 1.0 )
342+ task_frame_pose = Pose ()
343+ task_frame_pose .position = point
344+ task_frame_pose .orientation = orientation
345+ header = std_msgs .msg .Header (seq = 1 , frame_id = tf_prefix + "base" )
346+ header .stamp .sec = int (time .time ()) + 1
347+ header .stamp .nanosec = 0
348+ frame_stamp = PoseStamped ()
349+ frame_stamp .header = header
350+ frame_stamp .pose = task_frame_pose
351+
352+ res = self ._force_mode_controller_interface .start_force_mode (
353+ task_frame = frame_stamp ,
354+ )
355+ self .assertFalse (res .success )
356+
357+ def test_deactivating_controller_stops_force_mode (self , tf_prefix ):
358+ self .assertTrue (
359+ self ._controller_manager_interface .switch_controller (
360+ strictness = SwitchController .Request .BEST_EFFORT ,
361+ activate_controllers = [
362+ "force_mode_controller" ,
363+ ],
364+ deactivate_controllers = [
365+ "scaled_joint_trajectory_controller" ,
366+ "joint_trajectory_controller" ,
367+ ],
368+ ).ok
369+ )
370+ self ._force_mode_controller_interface = ForceModeInterface (self .node )
371+
372+ # Create task frame for force mode
373+ point = Point (x = 0.0 , y = 0.0 , z = 0.0 )
374+ orientation = Quaternion (x = 0.0 , y = 0.0 , z = 0.0 , w = 1.0 )
375+ task_frame_pose = Pose ()
376+ task_frame_pose .position = point
377+ task_frame_pose .orientation = orientation
378+ header = std_msgs .msg .Header (seq = 1 , frame_id = tf_prefix + "base" )
379+ header .stamp .sec = int (time .time ()) + 1
380+ header .stamp .nanosec = 0
381+ frame_stamp = PoseStamped ()
382+ frame_stamp .header = header
383+ frame_stamp .pose = task_frame_pose
384+
385+ # Create compliance vector (which axes should be force controlled)
386+ compliance = [False , False , True , False , False , False ]
387+
388+ # Create Wrench message for force mode
389+ wrench = Wrench ()
390+ wrench .force = Vector3 (x = 0.0 , y = 0.0 , z = 5.0 )
391+ wrench .torque = Vector3 (x = 0.0 , y = 0.0 , z = 0.0 )
392+
393+ # Specify interpretation of task frame (no transform)
394+ type_spec = 2
395+
396+ # Specify max speeds and deviations of force mode
397+ speed_limits = Twist ()
398+ speed_limits .linear = Vector3 (x = 0.0 , y = 0.0 , z = 1.0 )
399+ speed_limits .angular = Vector3 (x = 0.0 , y = 0.0 , z = 1.0 )
400+ deviation_limits = [1.0 , 1.0 , 1.0 , 1.0 , 1.0 , 1.0 ]
401+
402+ # specify damping and gain scaling
403+ damping_factor = 0.1
404+ gain_scale = 0.8
405+
406+ res = self ._force_mode_controller_interface .start_force_mode (
407+ task_frame = frame_stamp ,
408+ selection_vector_x = compliance [0 ],
409+ selection_vector_y = compliance [1 ],
410+ selection_vector_z = compliance [2 ],
411+ selection_vector_rx = compliance [3 ],
412+ selection_vector_ry = compliance [4 ],
413+ selection_vector_rz = compliance [5 ],
414+ wrench = wrench ,
415+ type = type_spec ,
416+ speed_limits = speed_limits ,
417+ deviation_limits = deviation_limits ,
418+ damping_factor = damping_factor ,
419+ gain_scaling = gain_scale ,
420+ )
421+ self .assertTrue (res .success )
422+
423+ time .sleep (0.5 )
424+
425+ self .assertTrue (
426+ self ._controller_manager_interface .switch_controller (
427+ strictness = SwitchController .Request .BEST_EFFORT ,
428+ activate_controllers = [],
429+ deactivate_controllers = [
430+ "force_mode_controller" ,
431+ "scaled_joint_trajectory_controller" ,
432+ "joint_trajectory_controller" ,
433+ ],
434+ ).ok
435+ )
436+ self ._force_mode_controller_interface = ForceModeInterface (self .node )
437+
438+ time .sleep (0.5 )
439+ trans_before_wait = self .lookup_tcp_in_base (tf_prefix , self .node .get_clock ().now ())
440+
441+ # Make sure the robot didn't move anymore
442+ time .sleep (0.5 )
443+ trans_after_wait = self .lookup_tcp_in_base (tf_prefix , self .node .get_clock ().now ())
444+
445+ self .assertAlmostEqual (
446+ trans_before_wait .transform .translation .z , trans_after_wait .transform .translation .z
447+ )
0 commit comments