Skip to content

Commit 7f76311

Browse files
committed
Added random_generator package, including an action interface, action client and action server, all in one.
Signed-off-by: Tirine <[email protected]>
1 parent 200a16c commit 7f76311

File tree

7 files changed

+400
-0
lines changed

7 files changed

+400
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
cmake_minimum_required(VERSION 3.8)
2+
project(random_generator)
3+
4+
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
5+
add_compile_options(-Wall -Wextra -Wpedantic)
6+
endif()
7+
8+
# find dependencies
9+
find_package(ament_cmake REQUIRED)
10+
find_package(rclcpp REQUIRED)
11+
find_package(rclcpp_action REQUIRED)
12+
find_package(rclcpp_components REQUIRED)
13+
find_package(rosidl_default_generators REQUIRED)
14+
15+
# Action Interface
16+
rosidl_generate_interfaces(${PROJECT_NAME}
17+
"action/Randomizer.action"
18+
)
19+
ament_export_dependencies(
20+
rosidl_default_runtime
21+
)
22+
23+
# Action Client
24+
add_library(action_client SHARED
25+
src/randomizer_action_client.cpp)
26+
target_include_directories(action_client PRIVATE
27+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
28+
$<INSTALL_INTERFACE:include>)
29+
target_compile_definitions(action_client
30+
PRIVATE "RANDOM_GENERATOR_BUILDING_DLL")
31+
ament_target_dependencies(action_client
32+
"rclcpp"
33+
"rclcpp_action"
34+
"rclcpp_components")
35+
rclcpp_components_register_node(action_client
36+
PLUGIN "random_generator::RandomizerActionClient"
37+
EXECUTABLE randomizer_action_client)
38+
install(TARGETS action_client
39+
ARCHIVE DESTINATION lib
40+
LIBRARY DESTINATION lib
41+
RUNTIME DESTINATION bin)
42+
43+
# Action Server
44+
add_library(action_server SHARED
45+
src/randomizer_action_server.cpp)
46+
target_include_directories(action_server PRIVATE
47+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
48+
$<INSTALL_INTERFACE:include>)
49+
target_compile_definitions(action_server
50+
PRIVATE "RANDOM_GENERATOR_BUILDING_DLL")
51+
ament_target_dependencies(action_server
52+
"rclcpp"
53+
"rclcpp_action"
54+
"rclcpp_components")
55+
rclcpp_components_register_node(action_server
56+
PLUGIN "random_generator::RandomizerActionServer"
57+
EXECUTABLE randomizer_action_server)
58+
install(TARGETS action_server
59+
ARCHIVE DESTINATION lib
60+
LIBRARY DESTINATION lib
61+
RUNTIME DESTINATION bin)
62+
63+
# Include the action interface to the client and server, both the library and executable
64+
rosidl_target_interfaces(action_server
65+
${PROJECT_NAME} "rosidl_typesupport_cpp")
66+
rosidl_target_interfaces(action_client
67+
${PROJECT_NAME} "rosidl_typesupport_cpp")
68+
rosidl_target_interfaces(randomizer_action_client
69+
${PROJECT_NAME} "rosidl_typesupport_cpp")
70+
rosidl_target_interfaces(randomizer_action_server
71+
${PROJECT_NAME} "rosidl_typesupport_cpp")
72+
73+
# Finally
74+
if(BUILD_TESTING)
75+
find_package(ament_lint_auto REQUIRED)
76+
# the following line skips the linter which checks for copyrights
77+
# uncomment the line when a copyright and license is not present in all source files
78+
#set(ament_cmake_copyright_FOUND TRUE)
79+
# the following line skips cpplint (only works in a git repo)
80+
# uncomment the line when this package is not in a git repo
81+
#set(ament_cmake_cpplint_FOUND TRUE)
82+
ament_lint_auto_find_test_dependencies()
83+
endif()
84+
85+
ament_package()
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# A single package with the action interface and the client and server.
2+
3+
This package contains an few example which show how to create a single package with the interface, client and server, all in one.
4+
5+
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.
6+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
uint16 number_of_values
2+
float64 min_val
3+
float64 max_val
4+
---
5+
float64[] random_values
6+
---
7+
uint16 number_of_random_values_calculated
8+
float64 new_random_value
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#ifndef RANDOM_GENERATOR__VISIBILITY_CONTROL_H_
2+
#define RANDOM_GENERATOR__VISIBILITY_CONTROL_H_
3+
4+
#ifdef __cplusplus
5+
extern "C"
6+
{
7+
#endif
8+
9+
// This logic was borrowed (then namespaced) from the examples on the gcc wiki:
10+
// https://gcc.gnu.org/wiki/Visibility
11+
12+
#if defined _WIN32 || defined __CYGWIN__
13+
#ifdef __GNUC__
14+
#define RANDOM_GENERATOR_EXPORT __attribute__ ((dllexport))
15+
#define RANDOM_GENERATOR_IMPORT __attribute__ ((dllimport))
16+
#else
17+
#define RANDOM_GENERATOR_EXPORT __declspec(dllexport)
18+
#define RANDOM_GENERATOR_IMPORT __declspec(dllimport)
19+
#endif
20+
#ifdef RANDOM_GENERATOR_BUILDING_DLL
21+
#define RANDOM_GENERATOR_PUBLIC RANDOM_GENERATOR_EXPORT
22+
#else
23+
#define RANDOM_GENERATOR_PUBLIC RANDOM_GENERATOR_IMPORT
24+
#endif
25+
#define RANDOM_GENERATOR_PUBLIC_TYPE RANDOM_GENERATOR_PUBLIC
26+
#define RANDOM_GENERATOR_LOCAL
27+
#else
28+
#define RANDOM_GENERATOR_EXPORT __attribute__ ((visibility("default")))
29+
#define RANDOM_GENERATOR_IMPORT
30+
#if __GNUC__ >= 4
31+
#define RANDOM_GENERATOR_PUBLIC __attribute__ ((visibility("default")))
32+
#define RANDOM_GENERATOR_LOCAL __attribute__ ((visibility("hidden")))
33+
#else
34+
#define RANDOM_GENERATOR_PUBLIC
35+
#define RANDOM_GENERATOR_LOCAL
36+
#endif
37+
#define RANDOM_GENERATOR_PUBLIC_TYPE
38+
#endif
39+
40+
#ifdef __cplusplus
41+
}
42+
#endif
43+
44+
#endif // RANDOM_GENERATOR__VISIBILITY_CONTROL_H_
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0"?>
2+
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
3+
<package format="3">
4+
<name>random_generator</name>
5+
<version>0.0.0</version>
6+
<description>TODO: Package description</description>
7+
<maintainer email="[email protected]">tirine</maintainer>
8+
<license>TODO: License declaration</license>
9+
10+
<buildtool_depend>ament_cmake</buildtool_depend>
11+
<buildtool_depend>rosidl_default_generators</buildtool_depend>
12+
13+
<depend>randomizer_action_interface</depend>
14+
<depend>action_msgs</depend>
15+
<depend>rclcpp</depend>
16+
<depend>rclcpp_action</depend>
17+
<depend>rclcpp_components</depend>
18+
19+
<member_of_group>rosidl_interface_packages</member_of_group>
20+
21+
<test_depend>ament_lint_auto</test_depend>
22+
<test_depend>ament_lint_common</test_depend>
23+
24+
<export>
25+
<build_type>ament_cmake</build_type>
26+
</export>
27+
</package>
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2016 Open Source Robotics Foundation, Inc.
2+
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <functional>
16+
#include <future>
17+
#include <memory>
18+
#include <sstream>
19+
#include <string>
20+
21+
#include "random_generator/action/randomizer.hpp"
22+
23+
#include "rclcpp/rclcpp.hpp"
24+
#include "rclcpp_action/rclcpp_action.hpp"
25+
#include "rclcpp_components/register_node_macro.hpp"
26+
27+
namespace random_generator {
28+
class RandomizerActionClient : public rclcpp::Node {
29+
public:
30+
using Randomizer = action::Randomizer;
31+
using GoalHandleRandomizer = rclcpp_action::ClientGoalHandle<Randomizer>;
32+
33+
explicit RandomizerActionClient(const rclcpp::NodeOptions& options)
34+
: Node("randomizer_action_client", options) {
35+
this->client_ptr_ = rclcpp_action::create_client<Randomizer>(this, "randomizer");
36+
37+
this->timer_ = this->create_wall_timer(std::chrono::milliseconds(500),
38+
std::bind(&RandomizerActionClient::send_goal, this));
39+
}
40+
41+
void send_goal() {
42+
using namespace std::placeholders;
43+
44+
this->timer_->cancel();
45+
46+
if (!this->client_ptr_->wait_for_action_server()) {
47+
RCLCPP_ERROR(this->get_logger(), "Action server not available after waiting");
48+
rclcpp::shutdown();
49+
}
50+
51+
auto goal_msg = Randomizer::Goal();
52+
goal_msg.number_of_values = 10;
53+
goal_msg.min_val = 0.5;
54+
goal_msg.max_val = 9.5;
55+
56+
RCLCPP_INFO(this->get_logger(), "Sending goal");
57+
58+
auto send_goal_options = rclcpp_action::Client<Randomizer>::SendGoalOptions();
59+
send_goal_options.goal_response_callback =
60+
std::bind(&RandomizerActionClient::goal_response_callback, this, _1);
61+
send_goal_options.feedback_callback =
62+
std::bind(&RandomizerActionClient::feedback_callback, this, _1, _2);
63+
send_goal_options.result_callback =
64+
std::bind(&RandomizerActionClient::result_callback, this, _1);
65+
this->client_ptr_->async_send_goal(goal_msg, send_goal_options);
66+
}
67+
68+
private:
69+
rclcpp_action::Client<Randomizer>::SharedPtr client_ptr_;
70+
rclcpp::TimerBase::SharedPtr timer_;
71+
72+
void goal_response_callback(std::shared_future<GoalHandleRandomizer::SharedPtr> future) {
73+
auto goal_handle = future.get();
74+
if (!goal_handle) {
75+
RCLCPP_ERROR(this->get_logger(), "Goal was rejected by server");
76+
} else {
77+
RCLCPP_INFO(this->get_logger(), "Goal accepted by server, waiting for result");
78+
}
79+
}
80+
81+
void feedback_callback(GoalHandleRandomizer::SharedPtr,
82+
const std::shared_ptr<const Randomizer::Feedback> feedback) {
83+
std::stringstream ss;
84+
ss << std::setprecision(6);
85+
ss << "Next random number: " << feedback->new_random_value
86+
<< ". \t Done: " << feedback->number_of_random_values_calculated << " values.";
87+
RCLCPP_INFO(this->get_logger(), ss.str().c_str());
88+
}
89+
90+
void result_callback(const GoalHandleRandomizer::WrappedResult& result_handle) {
91+
switch (result_handle.code) {
92+
case rclcpp_action::ResultCode::SUCCEEDED:
93+
break;
94+
case rclcpp_action::ResultCode::ABORTED:
95+
RCLCPP_ERROR(this->get_logger(), "Goal was aborted");
96+
return;
97+
case rclcpp_action::ResultCode::CANCELED:
98+
RCLCPP_ERROR(this->get_logger(), "Goal was canceled");
99+
return;
100+
default:
101+
RCLCPP_ERROR(this->get_logger(), "Unknown result code");
102+
return;
103+
}
104+
std::stringstream ss;
105+
ss << "Result received: ";
106+
for (auto number : result_handle.result->random_values) {
107+
ss << number << " ";
108+
}
109+
RCLCPP_INFO(this->get_logger(), ss.str().c_str());
110+
rclcpp::shutdown();
111+
}
112+
}; // class RandomizerActionClient
113+
114+
} // namespace random_generator
115+
116+
RCLCPP_COMPONENTS_REGISTER_NODE(random_generator::RandomizerActionClient)

0 commit comments

Comments
 (0)