Skeleton for Action Server and Client (#579)

* Skeleton for ActionServer and ActionClient
This commit is contained in:
Shane Loretz 2018-11-21 09:16:51 -08:00 committed by GitHub
parent f212d73413
commit be010cb2d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 919 additions and 0 deletions

View file

@ -0,0 +1,99 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP_ACTION__CLIENT_HPP_
#define RCLCPP_ACTION__CLIENT_HPP_
#include <rosidl_generator_c/action_type_support_struct.h>
#include <rclcpp/node_interfaces/node_base_interface.hpp>
#include <rclcpp/time.hpp>
#include <rosidl_typesupport_cpp/action_type_support.hpp>
#include <functional>
#include <memory>
#include <string>
#include "rclcpp_action/client_goal_handle.hpp"
#include "rclcpp_action/visibility_control.hpp"
namespace rclcpp_action
{
// Forward declaration
class ClientBaseImpl;
/// Base Action Client implementation
/// It is responsible for interfacing with the C action client API.
class ClientBase
{
public:
// TODO(sloretz) NodeLoggingInterface when it can be gotten off a node
RCLCPP_ACTION_PUBLIC
ClientBase(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
const std::string & name,
const rosidl_action_type_support_t * type_support);
RCLCPP_ACTION_PUBLIC
virtual ~ClientBase();
// TODO(sloretz) add a link between this class and callbacks in the templated
private:
std::unique_ptr<ClientBaseImpl> pimpl_;
};
/// Templated Action Client class
/// It is responsible for getting the C action type support struct from the C++ type, and
/// calling user callbacks with goal handles of the appropriate type.
template<typename ACTION>
class Client : public ClientBase
{
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(Client)
using FeedbackCallback = std::function<void (
std::shared_ptr<ClientGoalHandle<ACTION>>, const typename ACTION::Feedback)>;
Client(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
const std::string & name
)
: ClientBase(
node_base,
name,
rosidl_typesupport_cpp::get_action_type_support_handle<ACTION>())
{
// TODO(sloretz) what's the link that causes a feedback topic to be called ?
}
ClientGoalHandle<ACTION>
async_send_goal(typename ACTION::Goal * goal, FeedbackCallback callback = nullptr);
RCLCPP_ACTION_PUBLIC
std::future<typename ACTION::CancelGoalService::Response>
async_cancel_all_goals();
RCLCPP_ACTION_PUBLIC
std::future<typename ACTION::CancelGoalService::Response>
async_cancel_goals_before(rclcpp::Time);
virtual ~Client()
{
}
};
} // namespace rclcpp_action
#endif // RCLCPP_ACTION__CLIENT_HPP_

View file

@ -0,0 +1,57 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP_ACTION__CLIENT_GOAL_HANDLE_HPP_
#define RCLCPP_ACTION__CLIENT_GOAL_HANDLE_HPP_
#include <rcl_action/action_client.h>
#include <functional>
#include <memory>
#include "rclcpp_action/visibility_control.hpp"
namespace rclcpp_action
{
// Forward declarations
template<typename ACTION>
class Client;
template<typename ACTION>
class ClientGoalHandle
{
public:
virtual ~ClientGoalHandle();
/// TODO(sloretz) examples have this on client as `async_cancel_goal(goal_handle)`
std::future<bool>
async_cancel();
std::future<typename ACTION::Result>
async_result();
private:
// The templated Server creates goal handles
friend Client<ACTION>;
ClientGoalHandle(rcl_action_client_t * rcl_client, const rcl_action_goal_info_t rcl_info);
// 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_;
};
} // namespace rclcpp_action
#include <rclcpp_action/client_goal_handle_impl.hpp> // NOLINT(build/include_order)
#endif // RCLCPP_ACTION__CLIENT_GOAL_HANDLE_HPP_

View file

@ -0,0 +1,51 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP_ACTION__CLIENT_GOAL_HANDLE_IMPL_HPP_
#define RCLCPP_ACTION__CLIENT_GOAL_HANDLE_IMPL_HPP_
#include <rcl_action/types.h>
namespace rclcpp_action
{
template<typename ACTION>
ClientGoalHandle<ACTION>::ClientGoalHandle(
rcl_action_client_t * rcl_client,
const rcl_action_goal_info_t rcl_info
)
: rcl_client_(rcl_client), rcl_info_(rcl_info)
{
}
template<typename ACTION>
ClientGoalHandle<ACTION>::~ClientGoalHandle()
{
}
template<typename ACTION>
std::future<bool>
ClientGoalHandle<ACTION>::async_cancel()
{
throw std::runtime_error("Failed to cancel goal");
}
template<typename ACTION>
std::future<typename ACTION::Result>
ClientGoalHandle<ACTION>::async_result()
{
throw std::runtime_error("Failed to get result future");
}
} // namespace rclcpp_action
#endif // RCLCPP_ACTION__CLIENT_GOAL_HANDLE_IMPL_HPP_

View file

@ -0,0 +1,40 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP_ACTION__CREATE_CLIENT_HPP_
#define RCLCPP_ACTION__CREATE_CLIENT_HPP_
#include <rclcpp/node.hpp>
#include <memory>
#include <string>
#include "rclcpp_action/client.hpp"
#include "rclcpp_action/visibility_control.hpp"
namespace rclcpp_action
{
template<typename ACTION>
typename Client<ACTION>::SharedPtr
create_client(
rclcpp::Node * node,
const std::string & name)
{
return Client<ACTION>::make_shared(
node->get_node_base_interface(),
name);
}
} // namespace rclcpp_action
#endif // RCLCPP_ACTION__CREATE_CLIENT_HPP_
// TODO(sloretz) rclcpp_action::create_client<>(node, action_name);

View file

@ -0,0 +1,43 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP_ACTION__CREATE_SERVER_HPP_
#define RCLCPP_ACTION__CREATE_SERVER_HPP_
#include <rclcpp/node.hpp>
#include <memory>
#include <string>
#include "rclcpp_action/server.hpp"
#include "rclcpp_action/visibility_control.hpp"
namespace rclcpp_action
{
template<typename ACTION>
typename Server<ACTION>::SharedPtr
create_server(
rclcpp::Node * node,
const std::string & name,
typename Server<ACTION>::GoalCallback handle_goal,
typename Server<ACTION>::CancelCallback handle_cancel)
{
return Server<ACTION>::make_shared(
node->get_node_base_interface(),
name,
handle_goal,
handle_cancel);
}
} // namespace rclcpp_action
#endif // RCLCPP_ACTION__CREATE_SERVER_HPP_

View file

@ -0,0 +1,39 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/** \mainpage rclcpp_action: ROS Action Client Library for C++
*
* `rclcpp_action` provides the canonical C++ API for interacting with ROS Actions.
* It consists of these main components:
*
* - TODO(jacobperron): Finish docs
* - Action Client
* - Action Server
*/
#ifndef RCLCPP_ACTION__RCLCPP_ACTION_HPP_
#define RCLCPP_ACTION__RCLCPP_ACTION_HPP_
#include <csignal>
#include <memory>
#include "rclcpp_action/client.hpp"
#include "rclcpp_action/client_goal_handle.hpp"
#include "rclcpp_action/create_client.hpp"
#include "rclcpp_action/create_server.hpp"
#include "rclcpp_action/server.hpp"
#include "rclcpp_action/server_goal_handle.hpp"
#include "rclcpp_action/visibility_control.hpp"
#endif // RCLCPP_ACTION__RCLCPP_ACTION_HPP_

View file

@ -0,0 +1,95 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP_ACTION__SERVER_HPP_
#define RCLCPP_ACTION__SERVER_HPP_
#include <rosidl_generator_c/action_type_support_struct.h>
#include <rosidl_typesupport_cpp/action_type_support.hpp>
#include <rclcpp/node_interfaces/node_base_interface.hpp>
#include <functional>
#include <memory>
#include <string>
#include "rclcpp_action/visibility_control.hpp"
#include "rclcpp_action/server_goal_handle.hpp"
namespace rclcpp_action
{
// Forward declaration
class ServerBaseImpl;
/// Base Action Server implementation
/// It is responsible for interfacing with the C action server API.
class ServerBase
{
public:
// TODO(sloretz) NodeLoggingInterface when it can be gotten off a node
// TODO(sloretz) accept clock instance
RCLCPP_ACTION_PUBLIC
ServerBase(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
const std::string & name,
const rosidl_action_type_support_t * type_support);
RCLCPP_ACTION_PUBLIC
virtual ~ServerBase();
// TODO(sloretz) add a link between this class and callbacks in the server class
private:
std::unique_ptr<ServerBaseImpl> pimpl_;
};
/// Templated Action Server class
/// It is responsible for getting the C action type support struct from the C++ type, and
/// calling user callbacks with goal handles of the appropriate type.
template<typename ACTION>
class Server : public ServerBase
{
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(Server)
using GoalCallback = std::function<void (rcl_action_goal_info_t &, typename ACTION::Goal *)>;
using CancelCallback = std::function<void (std::shared_ptr<ServerGoalHandle<ACTION>>)>;
// TODO(sloretz) accept clock instance
Server(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
const std::string & name,
GoalCallback handle_goal,
CancelCallback handle_cancel
)
: ServerBase(
node_base,
name,
rosidl_typesupport_cpp::get_action_type_support_handle<ACTION>()),
handle_goal_(handle_goal),
handle_cancel_(handle_cancel)
{
// TODO(sloretz) what's the link that causes `handle_goal_` and `handle_cancel_` to be called?
}
virtual ~Server()
{
}
private:
GoalCallback handle_goal_;
CancelCallback handle_cancel_;
};
} // namespace rclcpp_action
#endif // RCLCPP_ACTION__SERVER_HPP_

View file

@ -0,0 +1,55 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP_ACTION__SERVER_GOAL_HANDLE_HPP_
#define RCLCPP_ACTION__SERVER_GOAL_HANDLE_HPP_
#include <rcl_action/goal_handle.h>
#include <functional>
#include <memory>
#include "rclcpp_action/visibility_control.hpp"
namespace rclcpp_action
{
template<typename ACTION>
class ServerGoalHandle
{
public:
virtual ~ServerGoalHandle();
/// Indicate if client has requested this goal be cancelled.
/// \return true if a cancelation request has been accepted for this goal.
virtual bool
is_cancel_request() const = 0;
/// Send an update about the progress of a goal.
virtual void
publish_feedback(const typename ACTION::Feedback * feedback_msg) = 0;
// TODO(sloretz) `set_cancelled`, `set_succeeded`, `set_aborted`
// TODO(sloretz) examples has this attribute as 'goal'
/// The original request message describing the goal.
const typename ACTION::Goal goal_;
protected:
explicit ServerGoalHandle(const typename ACTION::Goal goal)
: goal_(goal) {}
};
} // namespace rclcpp_action
#include <rclcpp_action/server_goal_handle_impl.hpp> // NOLINT(build/include_order)
#endif // RCLCPP_ACTION__SERVER_GOAL_HANDLE_HPP_

View file

@ -0,0 +1,76 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP_ACTION__SERVER_GOAL_HANDLE_IMPL_HPP_
#define RCLCPP_ACTION__SERVER_GOAL_HANDLE_IMPL_HPP_
#include <rcl_action/goal_handle.h>
#include <rcl_action/types.h>
#include <memory>
namespace rclcpp_action
{
template<typename ACTION>
class Server;
template<typename ACTION>
class ServerGoalHandleImpl : public ServerGoalHandle<ACTION>
{
public:
virtual ~ServerGoalHandleImpl()
{
}
bool
is_cancel_request() const override
{
rcl_action_goal_state_t state = GOAL_STATE_UNKNOWN;
if (RCL_RET_OK != rcl_action_goal_handle_get_status(rcl_handle_.get(), &state)) {
// TODO(sloretz) more specific exception
throw std::runtime_error("Failed to get goal handle state");
}
return GOAL_STATE_CANCELING == state;
}
void
publish_feedback(const typename ACTION::Feedback * feedback_msg) override
{
(void)feedback_msg;
// TODO(sloretz) what is ros_message and how does IntraProcessmessage come into play?
// if (RCL_RET_OK != rcl_action_publish_feedback(rcl_server_, ros_message) {
// // TODO(sloretz) more specific exception
// throw std::runtime_error("Failed to publish feedback");
// }
throw std::runtime_error("Failed to publish feedback");
}
protected:
ServerGoalHandleImpl(
rcl_action_server_t * rcl_server,
const typename ACTION::Goal goal,
rcl_action_goal_handle_t * rcl_handle
)
: rcl_server_(rcl_server), rcl_handle_(rcl_handle), ServerGoalHandle<ACTION>(goal)
{
}
private:
friend Server<ACTION>;
std::shared_ptr<rcl_action_server_t> rcl_server_;
std::shared_ptr<rcl_action_goal_handle_t> rcl_handle_;
};
} // namespace rclcpp_action
#endif // RCLCPP_ACTION__SERVER_GOAL_HANDLE_IMPL_HPP_

View file

@ -0,0 +1,56 @@
// Copyright 2018 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/* This header must be included by all rclcpp headers which declare symbols
* which are defined in the rclcpp library. When not building the rclcpp
* library, i.e. when using the headers in other package's code, the contents
* of this header change the visibility of certain symbols which the rclcpp
* library cannot have, but the consuming code must have inorder to link.
*/
#ifndef RCLCPP_ACTION__VISIBILITY_CONTROL_HPP_
#define RCLCPP_ACTION__VISIBILITY_CONTROL_HPP_
// This logic was borrowed (then namespaced) from the examples on the gcc wiki:
// https://gcc.gnu.org/wiki/Visibility
#if defined _WIN32 || defined __CYGWIN__
#ifdef __GNUC__
#define RCLCPP_ACTION_EXPORT __attribute__ ((dllexport))
#define RCLCPP_ACTION_IMPORT __attribute__ ((dllimport))
#else
#define RCLCPP_ACTION_EXPORT __declspec(dllexport)
#define RCLCPP_ACTION_IMPORT __declspec(dllimport)
#endif
#ifdef RCLCPP_ACTION_BUILDING_LIBRARY
#define RCLCPP_ACTION_PUBLIC RCLCPP_ACTION_EXPORT
#else
#define RCLCPP_ACTION_PUBLIC RCLCPP_ACTION_IMPORT
#endif
#define RCLCPP_ACTION_PUBLIC_TYPE RCLCPP_ACTION_PUBLIC
#define RCLCPP_ACTION_LOCAL
#else
#define RCLCPP_ACTION_EXPORT __attribute__ ((visibility("default")))
#define RCLCPP_ACTION_IMPORT
#if __GNUC__ >= 4
#define RCLCPP_ACTION_PUBLIC __attribute__ ((visibility("default")))
#define RCLCPP_ACTION_LOCAL __attribute__ ((visibility("hidden")))
#else
#define RCLCPP_ACTION_PUBLIC
#define RCLCPP_ACTION_LOCAL
#endif
#define RCLCPP_ACTION_PUBLIC_TYPE
#endif
#endif // RCLCPP_ACTION__VISIBILITY_CONTROL_HPP_