diff --git a/gst/CMakeLists.txt b/gst/CMakeLists.txt index 1e5760f..0ded7ea 100644 --- a/gst/CMakeLists.txt +++ b/gst/CMakeLists.txt @@ -1,4 +1,4 @@ +ADD_SUBDIRECTORY(tensor_ros_sink) IF(WITH_ROS1) - ADD_SUBDIRECTORY(tensor_ros_sink) ADD_SUBDIRECTORY(tensor_ros_src) ENDIF(WITH_ROS1) diff --git a/gst/tensor_ros_sink/CMakeLists.txt b/gst/tensor_ros_sink/CMakeLists.txt index d1ce9da..49acee1 100644 --- a/gst/tensor_ros_sink/CMakeLists.txt +++ b/gst/tensor_ros_sink/CMakeLists.txt @@ -4,14 +4,14 @@ SET(PKG_MODULES PKG_CHECK_MODULES(PKGS REQUIRED ${PKG_MODULES}) -ADD_LIBRARY(tensor_ros_sink tensor_ros_sink.c) -ADD_DEPENDENCIES(tensor_ros_sink nns_ros_bridge) +ADD_LIBRARY(tensor_ros_sink SHARED tensor_ros_sink.c) +ADD_DEPENDENCIES(tensor_ros_sink nns_ros_bridge2) TARGET_INCLUDE_DIRECTORIES(tensor_ros_sink PRIVATE ${PKGS_INCLUDE_DIRS} ) TARGET_LINK_LIBRARIES(tensor_ros_sink - nns_ros_bridge + nns_ros_bridge2 ${PKGS_COMMON_LIBRARIES} ${PKGS_LIBRARIES} ) diff --git a/ros2/CMakeLists.txt b/ros2/CMakeLists.txt index cf8d03b..6693d54 100644 --- a/ros2/CMakeLists.txt +++ b/ros2/CMakeLists.txt @@ -40,19 +40,24 @@ FIND_PACKAGE(std_msgs REQUIRED) FIND_PACKAGE(rosidl_default_generators REQUIRED) -ROSIDL_GENERATE_INTERFACES( - ${PROJECT_NAME} - "${NNS_ROS_COMMON_DIR}/msg:Tensors.msg" +SET(NNS_ROS2_LIB_MSGS "${NNS_ROS_COMMON_DIR}/msg:Tensors.msg") +SET(NNS_ROS2_LIB_SRCS + node/nns_rclcpp_publisher.cc ) +SET(NNS_ROS2_LIB_TARGET nns_ros_bridge2) -ADD_EXECUTABLE(publisher_member_function node/member_function.cpp) -AMENT_TARGET_DEPENDENCIES(publisher_member_function rclcpp std_msgs) +ROSIDL_GENERATE_INTERFACES(${PROJECT_NAME} + ${NNS_ROS2_LIB_MSGS} + DEPENDENCIES builtin_interfaces std_msgs +) -INSTALL(TARGETS - publisher_member_function - RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} - ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} +ADD_LIBRARY(${NNS_ROS2_LIB_TARGET} SHARED + ${NNS_ROS2_LIB_SRCS} +) +AMENT_TARGET_DEPENDENCIES(${NNS_ROS2_LIB_TARGET} rclcpp std_msgs) +AMENT_EXPORT_DEPENDENCIES(rosidl_default_runtime) +ROSIDL_TARGET_INTERFACES(${NNS_ROS2_LIB_TARGET} + ${PROJECT_NAME} "rosidl_typesupport_cpp" ) IF(BUILD_TESTING) @@ -67,3 +72,8 @@ IF(BUILD_TESTING) ENDIF() AMENT_PACKAGE() +INSTALL(TARGETS ${NNS_ROS2_LIB_TARGET} + RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} +) diff --git a/ros2/node/member_function.cpp b/ros2/node/member_function.cpp deleted file mode 100644 index c8d2ebf..0000000 --- a/ros2/node/member_function.cpp +++ /dev/null @@ -1,56 +0,0 @@ -// 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 -#include - -#include "rclcpp/rclcpp.hpp" -#include "std_msgs/msg/string.hpp" - -using namespace std::chrono_literals; - -/* This example creates a subclass of Node and uses std::bind() to register a - * member function as a callback from the timer. */ - -class MinimalPublisher : public rclcpp::Node -{ -public: - MinimalPublisher() - : Node("minimal_publisher"), count_(0) - { - publisher_ = this->create_publisher("topic", 10); - timer_ = this->create_wall_timer( - 500ms, std::bind(&MinimalPublisher::timer_callback, this)); - } - -private: - void timer_callback() - { - auto message = std_msgs::msg::String(); - message.data = "Hello, world! " + std::to_string(count_++); - RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str()); - publisher_->publish(message); - } - rclcpp::TimerBase::SharedPtr timer_; - rclcpp::Publisher::SharedPtr publisher_; - size_t count_; -}; - -int main(int argc, char * argv[]) -{ - rclcpp::init(argc, argv); - rclcpp::spin(std::make_shared()); - rclcpp::shutdown(); - return 0; -} diff --git a/ros2/node/nns_rclcpp_publisher.cc b/ros2/node/nns_rclcpp_publisher.cc new file mode 100644 index 0000000..0f14fea --- /dev/null +++ b/ros2/node/nns_rclcpp_publisher.cc @@ -0,0 +1,162 @@ +/* SPDX-License-Identifier: LGPL-2.1-only */ +/** + * NNStreamer-ROS: NNStreamer extension packages for ROS/ROS2 support + * Copyright (C) 2020 Wook Song + * Copyright (C) 2018 Samsung Electronics Co., Ltd. + * + * @file nns_rclcpp_publisher.cc + * @date 10/20/2020 + * @brief A helper class for publishing ROS2 (i.e., rclcpp) topic + * via NNStreamer plugins + * @see https://github.com/nnstreamer/nnstreamer-ros + * @author Wook Song + * @bug No known bugs except for NYI items + * + * This class bridges between the NNStreamer (C) and ROS2 frameworks (ROSCPP/C++) + * by implementing the NnsRosPublisher class. + * + */ + +#include +#include + +#include +#include + +#include "rclcpp/rclcpp.hpp" +#include "nns_ros_publisher.h" +#include "nns_ros2_bridge/msg/tensors.hpp" + + +class NnsRclCppPublisher + : public NnsRosPublisher +{ +public: + NnsRclCppPublisher (const char *node_name, const char *topic_name, + gboolean is_dummy); + ~NnsRclCppPublisher (); + + gboolean publish (const guint num_tensors, + const GstTensorMemory *tensors_mem, void *bag) final; + +private: + static const std::string node_namespace_; + rclcpp::Node::SharedPtr node_; + rclcpp::Publisher::SharedPtr publisher_; +}; + +const std::string NnsRclCppPublisher::node_namespace_ = "tensor_ros2_sink"; + +NnsRclCppPublisher::NnsRclCppPublisher (const char *node_name, + const char *topic_name, gboolean is_dummy) + : NnsRosPublisher (node_name, + topic_name, is_dummy) +{ + /* RCLCPP initialization requires command-line arguments */ + int dummy_argc = 0; + char **dummy_argv = NULL; + + rclcpp::init (dummy_argc, dummy_argv); + + this->node_ = rclcpp::Node::make_shared (node_name, + NnsRclCppPublisher::node_namespace_); + this->publisher_ = + this->node_->create_publisher ( + topic_name, default_q_size); +} + +NnsRclCppPublisher::~NnsRclCppPublisher () +{ +} + +/** + * @brief A method for publishing a ROS topic that contains the tensors passed by the NNStreamer framework + * @param[in] num_tensors : The number of tensors included in tensors_mem (for the verification purpose) + * @param[in] tensors_mem : The pointer of containers consists of information and raw data of tensors + * @return TRUE if the configuration is successfully done + */ +gboolean NnsRclCppPublisher::publish (const guint num_tensors, + const GstTensorMemory *tensors_mem, void *bag __attribute__((unused))) +{ + nns_ros2_bridge::msg::Tensors tensors_msg; + + g_return_val_if_fail (this->ready_to_pub, FALSE); + g_return_val_if_fail (num_tensors == this->num_of_tensors_pub, FALSE); + + for (guint i = 0; i < this->num_of_tensors_pub; ++i) { + std_msgs::msg::UInt8MultiArray each_tensor; + uint8_t *src_data = (uint8_t *) tensors_mem[i].data; + + each_tensor.layout = this->topic_layouts_pub[i]; + each_tensor.data.assign (src_data, src_data + tensors_mem[i].size); + + tensors_msg.tensors.push_back (each_tensor); + } + + if (!this->is_dummy) { + g_return_val_if_fail (rclcpp::ok(), FALSE); + this->publisher_->publish (tensors_msg); + rclcpp::spin_some(this->node_); + } + + return TRUE; +} + +/** + * C functions for NNStreamer plugins that want to publish or subscribe + * ROS topics. nns_ros_publisher_init() should be invoked before configuring the + * tensors information to publish or subscribe. Each NNStreamer plugin which + * uses this class should be holding the instance of NnsRclCppPublisher (i.e., the + * void type pointer what the nns_ros_publisher_init() function returns). + */ +void * +nns_ros_publisher_init (const char *node_name, const char *topic_name, + gboolean is_dummy) +{ + return new NnsRclCppPublisher (node_name, topic_name, is_dummy); +} + +void +nns_ros_publisher_finalize (void *instance) +{ + NnsRclCppPublisher *nrp_instance = (NnsRclCppPublisher *) instance; + if (nrp_instance != nullptr) + delete nrp_instance; +} + +gboolean +nns_ros_publisher_publish (void *instance, const guint num_tensors, + const GstTensorMemory *tensors_mem, void *bag) +{ + NnsRclCppPublisher *nrp_instance = (NnsRclCppPublisher *) instance; + + return nrp_instance->publish (num_tensors, tensors_mem, bag); +} + +gboolean +nns_ros_publisher_set_pub_topic (void *instance, const GstTensorsConfig *conf) +{ + NnsRclCppPublisher *nrp_instance = (NnsRclCppPublisher *) instance; + + return nrp_instance->setPubTopicInfo (conf); +} + +const gchar * +nns_ros_publisher_get_pub_topic_name (void *instance) +{ + NnsRclCppPublisher *nrp_instance = (NnsRclCppPublisher *) instance; + + return nrp_instance->getPubTopicName(); +} + +void * +nns_ros_publisher_open_writable_bag (void * instance __attribute__((unused)), const char *name __attribute__((unused))) +{ + return nullptr; +} + +void +nns_ros_publisher_close_bag (void *bag __attribute__((unused))) +{ + ; +} diff --git a/ros2/package.xml b/ros2/package.xml index e75ac49..0e4fba9 100644 --- a/ros2/package.xml +++ b/ros2/package.xml @@ -11,7 +11,6 @@ ament_cmake rclcpp std_msgs - rosidl_default_generators rclcpp