Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skeleton for Action Server and Client #579

Merged
merged 29 commits into from
Nov 21, 2018
Merged

Conversation

sloretz
Copy link
Contributor

@sloretz sloretz commented Nov 2, 2018

This is the start of C++ code matching the API in ros2/examples#216

@sloretz sloretz added the in progress Actively being worked on (Kanban column) label Nov 2, 2018
@sloretz sloretz changed the title Skeleton for ActionServer Skeleton for Action Server and Client Nov 16, 2018
@sloretz sloretz requested a review from hidmic November 16, 2018 03:00
@sloretz
Copy link
Contributor Author

sloretz commented Nov 16, 2018

CI

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

Copy link
Contributor

@hidmic hidmic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sloretz thank you for pushing this! I left some comments here and there. Feel free to focus on the server, taking care of the client is on me.

)
target_link_libraries(test_server
${PROJECT_NAME}
${test_msgs_LIBRARIES}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sloretz I've also seen CMake code using the ament_target_dependencies() macro to do just this. Which one's the recommended idiom?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ament_target_dependencies() is the recommended one. I keep forgetting the ament_cmake macros and fallback to the usual CMake functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


// TODO(sloretz) shared pointer to keep rcl_server_ alive while goal handles are alive
rcl_action_server_t * rcl_server_;
rcl_action_goal_handle_t * rcl_handle_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sloretz I agree we should use smart pointers, for both (I'd initially say shared and unique respectively).


/// TODO(sloretz) examples have this on client as `async_cancel_goal(goal_handle)`
std::future<bool>
async_cancel();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sloretz I do like the idea of calling cancel on the goal handle, but we have to support cancellation requests that expand multiple goals (e.g. cancel all goals). So I'd propose to keep this async_cancel() method here, plus async_cancel_all_goals() and async_cancel_goals_before() methods in the client, and maybe expose the low level method that just takes goal ID and timestamp for completeness.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


// TODO(sloretz) `async_result` to make method names consistent?
std::future<typename ACTION::Result>
result_future();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sloretz hmm, I do prefer async_result, but it's not a strong preference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I just need to remember to update this line in the examples https://github.com/ros2/examples/pull/216/files#diff-9df9aa44ab873a3a211a764112190449R37

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


private:
// The templated Server creates goal handles
friend Client<ACTION>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sloretz I don't know if this is a typical pattern in ROS2, but why not using an abstract base class and have the client implement their own?

Copy link
Contributor Author

@sloretz sloretz Nov 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think using friend and a private constructor is a typical pattern. The base class approach would work too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hidmic is 193eb4a what you had in mind?

Copy link
Contributor

@hidmic hidmic Nov 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I was actually thinking of something like (in client_goal_handle.hpp):

class ClientGoalHandle {
  public:
    virtual std::future<bool> async_cancel() = 0;
};

and then (in client.cpp):

class ClientGoalHandleImpl : public ClientGoalHandle {
   public:
      std::future<bool> async_cancel() override {
         ...
      }
};

External code never instantiates a GoalHandle because it's just an interface. We have to watch out for slicing though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think ClientGoalHandleImpl can be in client.cpp because std::future<typename ACTION::Result> async_result() requires knowing the user's type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combined base class with virtual methods and friendship of implementation class with Server in acdfcd9. How does that look?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Argh, right, there's no common base type for action user defined types, silly me.

I think it's fine. Another alternative (for the sake of completeness :) ) would be to define the goal handle subclass as a private nested class of the client/server class. Same code, no friendship.


// TODO(sloretz) shared pointer to keep rcl_client_ alive while goal handles are alive
rcl_action_client_t * rcl_client_;
rcl_action_goal_info_t rcl_info_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sloretz I agree we should use smart pointers.



// TODO(sloretz) goal_handle->result_future()
// TODO(sloretz) goal_handle->cancel()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sloretz I think we can remove these TODOs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


private:
// The templated Server creates goal handles
friend Server<ACTION>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sloretz same as above about using friend.

@sloretz
Copy link
Contributor Author

sloretz commented Nov 16, 2018

CI

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

Copy link
Member

@jacobperron jacobperron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pending green CI, I think this can be merged as a place to iterate from.

@sloretz
Copy link
Contributor Author

sloretz commented Nov 19, 2018

CI

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

@hidmic
Copy link
Contributor

hidmic commented Nov 20, 2018

I agree with Jacob.

@sloretz sloretz merged commit be010cb into master Nov 21, 2018
@sloretz sloretz removed the in progress Actively being worked on (Kanban column) label Nov 21, 2018
@sloretz sloretz deleted the rclcpp_action_prototype branch November 21, 2018 17:17
target_link_libraries(test_server
${PROJECT_NAME}
)
endif()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both of these tests only run with the default RMW impl. It would be good to update this to run the tests for each RMW impl.

cho3 pushed a commit to cho3/rclcpp that referenced this pull request Jun 3, 2019
* Skeleton for ActionServer and ActionClient
nnmm pushed a commit to ApexAI/rclcpp that referenced this pull request Jul 9, 2022
…shutdown` (ros2#579)

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
DensoADAS pushed a commit to DensoADAS/rclcpp that referenced this pull request Aug 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants