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

[rclcpp action example] Added new action package: random_generator #336

Open
wants to merge 1 commit into
base: rolling
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions rclcpp/actions/random_generator/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
cmake_minimum_required(VERSION 3.8)
project(random_generator)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rclcpp_action REQUIRED)
find_package(rclcpp_components REQUIRED)
find_package(rosidl_default_generators REQUIRED)

# Action Interface
rosidl_generate_interfaces(${PROJECT_NAME}
"action/Randomizer.action"
)
ament_export_dependencies(
rosidl_default_runtime
)

# Action Client
add_library(action_client SHARED
src/randomizer_action_client.cpp)
target_include_directories(action_client PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_compile_definitions(action_client
PRIVATE "RANDOM_GENERATOR_BUILDING_DLL")
ament_target_dependencies(action_client
"rclcpp"
"rclcpp_action"
"rclcpp_components")
rclcpp_components_register_node(action_client
PLUGIN "random_generator::RandomizerActionClient"
EXECUTABLE randomizer_action_client)
install(TARGETS action_client
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)

# Action Server
add_library(action_server SHARED
src/randomizer_action_server.cpp)
target_include_directories(action_server PRIVATE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_compile_definitions(action_server
PRIVATE "RANDOM_GENERATOR_BUILDING_DLL")
ament_target_dependencies(action_server
"rclcpp"
"rclcpp_action"
"rclcpp_components")
rclcpp_components_register_node(action_server
PLUGIN "random_generator::RandomizerActionServer"
EXECUTABLE randomizer_action_server)
install(TARGETS action_server
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)

# Include the action interface to the client and server, both the library and executable
rosidl_target_interfaces(action_server
${PROJECT_NAME} "rosidl_typesupport_cpp")
rosidl_target_interfaces(action_client
${PROJECT_NAME} "rosidl_typesupport_cpp")
rosidl_target_interfaces(randomizer_action_client
${PROJECT_NAME} "rosidl_typesupport_cpp")
rosidl_target_interfaces(randomizer_action_server
${PROJECT_NAME} "rosidl_typesupport_cpp")

# Finally
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# the following line skips the linter which checks for copyrights
# uncomment the line when a copyright and license is not present in all source files
#set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# uncomment the line when this package is not in a git repo
#set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
endif()

ament_package()
6 changes: 6 additions & 0 deletions rclcpp/actions/random_generator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# A single package with the action interface and the client and server.

This package contains an few example which show how to create a single package with the interface, client and server, all in one.

The main difference between the msg/srv interface that was included into a package with it's client and service is that an action client and server needs to have both the library and executable included in the rosidl_typesupport_cpp in the CMakeLists file.

8 changes: 8 additions & 0 deletions rclcpp/actions/random_generator/action/Randomizer.action
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
uint16 number_of_values
float64 min_val
float64 max_val
---
float64[] random_values
---
uint16 number_of_random_values_calculated
float64 new_random_value
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef RANDOM_GENERATOR__VISIBILITY_CONTROL_H_
#define RANDOM_GENERATOR__VISIBILITY_CONTROL_H_

#ifdef __cplusplus
extern "C"
{
#endif

// 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 RANDOM_GENERATOR_EXPORT __attribute__ ((dllexport))
#define RANDOM_GENERATOR_IMPORT __attribute__ ((dllimport))
#else
#define RANDOM_GENERATOR_EXPORT __declspec(dllexport)
#define RANDOM_GENERATOR_IMPORT __declspec(dllimport)
#endif
#ifdef RANDOM_GENERATOR_BUILDING_DLL
#define RANDOM_GENERATOR_PUBLIC RANDOM_GENERATOR_EXPORT
#else
#define RANDOM_GENERATOR_PUBLIC RANDOM_GENERATOR_IMPORT
#endif
#define RANDOM_GENERATOR_PUBLIC_TYPE RANDOM_GENERATOR_PUBLIC
#define RANDOM_GENERATOR_LOCAL
#else
#define RANDOM_GENERATOR_EXPORT __attribute__ ((visibility("default")))
#define RANDOM_GENERATOR_IMPORT
#if __GNUC__ >= 4
#define RANDOM_GENERATOR_PUBLIC __attribute__ ((visibility("default")))
#define RANDOM_GENERATOR_LOCAL __attribute__ ((visibility("hidden")))
#else
#define RANDOM_GENERATOR_PUBLIC
#define RANDOM_GENERATOR_LOCAL
#endif
#define RANDOM_GENERATOR_PUBLIC_TYPE
#endif

#ifdef __cplusplus
}
#endif

#endif // RANDOM_GENERATOR__VISIBILITY_CONTROL_H_
27 changes: 27 additions & 0 deletions rclcpp/actions/random_generator/package.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>random_generator</name>
<version>0.0.0</version>
<description>TODO: Package description</description>
<maintainer email="tirine@todo.todo">tirine</maintainer>
<license>TODO: License declaration</license>

<buildtool_depend>ament_cmake</buildtool_depend>
<buildtool_depend>rosidl_default_generators</buildtool_depend>

<depend>randomizer_action_interface</depend>
<depend>action_msgs</depend>
<depend>rclcpp</depend>
<depend>rclcpp_action</depend>
<depend>rclcpp_components</depend>

<member_of_group>rosidl_interface_packages</member_of_group>

<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>

<export>
<build_type>ament_cmake</build_type>
</export>
</package>
116 changes: 116 additions & 0 deletions rclcpp/actions/random_generator/src/randomizer_action_client.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Copyright 2016 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.

#include <functional>
#include <future>
#include <memory>
#include <sstream>
#include <string>

#include "random_generator/action/randomizer.hpp"

#include "rclcpp/rclcpp.hpp"
#include "rclcpp_action/rclcpp_action.hpp"
#include "rclcpp_components/register_node_macro.hpp"

namespace random_generator {
class RandomizerActionClient : public rclcpp::Node {
public:
using Randomizer = action::Randomizer;
using GoalHandleRandomizer = rclcpp_action::ClientGoalHandle<Randomizer>;

explicit RandomizerActionClient(const rclcpp::NodeOptions& options)
: Node("randomizer_action_client", options) {
this->client_ptr_ = rclcpp_action::create_client<Randomizer>(this, "randomizer");

this->timer_ = this->create_wall_timer(std::chrono::milliseconds(500),
std::bind(&RandomizerActionClient::send_goal, this));
}

void send_goal() {
using namespace std::placeholders;

this->timer_->cancel();

if (!this->client_ptr_->wait_for_action_server()) {
RCLCPP_ERROR(this->get_logger(), "Action server not available after waiting");
rclcpp::shutdown();
}

auto goal_msg = Randomizer::Goal();
goal_msg.number_of_values = 10;
goal_msg.min_val = 0.5;
goal_msg.max_val = 9.5;

RCLCPP_INFO(this->get_logger(), "Sending goal");

auto send_goal_options = rclcpp_action::Client<Randomizer>::SendGoalOptions();
send_goal_options.goal_response_callback =
std::bind(&RandomizerActionClient::goal_response_callback, this, _1);
send_goal_options.feedback_callback =
std::bind(&RandomizerActionClient::feedback_callback, this, _1, _2);
send_goal_options.result_callback =
std::bind(&RandomizerActionClient::result_callback, this, _1);
this->client_ptr_->async_send_goal(goal_msg, send_goal_options);
}

private:
rclcpp_action::Client<Randomizer>::SharedPtr client_ptr_;
rclcpp::TimerBase::SharedPtr timer_;

void goal_response_callback(std::shared_future<GoalHandleRandomizer::SharedPtr> future) {
auto goal_handle = future.get();
if (!goal_handle) {
RCLCPP_ERROR(this->get_logger(), "Goal was rejected by server");
} else {
RCLCPP_INFO(this->get_logger(), "Goal accepted by server, waiting for result");
}
}

void feedback_callback(GoalHandleRandomizer::SharedPtr,
const std::shared_ptr<const Randomizer::Feedback> feedback) {
std::stringstream ss;
ss << std::setprecision(6);
ss << "Next random number: " << feedback->new_random_value
<< ". \t Done: " << feedback->number_of_random_values_calculated << " values.";
RCLCPP_INFO(this->get_logger(), ss.str().c_str());
}

void result_callback(const GoalHandleRandomizer::WrappedResult& result_handle) {
switch (result_handle.code) {
case rclcpp_action::ResultCode::SUCCEEDED:
break;
case rclcpp_action::ResultCode::ABORTED:
RCLCPP_ERROR(this->get_logger(), "Goal was aborted");
return;
case rclcpp_action::ResultCode::CANCELED:
RCLCPP_ERROR(this->get_logger(), "Goal was canceled");
return;
default:
RCLCPP_ERROR(this->get_logger(), "Unknown result code");
return;
}
std::stringstream ss;
ss << "Result received: ";
for (auto number : result_handle.result->random_values) {
ss << number << " ";
}
RCLCPP_INFO(this->get_logger(), ss.str().c_str());
rclcpp::shutdown();
}
}; // class RandomizerActionClient

} // namespace random_generator

RCLCPP_COMPONENTS_REGISTER_NODE(random_generator::RandomizerActionClient)
Loading