Skip to content

Commit

Permalink
Added random_generator package, including an action interface, action…
Browse files Browse the repository at this point in the history
… client and action server, all in one.

Signed-off-by: Tirine <[email protected]>
  • Loading branch information
Tirine committed Jan 29, 2022
1 parent 200a16c commit 7f76311
Show file tree
Hide file tree
Showing 7 changed files with 400 additions and 0 deletions.
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="[email protected]">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

0 comments on commit 7f76311

Please sign in to comment.