Compare commits

...
19 Commits
Author SHA1 Message Date
Antonio cuadros 8a1b0e54da Add stop agent 2021-07-21 13:05:38 +02:00
Antonio cuadros e64e17aa25 Update callbacks on AgentAPI 2021-07-16 13:55:07 +02:00
Antonio cuadros 39d8ed0ba2 Add exit to graph manager thread 2021-07-16 13:54:46 +02:00
Antonio cuadros 37566d1c74 Add set vetbosity 2021-07-14 14:19:46 +02:00
Antonio cuadros 015343c4c8 Initial agent API 2021-07-14 14:11:13 +02:00
mergify[bot]andPablo Garrido 7f3f560bc7 Fix graph manager datawriters behaviour (#84) (#86)
* Fix graph manager datawriters

Fixes

Fix

Fix destruction

* Revert "Fix graph manager datawriters"

This reverts commit 2847a2ebc3.

* Initial

(cherry picked from commit 646ca52aab)

Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
2021-07-09 13:41:52 +02:00
mergify[bot]andPablo Garrido 80916d4949 Graph manager: Fix participant mask for listener callbacks (#81) (#83)
(cherry picked from commit 95fecd77ae)

Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
2021-07-08 15:33:20 +02:00
mergify[bot]andPablo Garrido d1e851ba4e Fix agent launch (#78) (#79)
Co-authored-by: Your Name <you@example.com>
(cherry picked from commit 69f17c28a8)

Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
2021-07-05 10:56:24 +02:00
mergify[bot]andPablo Garrido 6047f7135d Fix graph manager node namespaces (#75) (#76)
* Fix graph manager node namespaces

* Update

(cherry picked from commit f6a2aa3b60)

Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
2021-07-02 13:42:03 +02:00
mergify[bot]andPablo Garrido 9d3fbc63a0 Fix graph manager node namespaces (backport #72) (#73)
* Fix graph manager node namespaces (#72)

(cherry picked from commit a623308505)

# Conflicts:
#	micro_ros_agent/src/agent/graph_manager/graph_manager.cpp

* Update graph_manager.cpp

Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
2021-07-02 09:51:40 +02:00
Pablo GarridoandAntonio Cuadros a3fe4aa376 Add multi domain graph manager (#69)
* Add multi domain graph manager

* Update

* Fix

* Fix

* Update micro_ros_agent/include/agent/graph_manager/graph_manager.hpp

Co-authored-by: Antonio Cuadros <49162117+Acuadros95@users.noreply.github.com>

Co-authored-by: Antonio Cuadros <49162117+Acuadros95@users.noreply.github.com>
2021-06-21 16:15:07 +02:00
Pablo Garrido 003cb38ef2 Fix CI (#60) 2021-04-23 11:14:10 +02:00
Jose Antonio Moral 99b3d98430 Update snapcraft.yaml and install instructions (#58) 2021-03-31 13:01:35 +02:00
Jose Antonio Moral 0220dd6feb Delete outdated XRCE agent CLI flag (#53) 2021-03-02 14:29:22 +01:00
Pablo Garrido fc57709ead Add issue template 2021-01-25 15:29:37 +01:00
Silvio Traversaro 0009366a62 Fix README link to micro-ros website (#48) 2020-12-23 12:20:44 +01:00
Jose Antonio Moral df9202ea8c Add ros2 launch capabilities and example launch file (#47) 2020-12-14 08:30:18 +01:00
Jose Antonio Moral 837d8718bf Add steps for estalishing a serial connection (#45) 2020-12-14 07:39:41 +01:00
Jose Antonio Moral 4df06bcfaa Snap build for the micro-ROS-Agent (#43)
* Add snap packaging

* First approach for snap packaging

* Working state

* Fixes

* Simplify snapcraft.yaml

* Fix snapcraft build

* Fix daemon

* Fix compilation due to external micro_ros_msgs

* CMakeLists cleanup
2020-12-03 15:38:33 +01:00
16 changed files with 757 additions and 89 deletions
+24
View File
@@ -0,0 +1,24 @@
---
name: General issue
about: General issue template for micro-ROS
title: ''
labels: ''
assignees: ''
---
## Issue template
- Hardware description: <!-- hardware where you are using micro-ROS -->
- RTOS: <!-- RTOS where you are using micro-ROS -->
- Installation type: <!-- micro_ros_setup, modules, etc -->
- Version or commit hash: <!-- version of micro-ROS used: foxy, rolling -->
#### Steps to reproduce the issue
<!-- Detailed instructions on how to reliably reproduce this issue http://sscce.org/-->
#### Expected behavior
#### Actual behavior
#### Additional information
+12 -6
View File
@@ -12,21 +12,27 @@ jobs:
container: microros/base:foxy
steps:
- uses: actions/checkout@v2
with:
path: urosagent
- name: Download dependencies
run: |
apt update
cd /uros_ws
. /opt/ros/foxy/setup.sh
. /opt/ros/$ROS_DISTRO/setup.sh
. install/local_setup.sh
rosdep update
ros2 run micro_ros_setup create_agent_ws.sh
- uses: actions/checkout@v2
with:
path: src/uros/micro-ROS-Agent
- name: Patch branch
run: |
rm -rf /uros_ws/src/uros/micro-ROS-Agent/*
cp -R urosagent/* /uros_ws/src/uros/micro-ROS-Agent/
- name: Build
run: |
cd /uros_ws
. /opt/ros/foxy/setup.sh
. /opt/ros/$ROS_DISTRO/setup.sh
. install/local_setup.sh
ros2 run micro_ros_setup build_agent.sh
+1 -1
View File
@@ -11,7 +11,7 @@ This repository contains the Micro-ROS Agent package.
Micro-ROS Agent is a ROS 2 node that wraps the Micro XRCE-DDS Agent.
For further information about Micro XRCE-DDS Agent click [here](https://github.com/eProsima/Micro-XRCE-DDS-Agent)
This package is a part of the Micro-ROS project stack.
For more information about Micro-ROS project click [here](https://microros.github.io/micro-ROS/).
For more information about Micro-ROS project click [here](https://micro-ros.github.io/).
The node acts as a server between DDS Network and Micro-ROS nodes inside MCU.
It receives and send messages from Micro-ROS nodes, and keep track of the Micro-ROS nodes exposing them to the ROS 2 network.
+11 -4
View File
@@ -113,6 +113,13 @@ install(
lib/${PROJECT_NAME}
)
install(
DIRECTORY
launch
DESTINATION
share/${PROJECT_NAME}
)
if(UROSAGENT_GENERATE_PROFILE)
set(_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/python")
@@ -122,7 +129,7 @@ if(UROSAGENT_GENERATE_PROFILE)
set(_XML_DEFAULT_READ_BIN "${_OUTPUT_PATH}/bin/Xml_read_default_profiles.py")
normalize_path(_XML_DEFAULT_READ_BIN "${_XML_DEFAULT_READ_BIN}")
set(_PYTHON_PKG_TOOL ${PROJECT_NAME})
set(_PYTHON_PKG_TOOL utils)
set(_RESOURCE_DIR "${_OUTPUT_PATH}/resource")
normalize_path(_RESOURCE_DIR "${_RESOURCE_DIR}")
@@ -198,7 +205,7 @@ from ${_PYTHON_PKG_TOOL} import *
endforeach()
execute_process(
COMMAND
COMMAND
"${PYTHON_EXECUTABLE}" "${_XML_DEFAULT_READ_BIN}" "--default-xml-path" "${_RESOURCE_DIR}"
OUTPUT_VARIABLE
_XmlDoc
@@ -207,7 +214,7 @@ from ${_PYTHON_PKG_TOOL} import *
)
if(NOT _result EQUAL 0)
message(FATAL_ERROR "Error in typesuppor generation")
message(FATAL_ERROR "Error in typesupport generation")
endif()
foreach(package ${_packages})
@@ -241,7 +248,7 @@ from ${_PYTHON_PKG_TOOL} import *
)
if(NOT _result EQUAL 0)
message(FATAL_ERROR "Error in typesuppor generation")
message(FATAL_ERROR "Error in typesupport generation")
endif()
set(_XmlDoc "${_XmlDoc}${_XmlGen}")
+32
View File
@@ -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)
+87 -2
View File
@@ -32,18 +32,103 @@ public:
~Agent() = default;
/**
* @brief Agent class shall not be copy constructible.
*/
UXR_AGENT_EXPORT Agent(
const Agent &) = delete;
UXR_AGENT_EXPORT Agent(
Agent &&) = delete;
/**
* @brief Agent class shall not be copy assignable.
*/
UXR_AGENT_EXPORT Agent& operator =(
const Agent &) = delete;
UXR_AGENT_EXPORT Agent& operator =(
Agent &&) = delete;
static Agent& getInstance()
{
static Agent instance;
return instance;
}
bool create(
int argc,
char** argv);
void run();
private:
void stop();
void add_callbacks();
private:
eprosima::uxr::AgentInstance& xrce_dds_agent_instance_;
std::unique_ptr<graph_manager::GraphManager> graph_manager_;
std::map<eprosima::fastdds::dds::DomainId_t, std::shared_ptr<graph_manager::GraphManager>> graph_manager_map_;
std::shared_ptr<graph_manager::GraphManager> find_or_create_graph_manager(eprosima::fastdds::dds::DomainId_t domain_id);
bool started = false;
};
template<typename AgentType>
class AgentAPI
{
public:
AgentAPI()
: agent_instance_(agent_instance_.getInstance())
{};
~AgentAPI() = default;
void create(uint16_t port)
{
xrce_dds_agent_instance_API.configure(port);
}
void create(std::string dev, const std::string baudrate);
void create(std::vector<std::string> devs, const std::string baudrate);
void create(const std::string baudrate);
void set_verbose_level(uint8_t verbose_level)
{
xrce_dds_agent_instance_API.set_verbose_level(verbose_level);
}
void run()
{
agent_instance_.add_callbacks();
xrce_dds_agent_instance_API.run();
}
void stop()
{
xrce_dds_agent_instance_API.stop();
}
private:
Agent& agent_instance_;
eprosima::uxr::AgentInstanceAPI<AgentType> xrce_dds_agent_instance_API;
};
template<> inline UXR_AGENT_EXPORT void AgentAPI<eprosima::uxr::TermiosAgent>::create(std::string dev, const std::string baudrate)
{
xrce_dds_agent_instance_API.configure(dev, baudrate);
}
template<> inline UXR_AGENT_EXPORT void AgentAPI<eprosima::uxr::MultiTermiosAgent>::create(std::vector<std::string> devs, const std::string baudrate)
{
xrce_dds_agent_instance_API.configure(devs, baudrate);
}
template<> inline UXR_AGENT_EXPORT void AgentAPI<eprosima::uxr::PseudoTerminalAgent>::create(const std::string baudrate)
{
xrce_dds_agent_instance_API.configure(baudrate);
}
} // namespace agent
} // namespace uros
#endif // _UROS_AGENT_AGENT_HPP
@@ -75,12 +75,21 @@ public:
/**
* @brief Default constructor.
*/
GraphManager();
GraphManager(eprosima::fastdds::dds::DomainId_t domain_id);
/**
* @brief Default destructor.
*/
~GraphManager() = default;
~GraphManager()
{
exit = true;
cv_.notify_one();
if (microros_graph_publisher_.joinable())
{
microros_graph_publisher_.join();
}
}
/**
* @brief Implementation of the notification logic that updates the micro-ROS graph.
@@ -89,28 +98,22 @@ public:
/**
* @brief Adds a DDS participant to the graph tree.
* @param participant Pointer to the participant to be added to the graph.
*/
void add_participant(
const eprosima::fastdds::dds::DomainParticipant* participant);
/**
* @brief Adds a DDS participant to the graph tree.
* @param guid rtps::GUID_t of the participant to be added.
* @param node_name Name of the ROS 2 node associated to the given participant.
* @param participant eprosima::fastdds::dds::DomainParticipant to be added.
* @param from_microros if this participant has been added from micro-ROS.
* @param enclave ROS 2 enclave.
*/
void add_participant(
const eprosima::fastrtps::rtps::GUID_t& guid,
const std::string& node_name,
const std::string& enclave);
const eprosima::fastdds::dds::DomainParticipant* participant,
bool from_microros = true,
const std::string& enclave = "/");
/**
* @brief Removes a DDS participant from the graph tree.
* @param guid rtps::GUID_t of the participant to be removed.
* @param participant eprosima::fastdds::dds::DomainParticipant to be removed.
*/
void remove_participant(
const eprosima::fastrtps::rtps::GUID_t& guid);
const eprosima::fastdds::dds::DomainParticipant* participant,
bool from_microros = true);
/**
* @brief Adds a DDS datawriter to the graph tree.
@@ -292,13 +295,28 @@ private:
*/
void update_node_entities_info();
/**
* @brief Retrieves node name and namespace from
* participant.
* @param participant_name DDS participant name.
* @param node_name ROS2 Node name.
* @param namespace ROS2 Node namespace.
*/
void get_name_and_namespace(
std::string participant_name,
std::string& node_name,
std::string& node_namespace);
bool exit = false;
eprosima::fastdds::dds::DomainId_t domain_id_;
bool graph_changed_;
bool display_on_change_;
const char * enclave_;
std::thread microros_graph_publisher_;
std::mutex mtx_;
std::condition_variable cv_;
eprosima::fastdds::dds::DataWriterQos datawriter_qos_;
rmw_dds_common::GraphCache graphCache_;
std::unique_ptr<ParticipantListener> participant_listener_;
std::unique_ptr<DatareaderListener> datareader_listener_;
@@ -310,13 +328,18 @@ private:
std::unique_ptr<eprosima::fastdds::dds::Subscriber> subscriber_;
std::unique_ptr<eprosima::fastdds::dds::Topic> ros_discovery_topic_;
std::unique_ptr<eprosima::fastdds::dds::Topic> ros_to_microros_graph_topic_;
std::unique_ptr<eprosima::fastdds::dds::DataWriter> ros_discovery_datawriter_;
std::unique_ptr<eprosima::fastdds::dds::DataWriter> ros_to_microros_graph_datawriter_;
std::unique_ptr<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_;
};
} // namespace graph_manager
} // namespace agent
} // namespace uros
#endif // _UROS_AGENT_GRAPH_MANAGER_HPP
#endif // _UROS_AGENT_GRAPH_MANAGER_HPP
@@ -0,0 +1,12 @@
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='micro_ros_agent',
executable='micro_ros_agent',
name='micro_ros_agent',
arguments={"udp4", "-p", "8888", "-v6"}
)
])
+43 -10
View File
@@ -22,7 +22,6 @@ namespace agent {
Agent::Agent()
: xrce_dds_agent_instance_(xrce_dds_agent_instance_.getInstance())
, graph_manager_(nullptr)
{
}
@@ -30,11 +29,13 @@ bool Agent::create(
int argc,
char** argv)
{
bool result = xrce_dds_agent_instance_.create(argc, argv);
if (result)
{
graph_manager_.reset(new graph_manager::GraphManager());
return xrce_dds_agent_instance_.create(argc, argv);
}
void Agent::add_callbacks()
{
if (!started)
{
/**
* Add CREATE_PARTICIPANT callback.
*/
@@ -43,6 +44,7 @@ bool Agent::create(
([&](
const eprosima::fastdds::dds::DomainParticipant* participant) -> void
{
auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
graph_manager_->add_participant(participant);
});
xrce_dds_agent_instance_.add_middleware_callback(
@@ -58,7 +60,8 @@ bool Agent::create(
([&](
const eprosima::fastdds::dds::DomainParticipant* participant) -> void
{
graph_manager_->remove_participant(participant->guid());
auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
graph_manager_->remove_participant(participant);
});
xrce_dds_agent_instance_.add_middleware_callback(
eprosima::uxr::Middleware::Kind::FASTDDS,
@@ -75,6 +78,8 @@ bool Agent::create(
const eprosima::fastdds::dds::DomainParticipant* participant,
const eprosima::fastdds::dds::DataWriter* datawriter) -> void
{
auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
// TODO(jamoralp): Workaround for Fast-DDS bug #9977. Remove when fixed
const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
datawriter->get_instance_handle();
@@ -96,9 +101,11 @@ bool Agent::create(
const eprosima::fastdds::dds::DomainParticipant *,
const eprosima::fastdds::dds::DataWriter *)> on_delete_datawriter
([&](
const eprosima::fastdds::dds::DomainParticipant* /*participant*/,
const eprosima::fastdds::dds::DomainParticipant* participant,
const eprosima::fastdds::dds::DataWriter* datawriter) -> void
{
auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
// TODO(jamoralp): Workaround for Fast-DDS bug #9977. Remove when fixed
const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
datawriter->get_instance_handle();
@@ -122,6 +129,8 @@ bool Agent::create(
const eprosima::fastdds::dds::DomainParticipant* participant,
const eprosima::fastdds::dds::DataReader* datareader) -> void
{
auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
// TODO(jamoralp): Workaround for Fast-DDS bug #9977. Remove when fixed
const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
datareader->get_instance_handle();
@@ -143,9 +152,11 @@ bool Agent::create(
const eprosima::fastdds::dds::DomainParticipant *,
const eprosima::fastdds::dds::DataReader *)> on_delete_datareader
([&](
const eprosima::fastdds::dds::DomainParticipant* /*participant*/,
const eprosima::fastdds::dds::DomainParticipant* participant,
const eprosima::fastdds::dds::DataReader* datareader) -> void
{
auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
// TODO(jamoralp): Workaround for Fast-DDS bug #9977. Remove when fixed
const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
datareader->get_instance_handle();
@@ -158,9 +169,9 @@ bool Agent::create(
eprosima::uxr::Middleware::Kind::FASTDDS,
eprosima::uxr::middleware::CallbackKind::DELETE_DATAREADER,
std::move(on_delete_datareader));
}
return result;
started = true;
}
}
void Agent::run()
@@ -168,6 +179,28 @@ void Agent::run()
return xrce_dds_agent_instance_.run();
}
void Agent::stop()
{
return xrce_dds_agent_instance_.stop();
}
std::shared_ptr<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;
}else{
return graph_manager_map_.insert(
std::make_pair(
domain_id,
std::make_shared<graph_manager::GraphManager>(domain_id)
)
).first->second;
}
}
} // namespace agent
} // namespace uros
#endif // _UROS_AGENT_AGENT_CPP
@@ -21,11 +21,10 @@ namespace uros {
namespace agent {
namespace graph_manager {
GraphManager::GraphManager()
// : eprosima::fastrtps::ParticipantListener()
: graph_changed_(false)
GraphManager::GraphManager(eprosima::fastdds::dds::DomainId_t domain_id)
: domain_id_(domain_id)
, graph_changed_(false)
, display_on_change_(false)
, enclave_("/")
, mtx_()
, cv_()
, graphCache_()
@@ -36,25 +35,27 @@ GraphManager::GraphManager()
, microros_graph_info_typesupport_(std::make_unique<
eprosima::fastdds::dds::TypeSupport>(new graph_manager::MicrorosGraphInfoTypeSupport()))
{
// Create DomainParticipant
eprosima::fastdds::dds::DomainId_t domain_id(0);
eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->load_profiles();
// Create DomainParticipant
eprosima::fastdds::dds::DomainParticipantQos participant_qos =
eprosima::fastdds::dds::DomainParticipantFactory::get_instance()->get_default_participant_qos();
size_t length = snprintf(nullptr, 0, "enclave=%s;", enclave_) + 1;
const char * enclave = "/";
size_t length = snprintf(nullptr, 0, "enclave=%s;", enclave) + 1;
participant_qos.user_data().resize(length);
snprintf(reinterpret_cast<char *>(participant_qos.user_data().data_vec().data()),
length, "enclave=%s;", enclave_);
length, "enclave=%s;", enclave);
participant_qos.name(enclave_);
participant_qos.name(enclave);
participant_qos.wire_protocol().builtin.readerHistoryMemoryPolicy =
eprosima::fastrtps::rtps::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
participant_qos.wire_protocol().builtin.writerHistoryMemoryPolicy =
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()));
create_participant(domain_id_, participant_qos, participant_listener_.get(), par_mask));
// Register participant within typesupport
participant_->register_type(*participant_info_typesupport_);
@@ -78,28 +79,26 @@ GraphManager::GraphManager()
eprosima::fastdds::dds::TOPIC_QOS_DEFAULT));
// Create datawriters
eprosima::fastdds::dds::DataWriterQos datawriter_qos =
datawriter_qos_ =
eprosima::fastdds::dds::DATAWRITER_QOS_DEFAULT;
datawriter_qos.history().kind =
datawriter_qos_.history().kind =
eprosima::fastdds::dds::HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS;
datawriter_qos.history().depth = 1;
datawriter_qos.endpoint().history_memory_policy =
datawriter_qos_.history().depth = 1;
datawriter_qos_.endpoint().history_memory_policy =
eprosima::fastrtps::rtps::MemoryManagementPolicy::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
datawriter_qos.publish_mode().kind =
datawriter_qos_.publish_mode().kind =
eprosima::fastdds::dds::PublishModeQosPolicyKind::ASYNCHRONOUS_PUBLISH_MODE;
datawriter_qos.reliability().kind =
datawriter_qos_.reliability().kind =
eprosima::fastdds::dds::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS;
datawriter_qos.durability().kind =
datawriter_qos_.durability().kind =
eprosima::fastdds::dds::DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS;
ros_discovery_datawriter_.reset(
publisher_->create_datawriter(ros_discovery_topic_.get(), datawriter_qos));
datawriter_qos.history().kind =
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(), datawriter_qos));
publisher_->create_datawriter(ros_to_microros_graph_topic_.get(), ros_to_microros_datawriter_qos_));
// Create datareaders
@@ -138,10 +137,15 @@ inline void GraphManager::publish_microros_graph()
std::unique_lock<std::mutex> 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;
@@ -293,34 +297,55 @@ inline void GraphManager::publish_microros_graph()
}
void GraphManager::add_participant(
const eprosima::fastdds::dds::DomainParticipant* participant)
{
const eprosima::fastdds::dds::DomainParticipantQos qos = participant->get_qos();
this->add_participant(participant->guid(), qos.name().to_string(), enclave_);
}
void GraphManager::add_participant(
const eprosima::fastrtps::rtps::GUID_t& guid,
const std::string& node_name,
const eprosima::fastdds::dds::DomainParticipant* participant,
bool from_microros,
const std::string& enclave)
{
const rmw_gid_t gid = rmw_fastrtps_shared_cpp::create_rmw_gid("rmw_fastrtps_cpp", guid);
const eprosima::fastdds::dds::DomainParticipantQos qos = participant->get_qos();
const rmw_gid_t gid = rmw_fastrtps_shared_cpp::create_rmw_gid("rmw_fastrtps_cpp", participant->guid());
graphCache_.add_participant(gid, enclave);
if (node_name != enclave) // Do not add root node
// Do not add root node and
// do not announce non-micro-ROS participants
if (qos.name().to_string() != "/" && from_microros)
{
std::string isolated_node_name, isolated_namespace;
get_name_and_namespace(qos.name().to_string(), isolated_node_name, isolated_namespace);
rmw_dds_common::msg::ParticipantEntitiesInfo info =
graphCache_.add_node(gid, node_name, enclave_);
ros_discovery_datawriter_->write(static_cast<void *>(&info));
graphCache_.add_node(gid, isolated_node_name, isolated_namespace);
auto it = micro_ros_graph_datawriters_.find(participant);
if (it == micro_ros_graph_datawriters_.end())
{
// Create datawriter
std::unique_ptr<eprosima::fastdds::dds::DataWriter> datawriter;
datawriter.reset(publisher_->create_datawriter(ros_discovery_topic_.get(), datawriter_qos_));
it = micro_ros_graph_datawriters_.insert(
std::make_pair(participant, std::move(datawriter))).first;
}
it->second->write(static_cast<void *>(&info));
}
}
void GraphManager::remove_participant(
const eprosima::fastrtps::rtps::GUID_t& guid)
const eprosima::fastdds::dds::DomainParticipant* participant,
bool from_microros)
{
const rmw_gid_t gid = rmw_fastrtps_shared_cpp::create_rmw_gid("rmw_fastrtps_cpp", guid);
const rmw_gid_t gid = rmw_fastrtps_shared_cpp::create_rmw_gid("rmw_fastrtps_cpp", participant->guid());
graphCache_.remove_participant(gid);
if (from_microros)
{
rmw_dds_common::msg::ParticipantEntitiesInfo info;
rmw_dds_common::convert_gid_to_msg(&gid, &info.gid);
auto it = micro_ros_graph_datawriters_.find(participant);
it->second->write(static_cast<void *>(&info));
}
micro_ros_graph_datawriters_.erase(participant);
}
void GraphManager::add_datawriter(
@@ -450,14 +475,18 @@ void GraphManager::associate_entity(
{
case dds::xrce::OBJK_DATAWRITER:
{
std::string isolated_node_name, isolated_namespace;
get_name_and_namespace(qos.name().c_str(), isolated_node_name, isolated_namespace);
info = graphCache_.associate_writer(
entity_gid, participant_gid, qos.name().c_str(), enclave_);
entity_gid, participant_gid, isolated_node_name, isolated_namespace);
break;
}
case dds::xrce::OBJK_DATAREADER:
{
std::string isolated_node_name, isolated_namespace;
get_name_and_namespace(qos.name().c_str(), isolated_node_name, isolated_namespace);
info = graphCache_.associate_reader(
entity_gid, participant_gid, qos.name().c_str(), enclave_);
entity_gid, participant_gid, isolated_node_name, isolated_namespace);
break;
}
default:
@@ -465,7 +494,9 @@ void GraphManager::associate_entity(
break;
}
}
ros_discovery_datawriter_->write(static_cast<void *>(&info));
auto it = micro_ros_graph_datawriters_.find(participant);
it->second->write(static_cast<void *>(&info));
}
@@ -557,6 +588,43 @@ void GraphManager::update_node_entities_info()
}
}
void GraphManager::get_name_and_namespace(
std::string participant_name,
std::string& node_name,
std::string& node_namespace)
{
// Remove first / if exists
if (participant_name.rfind("/", 0) == 0)
{
participant_name.erase(participant_name.begin());
}
// Split node name in domain and node name
std::istringstream iss(participant_name);
std::vector<std::string> result;
std::string token;
while(std::getline(iss, token, '/'))
{
result.push_back(token);
}
if (result.size() > 1)
{
node_namespace = "/" + result[0];
for (size_t i = 1; i < result.size(); i++)
{
node_name.append(result[i] + "/");
}
node_name.pop_back();
}
else
{
node_name = participant_name;
node_namespace = "/";
}
}
GraphManager::ParticipantListener::ParticipantListener(
GraphManager* graph_manager)
: eprosima::fastdds::dds::DomainParticipantListener()
@@ -582,13 +650,13 @@ void GraphManager::ParticipantListener::on_participant_discovery(
const std::string enclave =
std::string(name_found->second.begin(), name_found->second.end());
graphManager_from_->add_participant(participant->guid(), info.info.m_participantName.to_string(), enclave);
graphManager_from_->add_participant(participant, false, enclave);
break;
}
case eprosima::fastrtps::rtps::ParticipantDiscoveryInfo::REMOVED_PARTICIPANT:
case eprosima::fastrtps::rtps::ParticipantDiscoveryInfo::DROPPED_PARTICIPANT:
{
graphManager_from_->remove_participant(info.info.m_guid);
graphManager_from_->remove_participant(participant, false);
break;
}
default:
@@ -657,7 +725,6 @@ void GraphManager::ParticipantListener::on_subscriber_discovery(
eprosima::fastrtps::rtps::ReaderDiscoveryInfo&& info)
{
process_discovery_info<eprosima::fastrtps::rtps::ReaderDiscoveryInfo>(info);
// graphManager_from_->associate_entity(info.info.guid(), participant, dds::xrce::OBJK_DATAREADER);
}
void GraphManager::ParticipantListener::on_publisher_discovery(
@@ -665,7 +732,6 @@ void GraphManager::ParticipantListener::on_publisher_discovery(
eprosima::fastrtps::rtps::WriterDiscoveryInfo&& info)
{
process_discovery_info<eprosima::fastrtps::rtps::WriterDiscoveryInfo>(info);
// graphManager_from_->associate_entity(info.info.guid(), participant, dds::xrce::OBJK_DATAWRITER);
}
GraphManager::DatareaderListener::DatareaderListener(
@@ -685,4 +751,4 @@ void GraphManager::DatareaderListener::on_data_available(
} // namespace agent
} // namespace uros
#endif // _UROS_AGENT_GRAPH_MANAGER_CPP
#endif // _UROS_AGENT_GRAPH_MANAGER_CPP
+63 -1
View File
@@ -18,10 +18,72 @@ int main(int argc, char** argv)
{
uros::agent::Agent micro_ros_agent;
if (!micro_ros_agent.create(argc, argv))
/** Bypass '--ros-args' flag, as we use our own CLI parser.
* As a workaround for launch files, arguments will be passed from
* ros2launch as a single token with spaces,
* to preserve the correct argument order; split it here.
* TODO(jamoralp): investigate ROS2 tools for properly parsing params from launch
**/
std::vector<std::string> params;
for (int i = 0; i < argc; ++i)
{
if(strcmp("--ros-args", argv[i]) == 0)
{
argc = i;
break;
}
params.emplace_back(std::string(argv[i]));
}
auto it = std::find(params.begin(), params.end(), "--ros-args");
if (params.end() != it)
{
if ((it - params.begin()) != 2)
{
std::ostringstream ss;
ss << "Error: when using ros2 launch, please specify ";
ss << "your arguments in a single variable." << std::endl;
ss << "Instead of 'arguments: {'udp4', '-p', '8888'}', do ";
ss << "'arguments: {'udp4 -p 8888'}" << std::endl;
std::cerr << ss.str();
return 1;
}
const std::string& agent_args(params.at(1));
std::istringstream iss(agent_args);
std::vector<std::string> agent_args_split(
std::istream_iterator<std::string>{iss},
std::istream_iterator<std::string>());
char** agent_argv = new char*[agent_args_split.size() + 1];
agent_argv[0] = argv[0];
char** agent_argv_it = &agent_argv[1];
for (const auto& arg : agent_args_split)
{
*agent_argv_it = new char[arg.length() + 1];
strcpy(*agent_argv_it, arg.c_str());
agent_argv_it++;
}
bool success = micro_ros_agent.create(agent_args_split.size() + 1, agent_argv);
for (size_t i = 1; i <= agent_args_split.size(); ++i)
{
delete [] agent_argv[i];
}
delete [] agent_argv;
if (!success)
{
return 1;
}
}
else if (!micro_ros_agent.create(argc, argv))
{
return 1;
}
micro_ros_agent.run();
return 0;
Vendored Executable
+104
View File
@@ -0,0 +1,104 @@
#!/bin/sh -e
# Confirm that the transport is valid
transport="$(snapctl get transport)"
case "$transport" in
udp4) ;;
udp6) ;;
tcp4) ;;
tcp6) ;;
serial) ;;
pseudoterminal) ;;
*)
echo "'$transport' is not a supported transport" >&2
return 1
;;
esac
# Confirm that the middleware is valid
middleware="$(snapctl get middleware)"
case "$middleware" in
dds) ;;
rtps) ;;
ced) ;;
*)
echo "'$middleware' is not a supported middleware" >&2
return 1
;;
esac
if [ "$transport" = "serial" ] || [ "$transport" = "pseudoterminal" ]; then
# A serial transport if being used, which requires a valid baud rate
# as well as a valid device
baudrate="$(snapctl get baudrate)"
if ! expr "$baudrate" : '^[0-9]\+$' > /dev/null; then
echo "'$baudrate' is not a valid baud rate" >&2
return 1
fi
device="$(snapctl get device)"
if [ -z "$device" ]; then
echo "Device must be specified" >&2
return 1
fi
else
port="$(snapctl get port)"
if ! expr "$port" : '^[0-9]\+$' > /dev/null; then
echo "'$port' is not a valid port" >&2
return 1
fi
fi
# Confirm that discovery is a boolean
discovery="$(snapctl get discovery)"
case "$discovery" in
true)
# Confirm that discovery port is valid
port="$(snapctl get discovery-port)"
if ! expr "$port" : '^[0-9]\+$' > /dev/null; then
echo "'$port' is not a valid discovery port" >&2
return 1
fi
;;
false) ;;
*)
echo "'$discovery' is not a valid boolean for discovery" >&2
return 1
;;
esac
# Confirm that the verbosity is valid
verbosity="$(snapctl get verbosity)"
if ! expr "$verbosity" : '^[0-6]$' > /dev/null; then
echo "'$verbosity' is not a valid verbosity" >&2
return 1
fi
# Confirm that p2p port is valid (assuming it's set)
p2p_port="$(snapctl get p2p-port)"
if [ -n "$p2p_port" ]; then
port="$(snapctl get p2p-port)"
if ! expr "$port" : '^[0-9]\+$' > /dev/null; then
echo "'$port' is not a valid p2p port" >&2
return 1
fi
fi
# Confirm that daemon is a boolean, and enable the service if true
daemon="$(snapctl get daemon)"
case "$daemon" in
true)
snapctl start --enable "$SNAP_INSTANCE_NAME.daemon"
# In case it was alraedy started and the configuration changed,
# restart the service
snapctl restart "$SNAP_INSTANCE_NAME.daemon"
;;
false)
snapctl stop --disable "$SNAP_INSTANCE_NAME.daemon"
;;
*)
echo "'$daemon' is not a valid boolean for daemon" >&2
return 1
;;
esac
+19
View File
@@ -0,0 +1,19 @@
#!/bin/sh -e
# Set default configuration values
snapctl set transport=udp4
snapctl set middleware=dds
snapctl set verbosity=4
snapctl set discovery=false
snapctl set discovery-port=7400
snapctl set p2p-port! # unset
# Network-specific things
snapctl set port=8888
# Serial-specific things
snapctl set baudrate=115200
snapctl set device! # unset
# By default the daemon is disabled
snapctl set daemon=false
+27
View File
@@ -0,0 +1,27 @@
#!/bin/sh -e
set -- --middleware "$(snapctl get middleware)" "$@"
set -- --verbose "$(snapctl get verbosity)" "$@"
transport="$(snapctl get transport)"
if [ "$transport" = "serial" ] || [ "$transport" = "pseudoterminal" ]; then
set -- --dev "$(snapctl get device)" "$@"
else
set -- --port "$(snapctl get port)" "$@"
fi
if [ "$(snapctl get discovery)" = "true" ]; then
set -- --discovery "$@"
discovery_port="$(snapctl get discovery-port)"
if [ -n "$discovery_port" ]; then
set -- --disport "$discovery_port" "$@"
fi
fi
p2p_port="$(snapctl get p2p-port)"
if [ -n "$p2p_port" ]; then
set -- --p2p "$p2p_port" "$@"
fi
exec "$SNAP/lib/micro_ros_agent/micro_ros_agent" "$transport" "$@"
+168
View File
@@ -0,0 +1,168 @@
name: micro-ros-agent
base: core20
version: git
summary: Bridge between Micro ROS client applications and ROS 2
description: |
Micro-ROS, whose default implementation is based on eProsima's
Micro XRCE-DDS middleware, is composed of client applications
which interact with the ROS 2 world by means of an Agent.
This agent keeps tracks of the entities created by means of
requests performed on the microcontroller side, and uses them
to communicate with the ROS 2 dataspace.
Being an extension of the Micro XRCE-DDS Agent, the micro-ROS
agent supports being run by the user like this:
$ micro-ros-agent --help
In addition, the Agent supports running as a service that can be
enabled with:
$ snap set micro-ros-agent daemon=true
If the service is enabled, by default it uses the `udp4` transport on
port 8888. The following parameters can be changed (these are
specific to the service, the `micro-ros-agent` command simply
takes command-line arguments, but the capabilities are the same):
* `transport`. Supported transports are `udp4`, `udp6`, `tcp4`,
`tcp6`, `serial`, and `pseudoterminal`. Default is `udp4`. Change
with:
$ snap set micro-ros-agent transport="new transport"
* `middleware`. Supported kinds of middleware are `ced`, `rtps`, and
`dds`. Default is `dds`. Change with:
$ snap set micro-ros-agent middleware="new middleware"
* `verbosity`. Supported verbosity levels are 0-6, defaulting to 4.
Change with:
$ snap set micro-ros-agent verbosity="selected verbosity"
* `discovery`. Enable or disable the discovery server. Defaults to
"false". Change with:
$ snap set micro-ros-agent discovery="true or false"
* `discovery-port`. Port on which the discovery server (see above)
listens. Defaults to 7400. Change with:
$ snap set micro-ros-agent discovery-port="selected port"
* `p2p-port`. Port to use for the P2P profile. Change with:
$ snap set micro-ros-agent p2p-port="selected port"
* `port`. Port on which the agent listens. Only applicable to one of
the UDP or TCP transports (see above). Defaults to 8888. Change with:
$ snap set micro-ros-agent port="selected port"
* `baudrate`. Baud rate to use when accessing serial ports. Only
applicable when using the `serial` or `pseudoterminal` transport.
Defaults to 115200. Change with:
$ snap set micro-ros-agent baudrate="baud rate"
* `device`. The serial device to use. Only applicable when using the
`serial` or `pseudoterminal` transport. Change with:
$ snap set micro-ros-agent device="device path"
If connecting the micro-ROS Agent using an IP based connection mode,
that is, `udp4`, `udp6`, `tcp4` or `tcp6`, care must be taken to
connect first the `micro-ros-agent-shm-netplug` plug.
This is due to the fact that ROS 2 Foxy is using Fast-DDS as the
default DDS middleware, and Fast-DDS comes with *shared memory transport*.
Thus, this plugin must be enabled, in order to gain access to the
`/dev/shm` folder from the snap image, prior to running it:
$ sudo snap connect micro-ros-agent:micro-ros-agent-shm-netplug
When using the snap with a serial device, some steps need to be taken
in order to establish a successful connection:
* Refresh your local installation of the snap `core` package:
$ sudo snap refresh core --edge
* Enable the hotplug feature and restart the `snapd` daemon:
$ sudo snap set core experimental.hotplug=true
$ sudo systemctl restart snapd
* After plugging the microcontroller to the serial port, execute
the `snap interface serial-port` command. You should see something
like this:
name: serial-port
summary: allows accessing a specific serial port
plugs:
- micro-ros-agent
slots:
- snapd:cp2102cp2109uartbrid (allows accessing a specific serial port)
* Connect your snap image to the desired serial port (replace accordingly):
$ snap connect micro-ros-agent:serial-port snapd:cp2102cp2109uartbrid
After this, you can execute your snap as usual,
using `sudo micro-ros-agent serial -d <serial-dev>`.
grade: stable
confinement: strict
architectures:
- build-on: amd64
- build-on: arm64
- build-on: armhf
- build-on: ppc64el
parts:
uros-agent:
plugin: colcon
source: .
override-build: |
set +u
git clone https://github.com/eProsima/Micro-XRCE-DDS-Agent.git -b $ROS_DISTRO
git clone https://github.com/eProsima/Micro-CDR.git -b $ROS_DISTRO
git clone https://github.com/micro-ROS/micro_ros_msgs.git -b $ROS_DISTRO
git clone https://github.com/micro-ROS/rosidl_typesupport_microxrcedds.git -b $ROS_DISTRO
git clone https://github.com/micro-ROS/rmw-microxrcedds.git -b $ROS_DISTRO
git clone https://github.com/micro-ROS/micro-ROS-Agent.git -b $ROS_DISTRO
. /opt/ros/$ROS_DISTRO/setup.sh
colcon build --merge-install --install-base $SNAPCRAFT_PRIME --cmake-args "-DUAGENT_BUILD_EXECUTABLE=OFF -DUAGENT_USE_SYSTEM_FASTDDS=ON" --packages-up-to micro_ros_agent
set -u
build-packages: [make, gcc, g++]
stage-packages: [ros-foxy-ros2launch]
runner:
plugin: dump
source: snap/local/
organize:
'*': usr/bin/
plugs:
micro-ros-agent-shm-netplug:
interface: system-files
allow-auto-connection: true
write:
- /dev/shm
apps:
micro-ros-agent:
command: lib/micro_ros_agent/micro_ros_agent
environment:
LD_LIBRARY_PATH: "$LD_LIBRARY_PATH:$SNAP/lib"
plugs: [network, network-bind, serial-port, micro-ros-agent-shm-netplug]
extensions: [ros2-foxy]
daemon:
command: usr/bin/micro-ros-agent-daemon
environment:
LD_LIBRARY_PATH: "$LD_LIBRARY_PATH:$SNAP/lib"
daemon: simple
plugs: [network, network-bind, serial-port, micro-ros-agent-shm-netplug]