diff --git a/micro_ros_agent/CMakeLists.txt b/micro_ros_agent/CMakeLists.txt index d0b63c0..da6830a 100644 --- a/micro_ros_agent/CMakeLists.txt +++ b/micro_ros_agent/CMakeLists.txt @@ -14,6 +14,9 @@ cmake_minimum_required(VERSION 3.5) +option(BUILD_SHARED_LIBS "Control shared/static building." ON) +option(UBUILD_AGENT_EXECUTABLE "Control shared/static building." ON) + option(UROSAGENT_GENERATE_PROFILE "Generates agent.refs according to the .msgs provided in the .repos" OFF ) @@ -41,15 +44,26 @@ find_package(ament_cmake_gtest REQUIRED) find_package(micro_ros_msgs REQUIRED) -add_executable(${PROJECT_NAME} - src/main.cpp +include(GNUInstallDirs) +set(BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR} CACHE PATH "Installation directory for binaries") +set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "Installation directory for C headers") +set(LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Installation directory for libraries") +set(DATA_INSTALL_DIR ${CMAKE_INSTALL_DATADIR} CACHE PATH "Installation directory for data") + +# Set source files +set(SRCS src/agent/Agent.cpp src/agent/graph_manager/graph_manager.cpp src/agent/graph_manager/graph_typesupport.cpp src/agent/utils/demangle.cpp ) -target_include_directories(${PROJECT_NAME} +# Library +add_library(${PROJECT_NAME} ${SRCS}) + +target_include_directories(${PROJECT_NAME} BEFORE + PUBLIC + $ PRIVATE include ) @@ -76,16 +90,9 @@ target_link_libraries(${PROJECT_NAME} target_compile_options(${PROJECT_NAME} PRIVATE - $<$:-Wall> - $<$:-Wextra> - $<$:-pedantic> - ) - -set_target_properties(${PROJECT_NAME} PROPERTIES - CXX_STANDARD - 14 - CXX_STANDARD_REQUIRED - YES + $<$,$>:-Wall> + $<$,$>:-Wextra> + $<$,$>:-Wpedantic> ) set_target_properties(${PROJECT_NAME} PROPERTIES @@ -95,31 +102,98 @@ set_target_properties(${PROJECT_NAME} PROPERTIES YES ) -target_compile_options(${PROJECT_NAME} - PRIVATE - $<$,$>:-Wall> - $<$,$>:-Wextra> - $<$,$>:-Wpedantic> - ) - -ament_export_dependencies(microxrcedds_agent) +# Install agent lib +install( + TARGETS + ${PROJECT_NAME} + EXPORT + ${PROJECT_NAME}Targets + RUNTIME DESTINATION + ${BIN_INSTALL_DIR} + LIBRARY DESTINATION + ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION + ${LIB_INSTALL_DIR} + COMPONENT + libraries + ) -ament_package() +# Install includes +install( + DIRECTORY + ${PROJECT_SOURCE_DIR}/include/agent + DESTINATION + ${INCLUDE_INSTALL_DIR} + FILES_MATCHING + PATTERN "*.hpp" + PATTERN "*.h" + ) +# Export library install( - TARGETS - ${PROJECT_NAME} + EXPORT + ${PROJECT_NAME}Targets DESTINATION - lib/${PROJECT_NAME} + ${DATA_INSTALL_DIR}/${PROJECT_NAME}/cmake ) +# Package configuration +include(CMakePackageConfigHelpers) + +configure_package_config_file( + ${PROJECT_SOURCE_DIR}/cmake/Config.cmake.in + ${PROJECT_BINARY_DIR}/cmake/config/${PROJECT_NAME}Config.cmake + INSTALL_DESTINATION + ${DATA_INSTALL_DIR}/${PROJECT_NAME}/cmake + PATH_VARS + BIN_INSTALL_DIR + INCLUDE_INSTALL_DIR + LIB_INSTALL_DIR + DATA_INSTALL_DIR + ) + install( - DIRECTORY - launch + FILES + ${PROJECT_BINARY_DIR}/cmake/config/${PROJECT_NAME}Config.cmake DESTINATION - share/${PROJECT_NAME} + ${DATA_INSTALL_DIR}/${PROJECT_NAME}/cmake ) +if(UBUILD_AGENT_EXECUTABLE) + add_executable(micro_ros_agent_bin + ${SRCS} + src/main.cpp + ) + + target_include_directories(micro_ros_agent_bin + PRIVATE + $ + ) + + target_link_libraries(micro_ros_agent_bin ${PROJECT_NAME}) + + set_target_properties(micro_ros_agent_bin + PROPERTIES OUTPUT_NAME ${PROJECT_NAME}) + + install( + TARGETS + micro_ros_agent_bin + DESTINATION + lib/${PROJECT_NAME} + ) + + install( + DIRECTORY + launch + DESTINATION + share/${PROJECT_NAME} + ) +endif() + +ament_export_dependencies(microxrcedds_agent) + +ament_package() + if(UROSAGENT_GENERATE_PROFILE) set(_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/python") diff --git a/micro_ros_agent/cmake/Config.cmake.in b/micro_ros_agent/cmake/Config.cmake.in new file mode 100644 index 0000000..cecf44e --- /dev/null +++ b/micro_ros_agent/cmake/Config.cmake.in @@ -0,0 +1,32 @@ +# Copyright 2016 Proyectos y Sistemas de Mantenimiento SL (eProsima). +# +# 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. + +set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@) + +@PACKAGE_INIT@ + +if(MSVC OR MSVC_IDE) + set_and_check(@PROJECT_NAME@_BIN_DIR "@PACKAGE_BIN_INSTALL_DIR@") +endif() +set_and_check(@PROJECT_NAME@_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set_and_check(@PROJECT_NAME@_LIB_DIR "@PACKAGE_LIB_INSTALL_DIR@") +set_and_check(@PROJECT_NAME@_DATA_DIR "@PACKAGE_DATA_INSTALL_DIR@") + +foreach(d @_deps@) + list(GET d 0 _name) + list(GET d 1 _version) + find_package(${_name} ${_version} REQUIRED) +endforeach() + +include(${@PROJECT_NAME@_DATA_DIR}/@PROJECT_NAME@/cmake/@PROJECT_NAME@Targets.cmake) diff --git a/micro_ros_agent/include/agent/Agent.hpp b/micro_ros_agent/include/agent/Agent.hpp index f5f22f3..a388bdf 100644 --- a/micro_ros_agent/include/agent/Agent.hpp +++ b/micro_ros_agent/include/agent/Agent.hpp @@ -26,11 +26,26 @@ namespace agent { class Agent { -public: - +private: Agent(); - ~Agent() = default; + ~Agent() + { + stop(); + } + + Agent(const Agent &) = delete; + + Agent(Agent &&) = delete; + + Agent& operator =( + const Agent &) = delete; + + Agent& operator =( + Agent &&) = delete; + +public: + static Agent& getInstance(); bool create( int argc, @@ -38,12 +53,14 @@ class Agent void run(); -private: + void stop(); +private: + bool initialized = false; eprosima::uxr::AgentInstance& xrce_dds_agent_instance_; - std::map> graph_manager_map_; + std::map graph_manager_map_; - std::shared_ptr find_or_create_graph_manager(eprosima::fastdds::dds::DomainId_t domain_id); + graph_manager::GraphManager* find_or_create_graph_manager(eprosima::fastdds::dds::DomainId_t domain_id); }; } // namespace agent diff --git a/micro_ros_agent/include/agent/graph_manager/graph_manager.hpp b/micro_ros_agent/include/agent/graph_manager/graph_manager.hpp index f0d94d2..d72388c 100644 --- a/micro_ros_agent/include/agent/graph_manager/graph_manager.hpp +++ b/micro_ros_agent/include/agent/graph_manager/graph_manager.hpp @@ -82,6 +82,28 @@ class GraphManager */ ~GraphManager() = default; + void stop() + { + if (microros_graph_publisher_.joinable()) + { + exit = true; + cv_.notify_one(); + microros_graph_publisher_.join(); + } + + subscriber_->delete_datareader(ros_discovery_datareader_); + publisher_->delete_datawriter(ros_to_microros_graph_datawriter_); + + participant_->delete_subscriber(subscriber_); + participant_->delete_publisher(publisher_); + + // Delete topics + participant_->delete_topic(ros_discovery_topic_); + participant_->delete_topic(ros_to_microros_graph_topic_); + + eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->delete_participant(participant_); + } + /** * @brief Implementation of the notification logic that updates the micro-ROS graph. */ @@ -274,27 +296,28 @@ class GraphManager std::thread microros_graph_publisher_; std::mutex mtx_; std::condition_variable cv_; + volatile bool exit = false; eprosima::fastdds::dds::DataWriterQos datawriter_qos_; rmw_dds_common::GraphCache graphCache_; - std::unique_ptr participant_listener_; - std::unique_ptr datareader_listener_; - - std::unique_ptr participant_info_typesupport_; - std::unique_ptr microros_graph_info_typesupport_; - std::unique_ptr participant_; - std::unique_ptr publisher_; - std::unique_ptr subscriber_; - std::unique_ptr ros_discovery_topic_; - std::unique_ptr ros_to_microros_graph_topic_; - std::unique_ptr ros_to_microros_graph_datawriter_; - std::unique_ptr ros_discovery_datareader_; + ParticipantListener participant_listener_; + DatareaderListener datareader_listener_; + + eprosima::fastdds::dds::TypeSupport participant_info_typesupport_; + eprosima::fastdds::dds::TypeSupport microros_graph_info_typesupport_; + eprosima::fastdds::dds::DomainParticipant* participant_; + eprosima::fastdds::dds::Publisher* publisher_; + eprosima::fastdds::dds::Subscriber* subscriber_; + eprosima::fastdds::dds::Topic* ros_discovery_topic_; + eprosima::fastdds::dds::Topic* ros_to_microros_graph_topic_; + eprosima::fastdds::dds::DataWriter* ros_to_microros_graph_datawriter_; + eprosima::fastdds::dds::DataReader* ros_discovery_datareader_; // Store a auxiliary publishers and datawriter for each participant created in micro-ROS std::map< const eprosima::fastdds::dds::DomainParticipant*, - std::unique_ptr + eprosima::fastdds::dds::DataWriter* > micro_ros_graph_datawriters_; }; diff --git a/micro_ros_agent/src/agent/Agent.cpp b/micro_ros_agent/src/agent/Agent.cpp index 87ef3cf..6cc87ce 100644 --- a/micro_ros_agent/src/agent/Agent.cpp +++ b/micro_ros_agent/src/agent/Agent.cpp @@ -25,13 +25,22 @@ Agent::Agent() { } +Agent& Agent::getInstance() +{ + static Agent instance; + return instance; +} + bool Agent::create( int argc, char** argv) { bool result = xrce_dds_agent_instance_.create(argc, argv); - if (result) + + if (result && !initialized) { + initialized = true; + /** * Add CREATE_PARTICIPANT callback. */ @@ -173,23 +182,29 @@ bool Agent::create( void Agent::run() { - return xrce_dds_agent_instance_.run(); + xrce_dds_agent_instance_.run(); } -std::shared_ptr Agent::find_or_create_graph_manager(eprosima::fastdds::dds::DomainId_t domain_id) +void Agent::stop() { + xrce_dds_agent_instance_.stop(); -auto it = graph_manager_map_.find(domain_id); + for (auto & element : graph_manager_map_) + { + element.second.stop(); + } + + graph_manager_map_.clear(); +} + +graph_manager::GraphManager* Agent::find_or_create_graph_manager(eprosima::fastdds::dds::DomainId_t domain_id) +{ + auto it = graph_manager_map_.find(domain_id); if (it != graph_manager_map_.end()) { - return it->second; + return &it->second; }else{ - return graph_manager_map_.insert( - std::make_pair( - domain_id, - std::make_shared(domain_id) - ) - ).first->second; + return &graph_manager_map_.emplace(domain_id, domain_id).first->second; } } diff --git a/micro_ros_agent/src/agent/graph_manager/graph_manager.cpp b/micro_ros_agent/src/agent/graph_manager/graph_manager.cpp index 9badffc..c1eac93 100644 --- a/micro_ros_agent/src/agent/graph_manager/graph_manager.cpp +++ b/micro_ros_agent/src/agent/graph_manager/graph_manager.cpp @@ -28,15 +28,16 @@ GraphManager::GraphManager(eprosima::fastdds::dds::DomainId_t domain_id) , mtx_() , cv_() , graphCache_() - , participant_listener_(std::make_unique(this)) - , datareader_listener_(std::make_unique(this)) - , participant_info_typesupport_(std::make_unique< - eprosima::fastdds::dds::TypeSupport>(new graph_manager::ParticipantEntitiesInfoTypeSupport())) - , microros_graph_info_typesupport_(std::make_unique< - eprosima::fastdds::dds::TypeSupport>(new graph_manager::MicrorosGraphInfoTypeSupport())) + , participant_listener_(this) + , datareader_listener_(this) + , participant_info_typesupport_() + , microros_graph_info_typesupport_() { eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->load_profiles(); + participant_info_typesupport_ = (eprosima::fastdds::dds::TypeSupport) new graph_manager::ParticipantEntitiesInfoTypeSupport(); + microros_graph_info_typesupport_ = (eprosima::fastdds::dds::TypeSupport) new graph_manager::MicrorosGraphInfoTypeSupport(); + // Create DomainParticipant eprosima::fastdds::dds::DomainParticipantQos participant_qos = eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->get_default_participant_qos(); @@ -54,29 +55,30 @@ GraphManager::GraphManager(eprosima::fastdds::dds::DomainId_t domain_id) eprosima::fastrtps::rtps::PREALLOCATED_WITH_REALLOC_MEMORY_MODE; eprosima::fastdds::dds::StatusMask par_mask = eprosima::fastdds::dds::StatusMask::none(); - participant_.reset(eprosima::fastdds::dds::DomainParticipantFactory::get_instance()-> - create_participant(domain_id_, participant_qos, participant_listener_.get(), par_mask)); + + participant_ = eprosima::fastdds::dds::DomainParticipantFactory::get_instance()-> + create_participant(domain_id_, participant_qos, &participant_listener_, par_mask); // Register participant within typesupport - participant_->register_type(*participant_info_typesupport_); - participant_->register_type(*microros_graph_info_typesupport_); + participant_->register_type(participant_info_typesupport_); + participant_->register_type(microros_graph_info_typesupport_); // Create publisher - publisher_.reset(participant_->create_publisher( - eprosima::fastdds::dds::PUBLISHER_QOS_DEFAULT)); + publisher_ = participant_->create_publisher( + eprosima::fastdds::dds::PUBLISHER_QOS_DEFAULT); // Create subscriber - subscriber_.reset(participant_->create_subscriber( - eprosima::fastdds::dds::SUBSCRIBER_QOS_DEFAULT)); + subscriber_ = participant_->create_subscriber( + eprosima::fastdds::dds::SUBSCRIBER_QOS_DEFAULT); // Create topics - ros_discovery_topic_.reset(participant_->create_topic("ros_discovery_info", - participant_info_typesupport_->get_type_name(), - eprosima::fastdds::dds::TOPIC_QOS_DEFAULT)); + ros_discovery_topic_ = participant_->create_topic("ros_discovery_info", + participant_info_typesupport_.get_type_name(), + eprosima::fastdds::dds::TOPIC_QOS_DEFAULT); - ros_to_microros_graph_topic_.reset(participant_->create_topic("ros_to_microros_graph", - microros_graph_info_typesupport_->get_type_name(), - eprosima::fastdds::dds::TOPIC_QOS_DEFAULT)); + ros_to_microros_graph_topic_ = participant_->create_topic("ros_to_microros_graph", + microros_graph_info_typesupport_.get_type_name(), + eprosima::fastdds::dds::TOPIC_QOS_DEFAULT); // Create datawriters datawriter_qos_ = @@ -97,8 +99,9 @@ GraphManager::GraphManager(eprosima::fastdds::dds::DomainId_t domain_id) eprosima::fastdds::dds::DataWriterQos ros_to_microros_datawriter_qos_ = datawriter_qos_; ros_to_microros_datawriter_qos_.history().kind = eprosima::fastdds::dds::HistoryQosPolicyKind::KEEP_ALL_HISTORY_QOS; - ros_to_microros_graph_datawriter_.reset( - publisher_->create_datawriter(ros_to_microros_graph_topic_.get(), ros_to_microros_datawriter_qos_)); + + ros_to_microros_graph_datawriter_ = + publisher_->create_datawriter(ros_to_microros_graph_topic_, ros_to_microros_datawriter_qos_); // Create datareaders @@ -114,9 +117,9 @@ GraphManager::GraphManager(eprosima::fastdds::dds::DomainId_t domain_id) datareader_qos.durability().kind = eprosima::fastdds::dds::DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS; - ros_discovery_datareader_.reset( - subscriber_->create_datareader(ros_discovery_topic_.get(), - datareader_qos, datareader_listener_.get())); + ros_discovery_datareader_ = + subscriber_->create_datareader(ros_discovery_topic_, + datareader_qos, &datareader_listener_); // Set graph cache on change callback function graphCache_.set_on_change_callback([this]() @@ -137,10 +140,15 @@ inline void GraphManager::publish_microros_graph() std::unique_lock lock(mtx_); cv_.wait(lock, [this]() { - return this->graph_changed_; + return this->graph_changed_ || exit; }); } + if (exit) + { + break; + } + if (display_on_change_) { std::cout << "Updated uros Graph: graph changed" << std::endl; @@ -315,8 +323,8 @@ void GraphManager::add_participant( if (it == micro_ros_graph_datawriters_.end()) { // Create datawriter - std::unique_ptr datawriter; - datawriter.reset(publisher_->create_datawriter(ros_discovery_topic_.get(), datawriter_qos_)); + eprosima::fastdds::dds::DataWriter* datawriter; + datawriter = publisher_->create_datawriter(ros_discovery_topic_, datawriter_qos_); it = micro_ros_graph_datawriters_.insert( std::make_pair(participant, std::move(datawriter))).first; @@ -339,8 +347,10 @@ void GraphManager::remove_participant( rmw_dds_common::convert_gid_to_msg(&gid, &info.gid); auto it = micro_ros_graph_datawriters_.find(participant); it->second->write(static_cast(&info)); + + publisher_->delete_datawriter(it->second); + micro_ros_graph_datawriters_.erase(participant); } - micro_ros_graph_datawriters_.erase(participant); } void GraphManager::add_datawriter( diff --git a/micro_ros_agent/src/main.cpp b/micro_ros_agent/src/main.cpp index d5b29bf..0c4937c 100644 --- a/micro_ros_agent/src/main.cpp +++ b/micro_ros_agent/src/main.cpp @@ -16,7 +16,7 @@ int main(int argc, char** argv) { - uros::agent::Agent micro_ros_agent; + uros::agent::Agent& micro_ros_agent = micro_ros_agent.getInstance(); /** Bypass '--ros-args' flag, as we use our own CLI parser. * As a workaround for launch files, arguments will be passed from