Compare commits
5 Commits
mjcarroll/
...
21.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77ede02251 | ||
|
|
a431256383 | ||
|
|
9d2849cb0a | ||
|
|
3610b68348 | ||
|
|
9c03a463c1 |
@@ -2,6 +2,18 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
21.1.0 (2023-04-27)
|
||||
-------------------
|
||||
|
||||
21.0.0 (2023-04-18)
|
||||
-------------------
|
||||
* Add support for logging service. (`#2122 <https://github.com/ros2/rclcpp/issues/2122>`_)
|
||||
* Picking ABI-incompatible executor changes (`#2170 <https://github.com/ros2/rclcpp/issues/2170>`_)
|
||||
* add events-executor and timers-manager in rclcpp (`#2155 <https://github.com/ros2/rclcpp/issues/2155>`_)
|
||||
* Create common structures for executors to use (`#2143 <https://github.com/ros2/rclcpp/issues/2143>`_)
|
||||
* Implement deliver message kind (`#2168 <https://github.com/ros2/rclcpp/issues/2168>`_)
|
||||
* Contributors: Alberto Soragna, Lei Liu, Michael Carroll, methylDragon
|
||||
|
||||
20.0.0 (2023-04-13)
|
||||
-------------------
|
||||
* applied tracepoints for ring_buffer (`#2091 <https://github.com/ros2/rclcpp/issues/2091>`_)
|
||||
|
||||
@@ -180,6 +180,13 @@ public:
|
||||
return _find_ptrs_if_impl<rclcpp::Waitable, Function>(func, waitable_ptrs_);
|
||||
}
|
||||
|
||||
/// Get the total number of entities in this callback group.
|
||||
/**
|
||||
* \return the number of entities in the callback group.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
size_t size() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::atomic_bool &
|
||||
can_be_taken_from();
|
||||
|
||||
@@ -51,6 +51,7 @@ typedef std::map<rclcpp::CallbackGroup::WeakPtr,
|
||||
|
||||
// Forward declaration is used in convenience method signature.
|
||||
class Node;
|
||||
class ExecutorImplementation;
|
||||
|
||||
/// Coordinate the order and timing of available communication tasks.
|
||||
/**
|
||||
@@ -697,6 +698,9 @@ protected:
|
||||
|
||||
/// shutdown callback handle registered to Context
|
||||
rclcpp::OnShutdownCallbackHandle shutdown_callback_handle_;
|
||||
|
||||
/// Pointer to implementation
|
||||
std::unique_ptr<ExecutorImplementation> impl_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -198,14 +198,15 @@ build_entities_collection(
|
||||
*
|
||||
* \param[in] collection Collection of entities corresponding to the current wait set.
|
||||
* \param[in] wait_result Result of rclcpp::WaitSet::wait corresponding to the collection.
|
||||
* \return A queue of executables that have been marked ready by the waitset.
|
||||
* \param[inout] queue of executables to append new ready executables to
|
||||
* \return number of new ready executables
|
||||
*/
|
||||
std::deque<rclcpp::AnyExecutable>
|
||||
size_t
|
||||
ready_executables(
|
||||
const ExecutorEntitiesCollection & collection,
|
||||
rclcpp::WaitResult<rclcpp::WaitSet> & wait_result
|
||||
rclcpp::WaitResult<rclcpp::WaitSet> & wait_result,
|
||||
std::deque<rclcpp::AnyExecutable> & executables
|
||||
);
|
||||
|
||||
} // namespace executors
|
||||
} // namespace rclcpp
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include "rclcpp/node_interfaces/node_logging_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
#include "rcl_interfaces/srv/get_logger_levels.hpp"
|
||||
#include "rcl_interfaces/srv/set_logger_levels.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
@@ -35,7 +38,7 @@ public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeLoggingInterface)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit NodeLogging(rclcpp::node_interfaces::NodeBaseInterface * node_base);
|
||||
explicit NodeLogging(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -49,13 +52,21 @@ public:
|
||||
const char *
|
||||
get_logger_name() const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
create_logger_services(
|
||||
node_interfaces::NodeServicesInterface::SharedPtr node_services) override;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeLogging)
|
||||
|
||||
/// Handle to the NodeBaseInterface given in the constructor.
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base_;
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_;
|
||||
|
||||
rclcpp::Logger logger_;
|
||||
|
||||
rclcpp::Service<rcl_interfaces::srv::GetLoggerLevels>::SharedPtr get_loggers_service_;
|
||||
rclcpp::Service<rcl_interfaces::srv::SetLoggerLevels>::SharedPtr set_loggers_service_;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -54,6 +55,13 @@ public:
|
||||
virtual
|
||||
const char *
|
||||
get_logger_name() const = 0;
|
||||
|
||||
/// create logger services
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
create_logger_services(
|
||||
node_interfaces::NodeServicesInterface::SharedPtr node_services) = 0;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
* - clock_type = RCL_ROS_TIME
|
||||
* - clock_qos = rclcpp::ClockQoS()
|
||||
* - use_clock_thread = true
|
||||
* - enable_logger_service = false
|
||||
* - rosout_qos = rclcpp::RosoutQoS()
|
||||
* - parameter_event_qos = rclcpp::ParameterEventQoS
|
||||
* - with history setting and depth from rmw_qos_profile_parameter_events
|
||||
@@ -232,6 +233,24 @@ public:
|
||||
NodeOptions &
|
||||
start_parameter_services(bool start_parameter_services);
|
||||
|
||||
/// Return the enable_logger_service flag.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
enable_logger_service() const;
|
||||
|
||||
/// Set the enable_logger_service flag, return this for logger idiom.
|
||||
/**
|
||||
* If true, ROS services are created to allow external nodes to get
|
||||
* and set logger levels of this node.
|
||||
*
|
||||
* If false, loggers will still be configured and set logger levels locally,
|
||||
* but logger levels cannot be changed remotely .
|
||||
*
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
NodeOptions &
|
||||
enable_logger_service(bool enable_log_service);
|
||||
|
||||
/// Return the start_parameter_event_publisher flag.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
@@ -421,6 +440,8 @@ private:
|
||||
|
||||
bool use_clock_thread_ {true};
|
||||
|
||||
bool enable_logger_service_ {false};
|
||||
|
||||
rclcpp::QoS parameter_event_qos_ = rclcpp::ParameterEventsQoS(
|
||||
rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events)
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp</name>
|
||||
<version>20.0.0</version>
|
||||
<version>21.1.0</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -56,6 +56,16 @@ CallbackGroup::type() const
|
||||
return type_;
|
||||
}
|
||||
|
||||
size_t
|
||||
CallbackGroup::size() const
|
||||
{
|
||||
return
|
||||
subscription_ptrs_.size() +
|
||||
service_ptrs_.size() +
|
||||
client_ptrs_.size() +
|
||||
timer_ptrs_.size() +
|
||||
waitable_ptrs_.size();
|
||||
}
|
||||
void CallbackGroup::collect_all_ptrs(
|
||||
std::function<void(const rclcpp::SubscriptionBase::SharedPtr &)> sub_func,
|
||||
std::function<void(const rclcpp::ServiceBase::SharedPtr &)> service_func,
|
||||
|
||||
@@ -41,11 +41,14 @@ using namespace std::chrono_literals;
|
||||
using rclcpp::exceptions::throw_from_rcl_error;
|
||||
using rclcpp::Executor;
|
||||
|
||||
class rclcpp::ExecutorImplementation {};
|
||||
|
||||
Executor::Executor(const rclcpp::ExecutorOptions & options)
|
||||
: spinning(false),
|
||||
interrupt_guard_condition_(std::make_shared<rclcpp::GuardCondition>(options.context)),
|
||||
shutdown_guard_condition_(std::make_shared<rclcpp::GuardCondition>(options.context)),
|
||||
memory_strategy_(options.memory_strategy)
|
||||
memory_strategy_(options.memory_strategy),
|
||||
impl_(std::make_unique<rclcpp::ExecutorImplementation>())
|
||||
{
|
||||
// Store the context for later use.
|
||||
context_ = options.context;
|
||||
|
||||
@@ -20,12 +20,13 @@ namespace executors
|
||||
{
|
||||
bool ExecutorEntitiesCollection::empty() const
|
||||
{
|
||||
return subscriptions.empty() &&
|
||||
timers.empty() &&
|
||||
guard_conditions.empty() &&
|
||||
clients.empty() &&
|
||||
services.empty() &&
|
||||
waitables.empty();
|
||||
return
|
||||
subscriptions.empty() &&
|
||||
timers.empty() &&
|
||||
guard_conditions.empty() &&
|
||||
clients.empty() &&
|
||||
services.empty() &&
|
||||
waitables.empty();
|
||||
}
|
||||
|
||||
void ExecutorEntitiesCollection::clear()
|
||||
@@ -38,7 +39,6 @@ void ExecutorEntitiesCollection::clear()
|
||||
waitables.clear();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
build_entities_collection(
|
||||
const std::vector<rclcpp::CallbackGroup::WeakPtr> & callback_groups,
|
||||
@@ -94,109 +94,136 @@ build_entities_collection(
|
||||
}
|
||||
}
|
||||
|
||||
template<typename EntityCollectionType>
|
||||
void check_ready(
|
||||
EntityCollectionType & collection,
|
||||
std::deque<rclcpp::AnyExecutable> & executables,
|
||||
size_t size_of_waited_entities,
|
||||
typename EntityCollectionType::Key * waited_entities,
|
||||
std::function<bool(rclcpp::AnyExecutable &,
|
||||
typename EntityCollectionType::EntitySharedPtr &)> fill_executable)
|
||||
size_t
|
||||
ready_executables(
|
||||
const ExecutorEntitiesCollection & collection,
|
||||
rclcpp::WaitResult<rclcpp::WaitSet> & wait_result,
|
||||
std::deque<rclcpp::AnyExecutable> & executables
|
||||
)
|
||||
{
|
||||
for (size_t ii = 0; ii < size_of_waited_entities; ++ii) {
|
||||
if (!waited_entities[ii]) {continue;}
|
||||
auto entity_iter = collection.find(waited_entities[ii]);
|
||||
if (entity_iter != collection.end()) {
|
||||
size_t added = 0;
|
||||
if (wait_result.kind() != rclcpp::WaitResultKind::Ready) {
|
||||
return added;
|
||||
}
|
||||
auto rcl_wait_set = wait_result.get_wait_set().get_rcl_wait_set();
|
||||
|
||||
// Cache shared pointers to groups to avoid extra work re-locking them
|
||||
std::map<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::CallbackGroup::SharedPtr,
|
||||
std::owner_less<rclcpp::CallbackGroup::WeakPtr>> group_map;
|
||||
|
||||
auto group_cache = [&group_map](const rclcpp::CallbackGroup::WeakPtr & weak_cbg_ptr)
|
||||
{
|
||||
if (group_map.count(weak_cbg_ptr) == 0) {
|
||||
group_map.insert({weak_cbg_ptr, weak_cbg_ptr.lock()});
|
||||
}
|
||||
return group_map.find(weak_cbg_ptr)->second;
|
||||
};
|
||||
|
||||
for (size_t ii = 0; ii < rcl_wait_set.size_of_timers; ++ii) {
|
||||
if (nullptr == rcl_wait_set.timers[ii]) {continue;}
|
||||
auto entity_iter = collection.timers.find(rcl_wait_set.timers[ii]);
|
||||
if (entity_iter != collection.timers.end()) {
|
||||
auto entity = entity_iter->second.entity.lock();
|
||||
if (!entity) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto callback_group = entity_iter->second.callback_group.lock();
|
||||
if (callback_group && !callback_group->can_be_taken_from().load()) {
|
||||
auto group_info = group_cache(entity_iter->second.callback_group);
|
||||
if (group_info && !group_info->can_be_taken_from().load()) {
|
||||
continue;
|
||||
}
|
||||
if (!entity->call()) {
|
||||
continue;
|
||||
}
|
||||
rclcpp::AnyExecutable exec;
|
||||
|
||||
exec.callback_group = callback_group;
|
||||
if (fill_executable(exec, entity)) {
|
||||
executables.push_back(exec);
|
||||
}
|
||||
exec.timer = entity;
|
||||
exec.callback_group = group_info;
|
||||
executables.push_back(exec);
|
||||
added++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::deque<rclcpp::AnyExecutable>
|
||||
ready_executables(
|
||||
const ExecutorEntitiesCollection & collection,
|
||||
rclcpp::WaitResult<rclcpp::WaitSet> & wait_result
|
||||
)
|
||||
{
|
||||
std::deque<rclcpp::AnyExecutable> ret;
|
||||
|
||||
if (wait_result.kind() != rclcpp::WaitResultKind::Ready) {
|
||||
return ret;
|
||||
}
|
||||
auto rcl_wait_set = wait_result.get_wait_set().get_rcl_wait_set();
|
||||
check_ready(
|
||||
collection.timers,
|
||||
ret,
|
||||
rcl_wait_set.size_of_timers,
|
||||
rcl_wait_set.timers,
|
||||
[](rclcpp::AnyExecutable & exec, auto timer) {
|
||||
if (!timer->call()) {
|
||||
return false;
|
||||
for (size_t ii = 0; ii < rcl_wait_set.size_of_subscriptions; ++ii) {
|
||||
if (nullptr == rcl_wait_set.subscriptions[ii]) {continue;}
|
||||
auto entity_iter = collection.subscriptions.find(rcl_wait_set.subscriptions[ii]);
|
||||
if (entity_iter != collection.subscriptions.end()) {
|
||||
auto entity = entity_iter->second.entity.lock();
|
||||
if (!entity) {
|
||||
continue;
|
||||
}
|
||||
exec.timer = timer;
|
||||
return true;
|
||||
});
|
||||
auto group_info = group_cache(entity_iter->second.callback_group);
|
||||
if (group_info && !group_info->can_be_taken_from().load()) {
|
||||
continue;
|
||||
}
|
||||
rclcpp::AnyExecutable exec;
|
||||
exec.subscription = entity;
|
||||
exec.callback_group = group_info;
|
||||
executables.push_back(exec);
|
||||
added++;
|
||||
}
|
||||
}
|
||||
|
||||
check_ready(
|
||||
collection.subscriptions,
|
||||
ret,
|
||||
rcl_wait_set.size_of_subscriptions,
|
||||
rcl_wait_set.subscriptions,
|
||||
[](rclcpp::AnyExecutable & exec, auto subscription) {
|
||||
exec.subscription = subscription;
|
||||
return true;
|
||||
});
|
||||
for (size_t ii = 0; ii < rcl_wait_set.size_of_services; ++ii) {
|
||||
if (nullptr == rcl_wait_set.services[ii]) {continue;}
|
||||
auto entity_iter = collection.services.find(rcl_wait_set.services[ii]);
|
||||
if (entity_iter != collection.services.end()) {
|
||||
auto entity = entity_iter->second.entity.lock();
|
||||
if (!entity) {
|
||||
continue;
|
||||
}
|
||||
auto group_info = group_cache(entity_iter->second.callback_group);
|
||||
if (group_info && !group_info->can_be_taken_from().load()) {
|
||||
continue;
|
||||
}
|
||||
rclcpp::AnyExecutable exec;
|
||||
exec.service = entity;
|
||||
exec.callback_group = group_info;
|
||||
executables.push_back(exec);
|
||||
added++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
check_ready(
|
||||
collection.services,
|
||||
ret,
|
||||
rcl_wait_set.size_of_services,
|
||||
rcl_wait_set.services,
|
||||
[](rclcpp::AnyExecutable & exec, auto service) {
|
||||
exec.service = service;
|
||||
return true;
|
||||
});
|
||||
|
||||
check_ready(
|
||||
collection.clients,
|
||||
ret,
|
||||
rcl_wait_set.size_of_clients,
|
||||
rcl_wait_set.clients,
|
||||
[](rclcpp::AnyExecutable & exec, auto client) {
|
||||
exec.client = client;
|
||||
return true;
|
||||
});
|
||||
for (size_t ii = 0; ii < rcl_wait_set.size_of_clients; ++ii) {
|
||||
if (nullptr == rcl_wait_set.clients[ii]) {continue;}
|
||||
auto entity_iter = collection.clients.find(rcl_wait_set.clients[ii]);
|
||||
if (entity_iter != collection.clients.end()) {
|
||||
auto entity = entity_iter->second.entity.lock();
|
||||
if (!entity) {
|
||||
continue;
|
||||
}
|
||||
auto group_info = group_cache(entity_iter->second.callback_group);
|
||||
if (group_info && !group_info->can_be_taken_from().load()) {
|
||||
continue;
|
||||
}
|
||||
rclcpp::AnyExecutable exec;
|
||||
exec.client = entity;
|
||||
exec.callback_group = group_info;
|
||||
executables.push_back(exec);
|
||||
added++;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto & [handle, entry] : collection.waitables) {
|
||||
auto waitable = entry.entity.lock();
|
||||
if (waitable && waitable->is_ready(&rcl_wait_set)) {
|
||||
auto group = entry.callback_group.lock();
|
||||
if (group && !group->can_be_taken_from().load()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rclcpp::AnyExecutable exec;
|
||||
exec.waitable = waitable;
|
||||
exec.callback_group = group;
|
||||
ret.push_back(exec);
|
||||
if (!waitable) {
|
||||
continue;
|
||||
}
|
||||
if (!waitable->is_ready(&rcl_wait_set)) {
|
||||
continue;
|
||||
}
|
||||
auto group_info = group_cache(entry.callback_group);
|
||||
if (group_info && !group_info->can_be_taken_from().load()) {
|
||||
continue;
|
||||
}
|
||||
rclcpp::AnyExecutable exec;
|
||||
exec.waitable = waitable;
|
||||
exec.callback_group = group_info;
|
||||
exec.data = waitable->take_data();
|
||||
executables.push_back(exec);
|
||||
added++;
|
||||
}
|
||||
return ret;
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
} // namespace executors
|
||||
|
||||
@@ -167,7 +167,7 @@ Node::Node(
|
||||
options.use_intra_process_comms(),
|
||||
options.enable_topic_statistics())),
|
||||
node_graph_(new rclcpp::node_interfaces::NodeGraph(node_base_.get())),
|
||||
node_logging_(new rclcpp::node_interfaces::NodeLogging(node_base_.get())),
|
||||
node_logging_(new rclcpp::node_interfaces::NodeLogging(node_base_)),
|
||||
node_timers_(new rclcpp::node_interfaces::NodeTimers(node_base_.get())),
|
||||
node_topics_(new rclcpp::node_interfaces::NodeTopics(node_base_.get(), node_timers_.get())),
|
||||
node_services_(new rclcpp::node_interfaces::NodeServices(node_base_.get())),
|
||||
@@ -225,6 +225,10 @@ Node::Node(
|
||||
node_topics_->resolve_topic_name("/parameter_events"),
|
||||
options.parameter_event_qos(),
|
||||
rclcpp::detail::PublisherQosParametersTraits{});
|
||||
|
||||
if (options.enable_logger_service()) {
|
||||
node_logging_->create_logger_services(node_services_);
|
||||
}
|
||||
}
|
||||
|
||||
Node::Node(
|
||||
|
||||
@@ -12,11 +12,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/node_impl.hpp"
|
||||
#include "rclcpp/node_interfaces/node_logging.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services_interface.hpp"
|
||||
|
||||
using rclcpp::node_interfaces::NodeLogging;
|
||||
|
||||
NodeLogging::NodeLogging(rclcpp::node_interfaces::NodeBaseInterface * node_base)
|
||||
NodeLogging::NodeLogging(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base)
|
||||
: node_base_(node_base)
|
||||
{
|
||||
logger_ = rclcpp::get_logger(NodeLogging::get_logger_name());
|
||||
@@ -37,3 +39,55 @@ NodeLogging::get_logger_name() const
|
||||
{
|
||||
return rcl_node_get_logger_name(node_base_->get_rcl_node_handle());
|
||||
}
|
||||
|
||||
void NodeLogging::create_logger_services(
|
||||
node_interfaces::NodeServicesInterface::SharedPtr node_services)
|
||||
{
|
||||
rclcpp::ServicesQoS qos_profile;
|
||||
const std::string node_name = node_base_->get_name();
|
||||
auto callback_group = node_base_->get_default_callback_group();
|
||||
|
||||
get_loggers_service_ = rclcpp::create_service<rcl_interfaces::srv::GetLoggerLevels>(
|
||||
node_base_, node_services,
|
||||
node_name + "/get_logger_levels",
|
||||
[](
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<rcl_interfaces::srv::GetLoggerLevels::Request> request,
|
||||
std::shared_ptr<rcl_interfaces::srv::GetLoggerLevels::Response> response)
|
||||
{
|
||||
for (auto & name : request->names) {
|
||||
rcl_interfaces::msg::LoggerLevel logger_level;
|
||||
logger_level.name = name;
|
||||
auto ret = rcutils_logging_get_logger_level(name.c_str());
|
||||
if (ret < 0) {
|
||||
logger_level.level = 0;
|
||||
} else {
|
||||
logger_level.level = static_cast<uint8_t>(ret);
|
||||
}
|
||||
response->levels.push_back(std::move(logger_level));
|
||||
}
|
||||
},
|
||||
qos_profile, callback_group);
|
||||
|
||||
set_loggers_service_ = rclcpp::create_service<rcl_interfaces::srv::SetLoggerLevels>(
|
||||
node_base_, node_services,
|
||||
node_name + "/set_logger_levels",
|
||||
[](
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<rcl_interfaces::srv::SetLoggerLevels::Request> request,
|
||||
std::shared_ptr<rcl_interfaces::srv::SetLoggerLevels::Response> response)
|
||||
{
|
||||
rcl_interfaces::msg::SetLoggerLevelsResult result;
|
||||
for (auto & level : request->levels) {
|
||||
auto ret = rcutils_logging_set_logger_level(level.name.c_str(), level.level);
|
||||
if (ret != RCUTILS_RET_OK) {
|
||||
result.successful = false;
|
||||
result.reason = rcutils_get_error_string().str;
|
||||
} else {
|
||||
result.successful = true;
|
||||
}
|
||||
response->results.push_back(std::move(result));
|
||||
}
|
||||
},
|
||||
qos_profile, callback_group);
|
||||
}
|
||||
|
||||
@@ -248,6 +248,19 @@ NodeOptions::start_parameter_services(bool start_parameter_services)
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
NodeOptions::enable_logger_service() const
|
||||
{
|
||||
return this->enable_logger_service_;
|
||||
}
|
||||
|
||||
NodeOptions &
|
||||
NodeOptions::enable_logger_service(bool enable_logger_service)
|
||||
{
|
||||
this->enable_logger_service_ = enable_logger_service;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
NodeOptions::start_parameter_event_publisher() const
|
||||
{
|
||||
|
||||
@@ -649,6 +649,13 @@ if(TARGET test_wait_for_message)
|
||||
target_link_libraries(test_wait_for_message ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_logger_service test_logger_service.cpp)
|
||||
if(TARGET test_logger_service)
|
||||
ament_target_dependencies(test_logger_service
|
||||
"rcl_interfaces")
|
||||
target_link_libraries(test_logger_service ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_interface_traits test_interface_traits.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_interface_traits)
|
||||
|
||||
214
rclcpp/test/rclcpp/test_logger_service.cpp
Normal file
214
rclcpp/test/rclcpp/test_logger_service.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
// Copyright 2023 Sony Group Corporation.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rcl_interfaces/srv/get_logger_levels.hpp"
|
||||
#include "rcl_interfaces/srv/set_logger_levels.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class TestLoggerService : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
rclcpp::NodeOptions options = rclcpp::NodeOptions();
|
||||
options.enable_logger_service(true);
|
||||
node_ = std::make_shared<rclcpp::Node>("test_logger_service", "/test", options);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
rclcpp::Node::SharedPtr node_;
|
||||
std::thread thread_;
|
||||
};
|
||||
|
||||
TEST_F(TestLoggerService, check_connect_get_logger_service) {
|
||||
auto client = node_->create_client<rcl_interfaces::srv::GetLoggerLevels>(
|
||||
"/test/test_logger_service/get_logger_levels");
|
||||
ASSERT_TRUE(client->wait_for_service(2s));
|
||||
}
|
||||
|
||||
TEST_F(TestLoggerService, check_connect_set_logger_service) {
|
||||
auto client = node_->create_client<rcl_interfaces::srv::SetLoggerLevels>(
|
||||
"/test/test_logger_service/set_logger_levels");
|
||||
ASSERT_TRUE(client->wait_for_service(2s));
|
||||
}
|
||||
|
||||
TEST_F(TestLoggerService, test_set_and_get_one_logging_level) {
|
||||
std::string test_logger_name = "rcl";
|
||||
uint8_t test_logger_level = 20;
|
||||
{
|
||||
auto client = node_->create_client<rcl_interfaces::srv::SetLoggerLevels>(
|
||||
"/test/test_logger_service/set_logger_levels");
|
||||
ASSERT_TRUE(client->wait_for_service(1s));
|
||||
auto request = std::make_shared<rcl_interfaces::srv::SetLoggerLevels::Request>();
|
||||
auto level = rcl_interfaces::msg::LoggerLevel();
|
||||
level.name = test_logger_name;
|
||||
level.level = test_logger_level;
|
||||
request->levels.push_back(level);
|
||||
auto result = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::spin_until_future_complete(node_, result),
|
||||
rclcpp::FutureReturnCode::SUCCESS);
|
||||
auto result_get = result.get();
|
||||
ASSERT_EQ(result_get->results.size(), 1u);
|
||||
ASSERT_TRUE(result_get->results[0].successful);
|
||||
ASSERT_STREQ(result_get->results[0].reason.c_str(), "");
|
||||
}
|
||||
|
||||
{
|
||||
auto client = node_->create_client<rcl_interfaces::srv::GetLoggerLevels>(
|
||||
"/test/test_logger_service/get_logger_levels");
|
||||
ASSERT_TRUE(client->wait_for_service(1s));
|
||||
auto request = std::make_shared<rcl_interfaces::srv::GetLoggerLevels::Request>();
|
||||
request->names.emplace_back(test_logger_name);
|
||||
auto result = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::spin_until_future_complete(node_, result),
|
||||
rclcpp::FutureReturnCode::SUCCESS);
|
||||
auto result_get = result.get();
|
||||
ASSERT_EQ(result_get->levels.size(), 1u);
|
||||
ASSERT_STREQ(result_get->levels[0].name.c_str(), test_logger_name.c_str());
|
||||
ASSERT_EQ(result_get->levels[0].level, test_logger_level);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestLoggerService, test_set_and_get_multi_logging_level) {
|
||||
std::vector<std::pair<std::string, uint8_t>> test_data {
|
||||
{"rcl", 30},
|
||||
{"rclcpp", 40},
|
||||
{"/test/test_logger_service", 50}
|
||||
};
|
||||
|
||||
// Set multi log levels
|
||||
{
|
||||
auto client = node_->create_client<rcl_interfaces::srv::SetLoggerLevels>(
|
||||
"/test/test_logger_service/set_logger_levels");
|
||||
ASSERT_TRUE(client->wait_for_service(1s));
|
||||
auto request = std::make_shared<rcl_interfaces::srv::SetLoggerLevels::Request>();
|
||||
for (auto & set_level : test_data) {
|
||||
auto level = rcl_interfaces::msg::LoggerLevel();
|
||||
level.name = std::get<0>(set_level);
|
||||
level.level = std::get<1>(set_level);
|
||||
request->levels.push_back(level);
|
||||
}
|
||||
auto result = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::spin_until_future_complete(node_, result),
|
||||
rclcpp::FutureReturnCode::SUCCESS);
|
||||
auto result_get = result.get();
|
||||
ASSERT_EQ(result_get->results.size(), test_data.size());
|
||||
for (uint32_t i = 0; i < test_data.size(); i++) {
|
||||
ASSERT_TRUE(result_get->results[0].successful);
|
||||
}
|
||||
}
|
||||
|
||||
// Get multi log levels
|
||||
{
|
||||
auto client = node_->create_client<rcl_interfaces::srv::GetLoggerLevels>(
|
||||
"/test/test_logger_service/get_logger_levels");
|
||||
ASSERT_TRUE(client->wait_for_service(1s));
|
||||
auto request = std::make_shared<rcl_interfaces::srv::GetLoggerLevels::Request>();
|
||||
for (auto & set_level : test_data) {
|
||||
request->names.emplace_back(std::get<0>(set_level));
|
||||
}
|
||||
auto result = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::spin_until_future_complete(node_, result),
|
||||
rclcpp::FutureReturnCode::SUCCESS);
|
||||
auto result_get = result.get();
|
||||
ASSERT_EQ(result_get->levels.size(), test_data.size());
|
||||
for (uint32_t i = 0; i < test_data.size(); i++) {
|
||||
ASSERT_STREQ(result_get->levels[i].name.c_str(), std::get<0>(test_data[i]).c_str());
|
||||
ASSERT_EQ(result_get->levels[i].level, std::get<1>(test_data[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestLoggerService, test_set_logging_level_with_invalid_param) {
|
||||
std::vector<std::pair<std::string, uint8_t>> test_data {
|
||||
{"rcl", 12},
|
||||
{"/test/test_logger_service", 22}
|
||||
};
|
||||
|
||||
// Set multi log levels
|
||||
{
|
||||
auto client = node_->create_client<rcl_interfaces::srv::SetLoggerLevels>(
|
||||
"/test/test_logger_service/set_logger_levels");
|
||||
ASSERT_TRUE(client->wait_for_service(1s));
|
||||
auto request = std::make_shared<rcl_interfaces::srv::SetLoggerLevels::Request>();
|
||||
for (auto & set_level : test_data) {
|
||||
auto level = rcl_interfaces::msg::LoggerLevel();
|
||||
level.name = std::get<0>(set_level);
|
||||
level.level = std::get<1>(set_level);
|
||||
request->levels.push_back(level);
|
||||
}
|
||||
auto result = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::spin_until_future_complete(node_, result),
|
||||
rclcpp::FutureReturnCode::SUCCESS);
|
||||
auto result_get = result.get();
|
||||
ASSERT_EQ(result_get->results.size(), test_data.size());
|
||||
for (uint32_t i = 0; i < test_data.size(); i++) {
|
||||
ASSERT_FALSE(result_get->results[i].successful);
|
||||
// Check string starts with prefix
|
||||
ASSERT_EQ(
|
||||
result_get->results[i].reason.rfind("Unable to determine severity_string for severity", 0),
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestLoggerService, test_set_logging_level_with_partial_invalid_param) {
|
||||
std::vector<std::pair<std::string, uint8_t>> test_data {
|
||||
{"rcl", 20},
|
||||
{"rclcpp", 22},
|
||||
{"/test/test_logger_service", 30}
|
||||
};
|
||||
|
||||
// Set multi log levels
|
||||
{
|
||||
auto client = node_->create_client<rcl_interfaces::srv::SetLoggerLevels>(
|
||||
"/test/test_logger_service/set_logger_levels");
|
||||
ASSERT_TRUE(client->wait_for_service(1s));
|
||||
auto request = std::make_shared<rcl_interfaces::srv::SetLoggerLevels::Request>();
|
||||
for (auto & set_level : test_data) {
|
||||
auto level = rcl_interfaces::msg::LoggerLevel();
|
||||
level.name = std::get<0>(set_level);
|
||||
level.level = std::get<1>(set_level);
|
||||
request->levels.push_back(level);
|
||||
}
|
||||
auto result = client->async_send_request(request);
|
||||
ASSERT_EQ(
|
||||
rclcpp::spin_until_future_complete(node_, result),
|
||||
rclcpp::FutureReturnCode::SUCCESS);
|
||||
auto result_get = result.get();
|
||||
ASSERT_EQ(result_get->results.size(), test_data.size());
|
||||
ASSERT_TRUE(result_get->results[0].successful);
|
||||
ASSERT_FALSE(result_get->results[1].successful);
|
||||
ASSERT_TRUE(result_get->results[2].successful);
|
||||
}
|
||||
}
|
||||
@@ -266,6 +266,11 @@ TEST(TestNodeOptions, bool_setters_and_getters) {
|
||||
EXPECT_FALSE(options.automatically_declare_parameters_from_overrides());
|
||||
options.automatically_declare_parameters_from_overrides(true);
|
||||
EXPECT_TRUE(options.automatically_declare_parameters_from_overrides());
|
||||
|
||||
options.enable_logger_service(false);
|
||||
EXPECT_FALSE(options.enable_logger_service());
|
||||
options.enable_logger_service(true);
|
||||
EXPECT_TRUE(options.enable_logger_service());
|
||||
}
|
||||
|
||||
TEST(TestNodeOptions, parameter_event_qos) {
|
||||
|
||||
@@ -3,6 +3,12 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
21.1.0 (2023-04-27)
|
||||
-------------------
|
||||
|
||||
21.0.0 (2023-04-18)
|
||||
-------------------
|
||||
|
||||
20.0.0 (2023-04-13)
|
||||
-------------------
|
||||
* extract the result response before the callback is issued. (`#2132 <https://github.com/ros2/rclcpp/issues/2132>`_)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp_action</name>
|
||||
<version>20.0.0</version>
|
||||
<version>21.1.0</version>
|
||||
<description>Adds action APIs for C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
21.1.0 (2023-04-27)
|
||||
-------------------
|
||||
|
||||
21.0.0 (2023-04-18)
|
||||
-------------------
|
||||
|
||||
20.0.0 (2023-04-13)
|
||||
-------------------
|
||||
* Update all rclcpp packages to C++17. (`#2121 <https://github.com/ros2/rclcpp/issues/2121>`_)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp_components</name>
|
||||
<version>20.0.0</version>
|
||||
<version>21.1.0</version>
|
||||
<description>Package containing tools for dynamically loadable components</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -3,6 +3,15 @@ Changelog for package rclcpp_lifecycle
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
21.1.0 (2023-04-27)
|
||||
-------------------
|
||||
|
||||
21.0.0 (2023-04-18)
|
||||
-------------------
|
||||
* Add support for logging service. (`#2122 <https://github.com/ros2/rclcpp/issues/2122>`_)
|
||||
* Support publishing loaned messages in LifecyclePublisher (`#2159 <https://github.com/ros2/rclcpp/issues/2159>`_)
|
||||
* Contributors: Lei Liu, Michael Babenko
|
||||
|
||||
20.0.0 (2023-04-13)
|
||||
-------------------
|
||||
* Fixes to silence some clang warnings. (`#2127 <https://github.com/ros2/rclcpp/issues/2127>`_)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp_lifecycle</name>
|
||||
<version>20.0.0</version>
|
||||
<version>21.1.0</version>
|
||||
<description>Package containing a prototype for lifecycle implementation</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
|
||||
@@ -76,7 +76,7 @@ LifecycleNode::LifecycleNode(
|
||||
options.use_intra_process_comms(),
|
||||
options.enable_topic_statistics())),
|
||||
node_graph_(new rclcpp::node_interfaces::NodeGraph(node_base_.get())),
|
||||
node_logging_(new rclcpp::node_interfaces::NodeLogging(node_base_.get())),
|
||||
node_logging_(new rclcpp::node_interfaces::NodeLogging(node_base_)),
|
||||
node_timers_(new rclcpp::node_interfaces::NodeTimers(node_base_.get())),
|
||||
node_topics_(new rclcpp::node_interfaces::NodeTopics(node_base_.get(), node_timers_.get())),
|
||||
node_services_(new rclcpp::node_interfaces::NodeServices(node_base_.get())),
|
||||
|
||||
Reference in New Issue
Block a user