Я работаю над очень простой клиент-серверной архитектурой с действиями, но у меня возникают проблемы с функцией вращения. По сути, у меня есть два сервера:
сервер 1
from example_interfaces.action import Fibonacci
import rclpy
from rclpy.action import ActionServer, CancelResponse, GoalResponse
from rclpy.callback_groups import ReentrantCallbackGroup
from rclpy.executors import MultiThreadedExecutor
from rclpy.node import Node
class MinimalActionServer(Node):
def __init__(self):
super().__init__('minimal_action_server_1')
self._action_server = ActionServer(
self,
Fibonacci,
'fibonacci_1',
execute_callback=self.execute_callback,
callback_group=ReentrantCallbackGroup(),
goal_callback=self.goal_callback,
cancel_callback=self.cancel_callback)
self.get_logger().info('SERVER 1 : ONLINE')
def destroy(self):
self._action_server.destroy()
super().destroy_node()
def goal_callback(self, goal_request):
"""Accepts or rejects a client request to begin an action."""
# This server allows multiple goals in parallel
self.get_logger().info('SERVER 1 : Received goal request')
return GoalResponse.ACCEPT
def cancel_callback(self, goal_handle):
"""Accepts or rejects a client request to cancel an action."""
self.get_logger().info('SERVER 1 : Received cancel request')
return CancelResponse.ACCEPT
async def execute_callback(self, goal_handle):
"""Executes a goal."""
self.get_logger().info('SERVER 1 : Executing goal...')
# Append the seeds for the Fibonacci sequence
feedback_msg = Fibonacci.Feedback()
feedback_msg.sequence = [0, 1]
# Start executing the action
for i in range(1, goal_handle.request.order):
if goal_handle.is_cancel_requested:
goal_handle.canceled()
self.get_logger().info('SERVER 1 : Goal canceled')
return Fibonacci.Result()
# Update Fibonacci sequence
feedback_msg.sequence.append(feedback_msg.sequence[i] + feedback_msg.sequence[i-1])
self.get_logger().info('SERVER 1 : Publishing feedback: {0}'.format(feedback_msg.sequence))
# Publish the feedback
goal_handle.publish_feedback(feedback_msg)
# Sleep for demonstration purposes
time.sleep(1)
goal_handle.succeed()
# Populate result message
result = Fibonacci.Result()
result.sequence = feedback_msg.sequence
self.get_logger().info('SERVER 1 : Returning result: {0}'.format(result.sequence))
return result
def main(args=None):
rclpy.init(args=args)
minimal_action_server = MinimalActionServer()
# Use a MultiThreadedExecutor to enable processing goals concurrently
executor = MultiThreadedExecutor()
rclpy.spin(minimal_action_server, executor=executor)
minimal_action_server.destroy()
rclpy.shutdown()
if __name__ == '__main__':
main()
сервер 2
import time
from example_interfaces.action import Fibonacci
import rclpy
from rclpy.action import ActionServer, CancelResponse, GoalResponse
from rclpy.callback_groups import ReentrantCallbackGroup
from rclpy.executors import MultiThreadedExecutor
from rclpy.node import Node
class MinimalActionServer(Node):
def __init__(self):
super().__init__('minimal_action_server_2')
self._action_server = ActionServer(
self,
Fibonacci,
'fibonacci_2',
execute_callback=self.execute_callback,
callback_group=ReentrantCallbackGroup(),
goal_callback=self.goal_callback,
cancel_callback=self.cancel_callback)
self.get_logger().info('SERVER 2 : ONLINE')
def destroy(self):
self._action_server.destroy()
super().destroy_node()
def goal_callback(self, goal_request):
"""Accepts or rejects a client request to begin an action."""
# This server allows multiple goals in parallel
self.get_logger().info('SERVER 2 : Received goal request')
return GoalResponse.ACCEPT
def cancel_callback(self, goal_handle):
"""Accepts or rejects a client request to cancel an action."""
self.get_logger().info('SERVER 2 : Received cancel request')
return CancelResponse.ACCEPT
async def execute_callback(self, goal_handle):
"""Executes a goal."""
self.get_logger().info('SERVER 2 : Executing goal...')
# Append the seeds for the Fibonacci sequence
feedback_msg = Fibonacci.Feedback()
feedback_msg.sequence = [0, 1]
# Start executing the action
for i in range(1, goal_handle.request.order):
if goal_handle.is_cancel_requested:
goal_handle.canceled()
self.get_logger().info('SERVER 2 : Goal canceled')
return Fibonacci.Result()
# Update Fibonacci sequence
feedback_msg.sequence.append(feedback_msg.sequence[i] + feedback_msg.sequence[i-1])
self.get_logger().info('SERVER 2 : Publishing feedback: {0}'.format(feedback_msg.sequence))
# Publish the feedback
goal_handle.publish_feedback(feedback_msg)
# Sleep for demonstration purposes
time.sleep(1)
goal_handle.succeed()
# Populate result message
result = Fibonacci.Result()
result.sequence = feedback_msg.sequence
self.get_logger().info('SERVER 2 : Returning result: {0}'.format(result.sequence))
return result
def main(args=None):
rclpy.init(args=args)
minimal_action_server = MinimalActionServer()
# Use a MultiThreadedExecutor to enable processing goals concurrently
executor = MultiThreadedExecutor()
rclpy.spin(minimal_action_server, executor=executor)
minimal_action_server.destroy()
rclpy.shutdown()
if __name__ == '__main__':
main()
Они оба очень похожи, и все, что они делают, это получают действия от клиентов и возвращают обратную связь.
И у меня также есть клиент: клиент
from action_msgs.msg import GoalStatus
from example_interfaces.action import Fibonacci
import rclpy
from rclpy.action import ActionClient
from rclpy.node import Node
class MinimalActionClient():
def __init__(self, node, server_name):
self._server_name = server_name
self._action_client = ActionClient(node, Fibonacci, server_name)
self.__result = None
self.__done = False
def goal_done(self):
return self.__done
def goal_response_callback(self, future):
goal_handle = future.result()
if not goal_handle.accepted:
print('Goal rejected :( '+self._server_name)
return
print('Goal accepted :) '+self._server_name)
self._get_result_future = goal_handle.get_result_async()
self._get_result_future.add_done_callback(self.get_result_callback)
def feedback_callback(self, feedback):
print('Received feedback: {0}'.format(feedback.feedback.sequence))
def get_result_callback(self, future):
result = future.result().result
print("RESULT", result)
status = future.result().status
if status == GoalStatus.STATUS_SUCCEEDED:
print(self._server_name+': Goal succeeded! Result: {0}'.format(result.sequence))
self.__done = True
else:
print(self._server_name+': Goal failed with status: {0}'.format(status))
# Shutdown after receiving a result
# rclpy.shutdown()
def send_goal(self):
# self.get_logger().info('Waiting for action server '+self._server_name)
print('Waiting for action server '+self._server_name)
self._action_client.wait_for_server()
goal_msg = Fibonacci.Goal()
goal_msg.order = 10
# self.get_logger().info('Sending goal request to '+self._server_name)
print('Sending goal request to '+self._server_name)
self._send_goal_future = self._action_client.send_goal_async(
goal_msg,
feedback_callback=self.feedback_callback)
self._send_goal_future.add_done_callback(self.goal_response_callback)
def main(args=None):
rclpy.init(args=args)
client_node = rclpy.create_node('minimal_action_client')
action_client_1 = MinimalActionClient(node=client_node, server_name='fibonacci_1')
action_client_2 = MinimalActionClient(node=client_node, server_name='fibonacci_2')
action_client_1.send_goal()
action_client_2.send_goal()
rclpy.spin(client_node)
# client_node.destroy()
rclpy.shutdown()
print("print executed")
if __name__ == '__main__':
main()
Что я хотел бы сделать, так это посмотреть распечатку после выключения, но я, кажется, никогда не смогу сделать это. Даже если я положу печать до выключения, печать никогда не будет выполнена. Что привело меня к вопросу: можно ли выполнить любой вызов после rclpy.spin ()?
Спасибо за помощь!