77import numpy as np
88import rclpy
99from bitbots_utils .transforms import quat2fused
10+ from bitbots_utils .utils import async_wait_for
1011from rclpy .action import ActionServer , GoalResponse
1112from rclpy .action .server import ServerGoalHandle
12- from rclpy .callback_groups import ReentrantCallbackGroup
13- from rclpy .duration import Duration
14- from rclpy .executors import ExternalShutdownException , MultiThreadedExecutor
13+ from rclpy .executors import ExternalShutdownException
14+ from rclpy .experimental .events_executor import EventsExecutor
1515from rclpy .node import Node
1616from sensor_msgs .msg import Imu , JointState
1717from simpleeval import simple_eval
@@ -65,11 +65,9 @@ def __init__(self):
6565 )
6666 traceback .print_exc ()
6767
68- callback_group = ReentrantCallbackGroup ()
69-
7068 # Subscribers
71- self .create_subscription (JointState , "joint_states" , self .update_current_pose , 1 , callback_group = callback_group )
72- self .create_subscription (Imu , "imu/data" , self .imu_callback , 1 , callback_group = callback_group )
69+ self .create_subscription (JointState , "joint_states" , self .update_current_pose , 1 )
70+ self .create_subscription (Imu , "imu/data" , self .imu_callback , 1 )
7371
7472 # Service clients
7573 self .hcm_animation_mode = self .create_client (SetBool , "play_animation_mode" )
@@ -79,7 +77,7 @@ def __init__(self):
7977
8078 # Action server for playing animations
8179 self ._action_server = ActionServer (
82- self , PlayAnimation , "animation" , self .execute_cb , callback_group = callback_group , goal_callback = self .goal_cb
80+ self , PlayAnimation , "animation" , self .execute_cb , goal_callback = self .goal_cb
8381 )
8482
8583 # Service to temporarily add an animation to the cache
@@ -125,7 +123,7 @@ def goal_cb(self, request: PlayAnimation.Goal) -> GoalResponse:
125123 # Everything is fine we are good to go
126124 return GoalResponse .ACCEPT
127125
128- def execute_cb (self , goal : ServerGoalHandle ) -> PlayAnimation .Result :
126+ async def execute_cb (self , goal : ServerGoalHandle ) -> PlayAnimation .Result :
129127 """This is called, when the action should be executed."""
130128
131129 # Convert goal id uuid to hashable tuple (custom UUID type)
@@ -165,16 +163,16 @@ def finish(successful: bool) -> PlayAnimation.Result:
165163
166164 # Send request to make the HCM to go into animation play mode
167165 num_tries = 0
168- while rclpy .ok () and (not self .hcm_animation_mode .call (SetBool .Request (data = True )).success ): # type: ignore[attr-defined]
166+ while rclpy .ok () and (not ( await self .hcm_animation_mode .call_async (SetBool .Request (data = True ) )).success ): # type: ignore[attr-defined]
169167 if num_tries >= 10 :
170168 self .get_logger ().error ("Failed to request HCM to go into animation play mode" )
171169 return finish (successful = False )
172170 num_tries += 1
173- self . get_clock (). sleep_for ( Duration ( seconds = 0.1 ) )
171+ await async_wait_for ( self , 0.1 )
174172
175173 # Make sure we have our current joint states
176174 while rclpy .ok () and self .current_joint_states is None :
177- self . get_clock (). sleep_for ( Duration ( seconds = 0.1 ) )
175+ await async_wait_for ( self , 0.1 )
178176
179177 # Create splines
180178 animator = SplineAnimator (
@@ -263,7 +261,9 @@ def finish(successful: bool) -> PlayAnimation.Result:
263261 if pose is None or (request .bounds and once and t > animator .get_keyframe_times ()[request .end - 1 ]):
264262 # Animation is finished, tell it to the hcm (except if it is from the hcm)
265263 if not request .hcm :
266- hcm_result : SetBool .Response = self .hcm_animation_mode .call (SetBool .Request (data = False ))
264+ hcm_result : SetBool .Response = await self .hcm_animation_mode .call_async (
265+ SetBool .Request (data = False )
266+ )
267267 if not hcm_result .success :
268268 self .get_logger ().error (f"Failed to finish animation on HCM. Reason: { hcm_result .message } " )
269269
@@ -283,7 +283,10 @@ def finish(successful: bool) -> PlayAnimation.Result:
283283
284284 once = True
285285
286- self .get_clock ().sleep_until (last_time + Duration (seconds = 0.02 ))
286+ execution_duration = (self .get_clock ().now () - last_time ).nanoseconds / 1e9
287+
288+ await async_wait_for (self , execution_duration + 0.02 ) # Wait for the next iteration
289+
287290 except (ExternalShutdownException , KeyboardInterrupt ):
288291 sys .exit (0 )
289292 return finish (successful = False )
@@ -339,7 +342,7 @@ def add_animation(self, request: AddAnimation.Request, response: AddAnimation.Re
339342def main (args = None ):
340343 rclpy .init (args = args )
341344 node = AnimationNode ()
342- ex = MultiThreadedExecutor ( num_threads = 10 )
345+ ex = EventsExecutor ( )
343346 ex .add_node (node )
344347 try :
345348 ex .spin ()
0 commit comments