Compare commits

..
90 Commits
Author SHA1 Message Date
acuadros95 e6b928b1e1 5.0.0 2023-06-06 09:25:33 +00:00
acuadros95 4c98e4f9f5 Changelog
Signed-off-by: acuadros95 <acuadros1995@gmail.com>
2023-06-06 09:24:56 +00:00
Antonio Cuadros 964b0aec1a Add empty type key hash to GraphCache (#189)
Signed-off-by: acuadros95 <acuadros1995@gmail.com>
2023-06-06 11:11:24 +02:00
Pablo Garrido 03946126dd 4.0.2 2022-09-28 15:58:41 +02:00
Pablo Garrido 0142528a73 Changelog 2022-09-28 15:58:35 +02:00
mergify[bot]andPablo Garrido 53ff7d409d Fix Datawriter destruction (#169) (#170)
Signed-off-by: Pablo Garrido <pablogs9@gmail.com>

Signed-off-by: Pablo Garrido <pablogs9@gmail.com>
(cherry picked from commit 4f686e8dc1)

Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
2022-08-23 13:08:35 +02:00
mergify[bot]andcmraaron 9e9167b0d7 Synchronise predicate (#160) (#165)
* ensure synchronised access to our predicate

Signed-off-by: Aaron <aaron.lipinski@cm-robotics.com>

* release lock before signalling

Signed-off-by: Aaron <aaron.lipinski@cm-robotics.com>

Signed-off-by: Aaron <aaron.lipinski@cm-robotics.com>
(cherry picked from commit d4be840332)

Co-authored-by: cmraaron <102722879+cmraaron@users.noreply.github.com>
2022-08-19 09:27:21 +02:00
Pablo Garrido 93aa9e6a73 4.0.1 2022-06-13 07:45:38 +02:00
Pablo Garrido e62154a1cf Changelog
Signed-off-by: Pablo Garrido <pablogs9@gmail.com>
2022-06-13 07:45:07 +02:00
mergify[bot]andPablo Garrido 495733690c Fix memory leak in graph manager (#147) (#148)
Signed-off-by: Pablo Garrido <pablogs9@gmail.com>
(cherry picked from commit c89776e1fd)

Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
2022-06-08 14:21:11 +02:00
Pablo Garrido 179ae80b94 4.0.0 2022-05-25 09:10:03 +02:00
Pablo Garrido 5ad09cec70 Update changelog 2022-05-25 09:09:56 +02:00
Pablo Garrido dfd6966cd1 Update CI (#138)
* Update CI

Signed-off-by: Pablo Garrido <pablogs9@gmail.com>

* Fix yml

Signed-off-by: Pablo Garrido <pablogs9@gmail.com>

* Update

Signed-off-by: Pablo Garrido <pablogs9@gmail.com>

* Ensure fastrtps rmw

Signed-off-by: Pablo Garrido <pablogs9@gmail.com>

* Modify approach

Signed-off-by: Pablo Garrido <pablogs9@gmail.com>
2022-05-23 09:08:43 +02:00
mergify[bot]andAntonio Cuadros d91c98ab6e Add snap issue to README (#131) (#132)
(cherry picked from commit 0d4fcf8547)

Co-authored-by: Antonio Cuadros <49162117+Acuadros95@users.noreply.github.com>
2022-04-19 14:57:19 +02:00
Pablo Garrido 9ed4bb3c15 3.0.1 2022-03-25 11:15:37 +01:00
Pablo Garrido 489dbddced Update changelog
Signed-off-by: Pablo Garrido <pablogs9@gmail.com>
2022-03-25 11:15:30 +01:00
mergify[bot]andPablo Garrido ed0402c2dd Add services to graph manager (#127) (#129)
Signed-off-by: Pablo Garrido <pablogs9@gmail.com>
(cherry picked from commit 6d67807737)

Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
2022-03-22 10:26:24 +01:00
mergify[bot]andPablo Garrido 5780038fcc Add used missing includes (#116) (#124)
* Signed-off-by: Pablo Garrido <pablogs9@gmail.com>

* Update CI

Signed-off-by: Pablo Garrido <pablogs9@gmail.com>
(cherry picked from commit 2326a201bc)

Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
2022-03-17 08:47:50 +01:00
mergify[bot]andAntonio Cuadros 57bdfc5463 Add system logger flag (#118) (#119)
* Add system logger flag

* Add flag to superbuild

(cherry picked from commit 90545b7184)

Co-authored-by: Antonio Cuadros <49162117+Acuadros95@users.noreply.github.com>
2022-01-27 15:35:26 +01:00
mergify[bot]andPablo Garrido 1f1b5842c6 Add condition variable include (#113) (#114)
Signed-off-by: Pablo Garrido <pablogs9@gmail.com>

Update

Signed-off-by: Pablo Garrido <pablogs9@gmail.com>
(cherry picked from commit 07c460a327)

Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
2022-01-14 08:21:30 +01:00
mergify[bot]andRoland Schwan 6d2d47490a pass system name to xrceagent (#110) (#112)
(cherry picked from commit 8aea206b93)

Co-authored-by: Roland Schwan <RSchwan@users.noreply.github.com>
2022-01-12 12:43:38 +01:00
mergify[bot]andPablo Garrido 61b1e6fc8c Fix memory leak in FastDDS datawriter (#107) (#109)
Signed-off-by: Pablo Garrido <pablogs9@gmail.com>
(cherry picked from commit ff2ae91877)

Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
2021-12-22 10:23:17 +01:00
Your Name d7dab5c671 3.0.0 2021-09-13 12:17:47 +02:00
Pablo Garrido e85eccb7c0 Changelog 2021-09-13 12:14:35 +02:00
Your Name ac9f09b656 1.0.1 2021-09-13 11:45:28 +02:00
Pablo Garrido 7ffd5f0bb6 Changelog 2021-09-13 11:45:14 +02:00
Pablo Garrido ceb1a1436c Remove XRCE dependency and add superbuild (#97)
Update package info


Update


Fix xrceagent paths

Update


Revert "Bump version"

This reverts commit 7b6b713041405a21d701952ef1eb2e8faab2802e.

Initial
2021-09-13 10:39:52 +02:00
mergify[bot]andmecarill c98705319f Fixed launch file by using a list for arguments. Ensures order of items is kept. (#93) (#94)
Co-authored-by: mecarill <mihkailkennerley@gmail.com>
(cherry picked from commit fe1b3ade97)

Co-authored-by: mecarill <62688286+mecarill@users.noreply.github.com>
2021-08-25 09:14:01 +02:00
Antonio Cuadros d149bb7018 Modify argument type (#91) 2021-08-23 13:52:17 +02:00
Pablo Garrido 646ca52aab Fix graph manager datawriters behaviour (#84)
* Fix graph manager datawriters


Fixes


Fix


Fix destruction

* Revert "Fix graph manager datawriters"

This reverts commit 2847a2ebc3.

* Initial
2021-07-09 13:36:31 +02:00
Pablo Garrido 95fecd77ae Graph manager: Fix participant mask for listener callbacks (#81) 2021-07-08 15:21:01 +02:00
Pablo GarridoandYour Name 69f17c28a8 Fix agent launch (#78)
Co-authored-by: Your Name <you@example.com>
2021-07-05 10:49:11 +02:00
Pablo Garrido f6a2aa3b60 Fix graph manager node namespaces (#75)
* Fix graph manager node namespaces

* Update
2021-07-02 13:28:22 +02:00
Pablo Garrido a623308505 Fix graph manager node namespaces (#72) 2021-07-02 09:44:20 +02:00
Pablo Garrido e133754746 Fix Rolling agent (#61)
* Initial

* Remove deprecated FastDDS entities methods


Remove headers

* Add conversion functions
2021-06-21 16:15:47 +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
Jose Antonio Moral e9330bf974 Create graph manager after checking passed CLI arguments and launch xrce-dds server (#41) 2020-12-02 16:51:22 +01:00
Jose Antonio Moral 602976b45f micro_ros_msgs has its own repository now (#40)
* micro_ros_msgs has its own repository now

* Update CI

* Update CI

* Fix CI order

* Error in YAML file

* Source ROS2

* Add rosdep update

* Fix
2020-12-01 11:58:57 +01:00
Jose Antonio MoralandPablo Garrido 23bcea8efb Feature/graph manager (#38)
* Initial changes

* Working state

* Working state

* Working state

* Working state

* Working state

* Working state

* Added graph listener

* Updates

* Testing name demangling

* Graph manager: reworked

* Remove debug trace

* Treat errors when freeing rcutils resources

* Improve logics for discovering entities

* Working state: Micro-ROS graph manager

* Fix micro_ros_graph_info typesupport type name

* Remove double CMakeLists comment

* Remove package.xml commented block

* Add missing include

* Added CI

* Remove GUID_t param from callbacks signature

* Add services names and types to micro-ROS graph topic

* Differenciate between service server and clients

* remove debug traces

Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
2020-11-26 07:44:52 +01:00
Pablo Garrido dce3c25a33 Update README.md 2020-08-06 08:04:37 +02:00
Jose Antonio Moral 8bbe143d11 Refactor micro-ROS-Agent to use new singleton class (#34) 2020-08-04 12:41:39 +02:00
Pablo Garrido 81316109d9 Add licensing (#31)
* Add licensing

* Update

* Update
2020-08-04 11:24:10 +02:00
Pablo Garrido b7406c4b34 Update CMakeLists.txt 2020-07-22 08:00:40 +02:00
Pablo Garrido 85ef5321f8 Feature/foxy migration (#30)
* Adding rosidl_cmake

* Updated XML generation

* Updated readme

* Update README.md
2020-06-29 10:22:23 +02:00
Julián Bermúdez Ortega f0effec782 Refactor CMakeLists.txt. (#28) 2020-04-28 09:47:03 +02:00
Julián Bermúdez Ortega 85ec50d441 Update main.cpp according to Micro XRCE-DDS Agent API changes. (#27) 2020-04-14 16:59:32 +02:00
Borja OutereloandJulián Bermúdez Ortega f377b7a727 Dashing migration. (#15)
* Addapt to Dashing Diademata rosidl generation.

* Use new Micro XRCE-DDS agent library API.

* main.cpp update (#22)

* Update main.cpp according to the new version of Micro-XRCE-DDS-Agent.

* Apply suggestions from code review

Co-Authored-By: Borja Outerelo <borjaouterelo@gmail.com>

Co-authored-by: Borja Outerelo <borjaouterelo@gmail.com>

Co-authored-by: Julián Bermúdez Ortega <julianbermudez@eprosima.com>
2020-01-28 11:06:29 +01:00
Borja Outerelo b47de612e6 Remove not needed package. 2019-07-12 12:26:34 +02:00
Borja Outerelo d604a15708 Add CMakeLists.txt.user to gitignore and remove it from repo. (#13) 2019-04-26 13:51:51 +02:00
Borja Outerelo f7f4bf405e Rename package. (#12) 2019-04-24 18:23:13 +02:00
Borja Outerelo 1ef5e1b177 Update README.md 2019-04-24 16:09:52 +02:00
Borja Outerelo 5301589a90 Update micro-xrce-dds-agent package name. 2019-04-24 15:39:57 +02:00
Borja Outerelo e3fa817083 Fix package file. 2019-04-24 08:46:25 +02:00
Borja Outerelo 93621c8d67 Merge pull request #11 from micro-ROS/develop
Feature/pack (#10)
2019-04-24 08:32:40 +02:00
Borja Outerelo 6cdb2c2e5c Feature/pack (#10)
* Change name.

* Add changelog.
2019-04-24 08:31:13 +02:00
Borja Outerelo 8c65e094f2 Merge pull request #8 from microROS/develop
Update master
2018-11-30 10:30:39 +01:00
Borja Outerelo b820033df7 Update README.md 2018-11-30 10:23:24 +01:00
Borja Outerelo 16ef5db11c Create README.md 2018-11-30 10:22:28 +01:00
Borja Outerelo 9eaf57d2eb Update README.md 2018-11-29 20:51:43 +01:00
Borja Outerelo 2dd00a29b6 Create LICENSE 2018-11-29 20:51:12 +01:00
Borja Outerelo eb8f02b322 Merge branch 'master' into develop 2018-11-20 09:09:53 +01:00
Javier Moreno d1c08622ce Uncrustify lint format fix. (#7) 2018-11-19 16:17:04 +01:00
Borja Outerelo 8cb1bfe91a v0.0.1-alpha (#6)
* Issue with windows paths solved.

* Fixed issue when --merge-install is activated (Windows issue)

* Updated to last version of Micoxrcedds Agent. (#3)

* Restored removed code by accident (#4)

* Refs #3842. Removes agent node.
2018-11-17 22:06:58 +01:00
Javier Moreno 162117d9a2 Merge pull request #5 from microROS/feature/agentnode
Refs #3842. Removes agent node.
2018-11-17 13:05:01 +01:00
Borja Outerelo efaf219a63 Refs #3842. Removes agent node. 2018-11-16 10:34:08 +01:00
Javier Moreno 4a3a8a3b52 Restored removed code by accident (#4) 2018-11-15 16:23:35 +01:00
Javier Moreno 53555aa991 Updated to last version of Micoxrcedds Agent. (#3) 2018-11-15 15:00:37 +01:00
Borja Outerelo 735babba37 Merge pull request #2 from microROS/feature/WindowsFix
Feature/windows fix
2018-11-15 14:39:06 +01:00
Javier Moreno 9b615a4174 Fixed issue when --merge-install is activated (Windows issue) 2018-11-14 13:17:15 +01:00
Javier Moreno 70757b4144 Issue with windows paths solved. 2018-11-14 00:01:02 +01:00
Borja Outerelo 6b093d8417 Merge pull request #1 from microROS/develop
Develop
2018-11-06 17:58:02 +01:00
Javier Moreno 27203c273e XML fix 2018-11-02 11:57:07 +01:00
Javier JM. Moreno b483e7e007 Feature/u ros agent node 2018-10-31 15:49:30 +01:00
Javier JM. Moreno d66fa96f30 Refs #3552 - Adapt to new XML profiles 2018-10-31 15:09:09 +01:00
Javier Moreno bb1fe9561c Refs #3561 - Generate uROS_Agent module 2018-10-19 10:45:56 +02:00
Borja Outerelo 45c4a698c3 Refs #3486. Adds some wording improvements. 2018-10-19 10:14:12 +02:00
Javier Moreno c5cc980824 logo size ajusted. 2018-10-16 15:04:02 +02:00
Javier Moreno fa6e94898b Review needed. Links are missing until migration to external networks. 2018-10-16 15:04:02 +02:00
Javier Moreno e8621a76e6 Refs #3486 - Create Readme.md for uROS agent 2018-10-16 15:04:02 +02:00
Borja Outerelo a77c0f7547 Refs #3499. Uses new middleware name, Micro XRCE-DDS. 2018-10-16 11:48:51 +02:00
Javier Moreno ffc3c372be Refs #3459. 2018-10-04 09:14:22 +02:00
Borja Outerelo 1d106a8945 Merge branch 'developJ' into 'develop'
Develop j

See merge request eProsima/micro-ros-agent!1
2018-10-02 11:56:17 +02:00
40 changed files with 3840 additions and 500 deletions
+30
View File
@@ -0,0 +1,30 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behaviour:
1. Clone repo '...'
2. Add these lines '...'
3. Run the script '....'
4. See error
Code or shell commands ready to be copy-pasted are welcome.
**Expected behaviour**
A clear and concise description of what you expected to happen.
**System information (please complete the following information):**
- OS: [e.g. WIndows 10, Ubuntu 16.04, ...]
- ROS 2 [e.g. Dashing, Foxy, ...]
- Version [e.g. commit hash, tag, ...]
**Additional context**
Add any other context about the problem here.
+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
+37
View File
@@ -0,0 +1,37 @@
name: CI micro-ROS Agent
on:
pull_request:
branches:
- 'main'
schedule:
- cron: '33 6 * * *'
jobs:
microros_agent_ci:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-20.04 ]
ros_distribution: [ rolling ]
include:
- docker_image: ubuntu:22.04
ros_distribution: rolling
container:
image: ubuntu:22.04
steps:
- uses: actions/checkout@v2
- uses: ros-tooling/setup-ros@0.3.2
with:
use-ros2-testing: false
required-ros-distributions: ${{ matrix.ros_distribution }}
- name : Download and install dependencies
run: |
apt-get install ros-${{ matrix.ros_distribution }}-micro-ros-msgs
apt-get install ros-${{ matrix.ros_distribution }}-rmw-fastrtps-cpp
- uses : ros-tooling/action-ros-ci@0.2.5
with:
package-name: "micro_ros_agent"
target-ros2-distro: ${{ matrix.ros_distribution }}
+35
View File
@@ -0,0 +1,35 @@
# Created by https://www.gitignore.io/api/qtcreator
# Edit at https://www.gitignore.io/?templates=qtcreator
### QtCreator ###
# gitignore for Qt Creator like IDE for pure C/C++ project without Qt
#
# Reference: http://doc.qt.io/qtcreator/creator-project-generic.html
# Qt Creator autogenerated files
# A listing of all the files included in the project
*.files
# Include directories
*.includes
# Project configuration settings like predefined Macros
*.config
# Qt Creator settings
*.creator
# User project settings
*.creator.user*
# Qt Creator backups
*.autosave
# End of https://www.gitignore.io/api/qtcreator
CMakeLists.txt.user
+4
View File
@@ -0,0 +1,4 @@
Third Party Licenses
====================
This repository does not directly contain 3rd party source code.
-60
View File
@@ -1,60 +0,0 @@
# Copyright 2018 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 CMake version
cmake_minimum_required(VERSION 3.5)
# Set proyect name
project(micro_ros_agent)
# Find packages depencences
find_package(ament_cmake REQUIRED)
find_package(fastcdr REQUIRED CONFIG)
find_package(fastrtps REQUIRED CONFIG)
find_package(micrortps_agent REQUIRED CONFIG)
find_package(ament_cmake_python REQUIRED)
# Export dependencies to downstream packages
ament_export_dependencies(fastcdr)
ament_export_dependencies(fastrtps)
ament_export_dependencies(micrortps_agent)
# Install python files
ament_python_install_package(${PROJECT_NAME})
# Register package resource in order to be called when a new msg package is generated
ament_index_register_resource("rosidl_typesupport_c")
# Install the package.xml file, and generate code for ``find_package`` so that other packages can get information about this package.
ament_package(
CONFIG_EXTRAS "micro_ros_agent-extras.cmake.in"
)
install(
PROGRAMS bin/micro_ros_agent
DESTINATION lib/micro_ros_agent
)
install(
DIRECTORY cmake resource
DESTINATION share/${PROJECT_NAME}
)
+107
View File
@@ -0,0 +1,107 @@
# Contributing
Want to contribute? Great! You can do so through the standard GitHub pull
request model. For large contributions we do encourage you to file a ticket in
the GitHub issues tracking system prior to any code development to coordinate
with the system_modes development team early in the process. Coordinating up
front helps to avoid frustration later on.
Your contribution must be licensed under the Apache-2.0 license, the license
used by this project.
## Add / retain copyright notices
Include a copyright notice and license in each new file to be contributed,
consistent with the style used by this project. If your contribution contains
code under the copyright of a third party, document its origin, license, and
copyright holders.
## Sign your work
This project tracks patch provenance and licensing using a modified Developer
Certificate of Origin (DCO; from [OSDL][DCO]) and Signed-off-by tags initially
developed by the Linux kernel project.
```
system_modes Developer's Certificate of Origin. Version 1.0
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the "Apache License, Version 2.0"
("Apache-2.0"); or
(b) The contribution is based upon previous work that is covered by
an appropriate open source license and I have the right under
that license to submit that work with modifications, whether
created in whole or in part by me, under the Apache-2.0 license;
or
(c) The contribution was provided directly to me by some other
person who certified (a) or (b) and I have not modified it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
metadata and personal information I submit with it, including my
sign-off) is maintained indefinitely and may be redistributed
consistent with this project and the requirements of the Apache-2.0
license or any open source license(s) involved, where they are
relevant.
(e) I am granting the contribution to this project under the terms of
Apache-2.0.
http://www.apache.org/licenses/LICENSE-2.0
```
With the sign-off in a commit message you certify that you authored the patch
or otherwise have the right to submit it under an open source license. The
procedure is simple: To certify above system_modes Developer's Certificate of
Origin 1.0 for your contribution just append a line
Signed-off-by: Random J Developer <random@developer.example.org>
to every commit message using your real name or your pseudonym and a valid
email address.
If you have set your `user.name` and `user.email` git configs you can
automatically sign the commit by running the git-commit command with the `-s`
option. There may be multiple sign-offs if more than one developer was
involved in authoring the contribution.
For a more detailed description of this procedure, please see
[SubmittingPatches][] which was extracted from the Linux kernel project, and
which is stored in an external repository.
### Individual vs. Corporate Contributors
Often employers or academic institution have ownership over code that is
written in certain circumstances, so please do due diligence to ensure that
you have the right to submit the code.
If you are a developer who is authorized to contribute to system_modes on
behalf of your employer, then please use your corporate email address in the
Signed-off-by tag. Otherwise please use a personal email address.
## Maintain Copyright holder / Contributor list
Each contributor is responsible for identifying themselves in the
[NOTICE](NOTICE) file, the project's list of copyright holders and authors.
Please add the respective information corresponding to the Signed-off-by tag
as part of your first pull request.
If you are a developer who is authorized to contribute to system_modes on
behalf of your employer, then add your company / organization to the list of
copyright holders in the [NOTICE](NOTICE) file. As author of a corporate
contribution you can also add your name and corporate email address as in the
Signed-off-by tag.
If your contribution is covered by this project's DCO's clause "(c) The
contribution was provided directly to me by some other person who certified
(a) or (b) and I have not modified it", please add the appropriate copyright
holder(s) to the [NOTICE](NOTICE) file as part of your contribution.
[DCO]: http://web.archive.org/web/20070306195036/http://osdlab.org/newsroom/press_releases/2004/2004_05_24_dco.html
[SubmittingPatches]: https://github.com/wking/signed-off-by/blob/7d71be37194df05c349157a2161c7534feaf86a4/Documentation/SubmittingPatches
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.
+27
View File
@@ -0,0 +1,27 @@
# This is the official list of copyright holders and authors.
#
# Often employers or academic institutions have ownership over code that is
# written in certain circumstances, so please do due diligence to ensure that
# you have the right to submit the code.
#
# When adding J Random Contributor's name to this file, either J's name on its
# own or J's name associated with J's organization's name should be added,
# depending on whether J's employer (or academic institution) has ownership
# over code that is written for this project.
#
# How to add names to this file:
# Individual's name <submission email address>.
#
# If Individual's organization is copyright holder of her contributions add the
# organization's name, optionally also the contributor's name:
#
# Organization's name
# Individual's name <submission corporate email address>
#
# Please keep the list sorted.
eProsima
Jose Antonio Moral <joseantoniomoralparras@eprosima.com>
Pablo Garrido <pablogarrido@eprosima.com>
+57 -1
View File
@@ -1,2 +1,58 @@
# micro-ros-agent
# micro-ROS Agent
[![GitHub license](https://img.shields.io/github/license/microROS/micro-ROS-Agent.svg)](https://github.com/microROS/micro-ROS-Agent)
[![GitHub release](https://img.shields.io/github/release/microROS/micro-ROS-Agent.svg)](https://github.com/microROS/micro-ROS-Agent/releases)
ROS 2 package using Micro XRCE-DDS Agent.
## Overview
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://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.
The node interacts with DDS Global Data Space on behalf of the Micro-ROS nodes.
## Package features
### XML generation
During the build process, the package looks for all ROS 2 messages to generate an initial list of XML profiles.
These profiles can are referenced in the Agent-Client communication to avoid sending the full XML content.
This reference mechanism can be switched on and off from the Micro XRCE-DDS middleware layer.
### Agent-Client communication mechanism
Communication between the Micro-ROS Agent and the Micro-ROS nodes supports two types of transport:
- UDP and TCP over IPv4 and IPv6.
- Serial Port transports.
All available configurations are supported directly by the Micro XRCE-DDS agent.
## Purpose of the Project
This software is not ready for production use. It has neither been developed nor
tested for a specific use case. However, the license conditions of the
applicable Open Source licenses allow you to adapt the software to your needs.
Before using it in a safety relevant setting, make sure that the software
fulfills your requirements and adjust it according to any applicable safety
standards, e.g., ISO 26262.
## License
This repository is open-sourced under the Apache-2.0 license. See the [LICENSE](LICENSE) file for details.
For a list of other open-source components included in this repository,
see the file [3rd-party-licenses.txt](3rd-party-licenses.txt).
## Known Issues/Limitations
Please notice the following issues/limitations:
* There is an unknown issue when dealing with serial ports shared with the micro-ROS agent running inside a Docker. Sometimes it works with a remarkable packet loss.
* There is an known issues with serial port communication on micro-ros-agent snap version. It is recommended to use the dockerized version or build it from source.
-45
View File
@@ -1,45 +0,0 @@
#!/usr/bin/env python3
import argparse
import os
import sys
from rosidl_cmake import read_generator_arguments
from rosidl_parser import UnknownMessageType
from micro_ros_agent import generate_micro_ros_agent_xml_support
def is_valid_file(parser, file_name):
if not os.path.exists(file_name):
parser.error("File does not exist: '{0}'".format(file_name))
file_name_abs = os.path.abspath(file_name)
if not os.path.isfile(file_name_abs):
parser.error("Path exists but is not a file: '{0}'".format(file_name_abs))
return file_name
def main(argv=sys.argv[1:]):
parser = argparse.ArgumentParser(
description='Generate xml files for micrortps agent.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument(
'--generator-arguments-file',
required=True,
help='The location of the file containing the generator arguments')
args = parser.parse_args(argv)
generator_args = read_generator_arguments(args.generator_arguments_file)
try:
rc = generate_micro_ros_agent_xml_support(generator_args)
return 0
except UnknownMessageType as e:
print(str(e), file=sys.stderr)
return 1
if rc:
return rc
return 0
if __name__ == '__main__':
sys.exit(main())
-69
View File
@@ -1,69 +0,0 @@
# Copyright 2016-2018 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.
# list msg files
set(_ros_idl_files "")
foreach(_idl_file ${rosidl_generate_interfaces_IDL_FILES})
get_filename_component(_extension "${_idl_file}" EXT)
# Skip .srv files
if(_extension STREQUAL ".msg")
list(APPEND _ros_idl_files "${_idl_file}")
endif()
endforeach()
# Set output dir
set(_output_path "${CMAKE_CURRENT_BINARY_DIR}/../micro_ros_agent/xml_gen")
# check if all templates exits
set(target_dependencies
"${micro_ros_agent_BIN}"
"${micro_ros_agent_GENERATOR_FILES}"
${rosidl_generate_interfaces_IDL_FILES}
${_dependency_files})
foreach(dep ${target_dependencies})
if(NOT EXISTS "${dep}")
message(FATAL_ERROR "Target dependency '${dep}' does not exist")
endif()
endforeach()
# generate script argument file
set(generator_arguments_file "${CMAKE_CURRENT_BINARY_DIR}/micro_ros_agent__arguments.json")
rosidl_write_generator_arguments(
"${generator_arguments_file}"
PACKAGE_NAME "${PROJECT_NAME}"
ROS_INTERFACE_FILES "${rosidl_generate_interfaces_IDL_FILES}"
ROS_INTERFACE_DEPENDENCIES "${_dependencies}"
OUTPUT_DIR "${_output_path}"
TEMPLATE_DIR "${micro_ros_agent_DEFAULT_PROFILES_DIR}"
TARGET_DEPENDENCIES ${target_dependencies}
ADDITIONAL_FILES ${_dds_idl_files}
)
# Execute python script
execute_process(
COMMAND ${PYTHON_EXECUTABLE} ${micro_ros_agent_BIN}
--generator-arguments-file "${generator_arguments_file}"
)
#Install
install(
DIRECTORY "${_output_path}/"
DESTINATION "../micrortps_agent/bin"
)
-14
View File
@@ -1,14 +0,0 @@
find_package(ament_cmake_core QUIET REQUIRED)
ament_register_extension(
"rosidl_generate_interfaces"
"micro_ros_agent"
"micrortps_agent_xml_generator.cmake")
set(micro_ros_agent_BIN "${micro_ros_agent_DIR}/../../../lib/micro_ros_agent/micro_ros_agent")
normalize_path(micro_ros_agent_BIN "${micro_ros_agent_BIN}")
set(micro_ros_agent_GENERATOR_FILES "${micro_ros_agent_DIR}/../../../@PYTHON_INSTALL_DIR@/micro_ros_agent/__init__.py")
normalize_path(micro_ros_agent_GENERATOR_FILES "${micro_ros_agent_GENERATOR_FILES}")
set(micro_ros_agent_DEFAULT_PROFILES_DIR "${micro_ros_agent_DIR}/../resource")
normalize_path(micro_ros_agent_DEFAULT_PROFILES_DIR "${micro_ros_agent_DEFAULT_PROFILES_DIR}")
+53
View File
@@ -0,0 +1,53 @@
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Changelog for package micro-ros_agent
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5.0.0 (2023-06-06)
------------------
* Add empty type key hash to GraphCache (`#189 <https://github.com/micro-ROS/micro-ROS-Agent/issues/189>`_)
* Contributors: Antonio Cuadros
4.0.2 (2022-09-28)
------------------
* Fix Datawriter destruction (`#169 <https://github.com/micro-ROS/micro-ROS-Agent/issues/169>`_) (`#170 <https://github.com/micro-ROS/micro-ROS-Agent/issues/170>`_)
* Synchronise predicate (`#160 <https://github.com/micro-ROS/micro-ROS-Agent/issues/160>`_) (`#165 <https://github.com/micro-ROS/micro-ROS-Agent/issues/165>`_)
4.0.1 (2022-06-13)
------------------
* Fix memory leak in graph manager (`#147 <https://github.com/micro-ROS/micro-ROS-Agent/issues/147>`_) (`#148 <https://github.com/micro-ROS/micro-ROS-Agent/issues/148>`_)
4.0.0 (2022-05-25)
------------------
3.0.1 (2022-03-25)
------------------
* Add services to graph manager (`#127 <https://github.com/micro-ROS/micro-ROS-Agent/issues/127>`_) (`#129 <https://github.com/micro-ROS/micro-ROS-Agent/issues/129>`_)
* Add used missing includes (`#116 <https://github.com/micro-ROS/micro-ROS-Agent/issues/116>`_) (`#124 <https://github.com/micro-ROS/micro-ROS-Agent/issues/124>`_)
* Add system logger flag (`#118 <https://github.com/micro-ROS/micro-ROS-Agent/issues/118>`_) (`#119 <https://github.com/micro-ROS/micro-ROS-Agent/issues/119>`_)
* Add condition variable include (`#113 <https://github.com/micro-ROS/micro-ROS-Agent/issues/113>`_) (`#114 <https://github.com/micro-ROS/micro-ROS-Agent/issues/114>`_)
* pass system name to xrceagent (`#110 <https://github.com/micro-ROS/micro-ROS-Agent/issues/110>`_) (`#112 <https://github.com/micro-ROS/micro-ROS-Agent/issues/112>`_)
* Fix memory leak in FastDDS datawriter (`#107 <https://github.com/micro-ROS/micro-ROS-Agent/issues/107>`_) (`#109 <https://github.com/micro-ROS/micro-ROS-Agent/issues/109>`_)
3.0.0 (2021-09-13)
------------------
1.0.1 (2021-09-13)
------------------
* Remove XRCE dependency and add superbuild (`#97 <https://github.com/micro-ROS/micro-ROS-Agent/issues/97>`_)
* Fixed launch file by using a list for arguments. Ensures order of items is kept. (`#93 <https://github.com/micro-ROS/micro-ROS-Agent/issues/93>`_) (`#94 <https://github.com/micro-ROS/micro-ROS-Agent/issues/94>`_)
* Modify argument type (`#91 <https://github.com/micro-ROS/micro-ROS-Agent/issues/91>`_)
* Fix graph manager datawriters behaviour (`#84 <https://github.com/micro-ROS/micro-ROS-Agent/issues/84>`_)
* Graph manager: Fix participant mask for listener callbacks (`#81 <https://github.com/micro-ROS/micro-ROS-Agent/issues/81>`_)
* Fix agent launch (`#78 <https://github.com/micro-ROS/micro-ROS-Agent/issues/78>`_)
* Fix graph manager node namespaces (`#75 <https://github.com/micro-ROS/micro-ROS-Agent/issues/75>`_)
* Fix Rolling agent (`#61 <https://github.com/micro-ROS/micro-ROS-Agent/issues/61>`_)
* Add multi domain graph manager (`#69 <https://github.com/micro-ROS/micro-ROS-Agent/issues/69>`_)
* Add ros2 launch capabilities and example launch file (`#47 <https://github.com/micro-ROS/micro-ROS-Agent/issues/47>`_)
* Snap build for the micro-ROS-Agent (`#43 <https://github.com/micro-ROS/micro-ROS-Agent/issues/43>`_)
* Create graph manager after checking passed CLI arguments and launch xrce-dds server (`#41 <https://github.com/micro-ROS/micro-ROS-Agent/issues/41>`_)
* Contributors: Antonio Cuadros, Jose Antonio Moral, Pablo Garrido, mergify[bot]
0.0.1 (2019-04-24)
-----------------
* Initial release
+270
View File
@@ -0,0 +1,270 @@
# Copyright 2018-present 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.
cmake_minimum_required(VERSION 3.5)
option(UROSAGENT_GENERATE_PROFILE
"Generates agent.refs according to the .msgs provided in the .repos" OFF
)
set(CMAKE_C_CLANG_TIDY clang-tidy -checks=*)
option(MICROROSAGENT_SUPERBUILD "Enable superbuild compilation." ON)
option(UAGENT_USE_SYSTEM_LOGGER "Force use of system installed spdlog logger on superbuild." OFF)
if(NOT MICROROSAGENT_SUPERBUILD)
project(micro_ros_agent LANGUAGES CXX)
else()
project(uagent_superbuild NONE)
include(${PROJECT_SOURCE_DIR}/cmake/SuperBuild.cmake)
return()
endif()
find_package(ament_cmake REQUIRED)
find_package(microxrcedds_agent REQUIRED)
find_package(rosidl_cmake REQUIRED)
find_package(fastcdr REQUIRED)
find_package(fastrtps REQUIRED)
find_package(fastrtps_cmake_module REQUIRED)
find_package(rmw_dds_common REQUIRED)
find_package(rmw REQUIRED)
find_package(rcutils REQUIRED)
find_package(rmw_fastrtps_shared_cpp REQUIRED)
find_package(ament_lint_auto REQUIRED)
find_package(rosidl_typesupport_fastrtps_cpp REQUIRED)
find_package(rosidl_runtime_cpp REQUIRED)
find_package(rosidl_typesupport_cpp REQUIRED)
find_package(ament_cmake_gtest REQUIRED)
find_package(micro_ros_msgs REQUIRED)
add_executable(${PROJECT_NAME}
src/main.cpp
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}
PRIVATE
include
)
ament_target_dependencies(${PROJECT_NAME}
rosidl_typesupport_fastrtps_cpp
rosidl_runtime_cpp
rosidl_typesupport_cpp
fastcdr
fastrtps
rmw_dds_common
rmw
rmw_fastrtps_shared_cpp
micro_ros_msgs
)
target_link_libraries(${PROJECT_NAME}
microxrcedds_agent
fastcdr
fastrtps
$<$<BOOL:$<PLATFORM_ID:Linux>>:rt>
$<$<BOOL:$<PLATFORM_ID:Linux>>:dl>
)
target_compile_options(${PROJECT_NAME}
PRIVATE
$<$<C_COMPILER_ID:GNU>:-Wall>
$<$<C_COMPILER_ID:GNU>:-Wextra>
$<$<C_COMPILER_ID:GNU>:-pedantic>
)
set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD
14
CXX_STANDARD_REQUIRED
YES
)
set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD
14
CXX_STANDARD_REQUIRED
YES
)
target_compile_options(${PROJECT_NAME}
PRIVATE
$<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>>:-Wall>
$<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>>:-Wextra>
$<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>>:-Wpedantic>
)
ament_export_dependencies(microxrcedds_agent)
ament_package()
install(
TARGETS
${PROJECT_NAME}
DESTINATION
lib/${PROJECT_NAME}
)
install(
DIRECTORY
launch
DESTINATION
share/${PROJECT_NAME}
)
if(UROSAGENT_GENERATE_PROFILE)
set(_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/python")
set(_XML_INTERFACE_GEN_BIN "${_OUTPUT_PATH}/bin/Xml_interface_gen.py")
normalize_path(_XML_INTERFACE_GEN_BIN "${_XML_INTERFACE_GEN_BIN}")
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 utils)
set(_RESOURCE_DIR "${_OUTPUT_PATH}/resource")
normalize_path(_RESOURCE_DIR "${_RESOURCE_DIR}")
set(_DEFAULT_FASTRTPS_PROFILES_PATH "${_OUTPUT_PATH}/gen/DEFAULT_FASTRTPS_PROFILES.xml")
normalize_path(_DEFAULT_FASTRTPS_PROFILES_PATH "${_DEFAULT_FASTRTPS_PROFILES_PATH}")
get_filename_component(_COLCON_CALL_DIR "${PROJECT_BINARY_DIR}" DIRECTORY)
get_filename_component(_COLCON_CALL_DIR "${_COLCON_CALL_DIR}" DIRECTORY)
set(_PYTHON_SCRIPT_HEAD
"import os
import sys
sys.path.append('${_OUTPUT_PATH}')
from ${_PYTHON_PKG_TOOL} import *
"
)
file(
COPY
"bin" "${_PYTHON_PKG_TOOL}" "resource"
DESTINATION
"${CMAKE_CURRENT_BINARY_DIR}/python"
)
execute_process(
COMMAND
"${PYTHON_EXECUTABLE}"
"-c"
"${_PYTHON_SCRIPT_HEAD}for package in GetInterfacePackages(GetPackageList('${_COLCON_CALL_DIR}')): print ('%s,%s' % (package, GetPackageName(package)))"
OUTPUT_VARIABLE
_packages
RESULT_VARIABLE
_result
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT _result EQUAL 0)
message(FATAL_ERROR "Error finding XML packages")
endif()
string(REPLACE "\n" ";" _packages ${_packages})
set(ALL_MSG_FILES "")
foreach(package ${_packages})
string(REPLACE "," ";" package ${package})
list(GET package 0 package_file)
list(GET package 1 package)
execute_process(
COMMAND
"${PYTHON_EXECUTABLE}"
"-c"
"${_PYTHON_SCRIPT_HEAD}for msg in GetInterfacePackageMsgs('${package_file}'): print ('%s' % msg)"
OUTPUT_VARIABLE
${package}_MSG_FILES
RESULT_VARIABLE
_result
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if(NOT _result EQUAL 0)
message(FATAL_ERROR "Error finding .msg files")
endif()
if(${package}_MSG_FILES STREQUAL "")
continue()
endif()
string(REPLACE "\n" ";" ${package}_MSG_FILES ${${package}_MSG_FILES})
endforeach()
execute_process(
COMMAND
"${PYTHON_EXECUTABLE}" "${_XML_DEFAULT_READ_BIN}" "--default-xml-path" "${_RESOURCE_DIR}"
OUTPUT_VARIABLE
_XmlDoc
RESULT_VARIABLE
_result
)
if(NOT _result EQUAL 0)
message(FATAL_ERROR "Error in typesupport generation")
endif()
foreach(package ${_packages})
string(REPLACE "," ";" package ${package})
list(GET package 0 package_file)
list(GET package 1 package)
if(${package}_MSG_FILES STREQUAL "")
continue()
endif()
set(generator_arguments_file "${_OUTPUT_PATH}/XML_ArgFiles/${package}_Args.json")
rosidl_write_generator_arguments(
"${generator_arguments_file}"
PACKAGE_NAME "${package}"
ROS_INTERFACE_FILES "${${package}_MSG_FILES}"
ROS_INTERFACE_DEPENDENCIES "NULL"
OUTPUT_DIR "NULL"
TEMPLATE_DIR "NULL"
TARGET_DEPENDENCIES "NULL"
ADDITIONAL_FILES ""
)
execute_process(
COMMAND
"${PYTHON_EXECUTABLE}" "${_XML_INTERFACE_GEN_BIN}" --generator-arguments-file "${generator_arguments_file}"
OUTPUT_VARIABLE
_XmlGen
RESULT_VARIABLE
_result
)
if(NOT _result EQUAL 0)
message(FATAL_ERROR "Error in typesupport generation")
endif()
set(_XmlDoc "${_XmlDoc}${_XmlGen}")
endforeach()
set (_XmlDoc "<profiles>\n${_XmlDoc}</profiles>\n")
file(WRITE "${_DEFAULT_FASTRTPS_PROFILES_PATH}" "${_XmlDoc}")
endif()
+31
View File
@@ -0,0 +1,31 @@
# Micro ROS Agent
## Overview
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/).
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.
The node interacts with DDS Global Data Space on behalf of the Micro-ROS nodes.
## Package features
### XML generation
During the build process, the package looks for all ROS 2 messages to generate an initial list of XML profiles.
These profiles can are referenced in the Agent-Client communication to avoid sending the full XML content.
This reference mechanism can be switched on and off from the Micro XRCE-DDS middleware layer.
### Agent-Client communication mechanism
Communication between the Micro-ROS Agent and the Micro-ROS nodes supports two types of transport:
- UDP.
- SerialPort.
All available configurations are supported directly by the Micro XRCE-DDS agent.
For further information on how to configure the agent click [here](TODO).
-241
View File
@@ -1,241 +0,0 @@
# Copyright 2016-2018 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.
import struct
import os
import sys
if os.name == 'nt':
import win32con
import win32file
import pywintypes
__overlapped = pywintypes.OVERLAPPED()
elif os.name == 'posix':
import fcntl
else:
raise RuntimeError('PortaLocker only defined for nt and posix platforms')
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_cmake import expand_template
from rosidl_cmake import extract_message_types
from rosidl_cmake import get_newest_modification_time
from rosidl_parser import parse_message_file
from rosidl_parser import parse_service_file
from rosidl_parser import validate_field_types
from shutil import copyfile
from pathlib import Path
def generate_micro_ros_agent_xml_support(args):
pkg_name = args['package_name']
known_msg_types = extract_message_types(
pkg_name, args['ros_interface_files'], args.get('ros_interface_dependencies', []))
functions = {
'get_header_filename_from_msg_name': convert_camel_case_to_lower_case_underscore,
}
# Set file format
file_format = ".xml"
ros2_prefix = "rt/"
# Check destination dir
dest_dir = args['output_dir']
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
# Check source dir
srcs_dir = os.path.join(dest_dir, "srcs")
if not os.path.exists(srcs_dir):
os.makedirs(srcs_dir)
# Copy all included xml files
for filename in os.listdir(args['template_dir']):
if filename.endswith(file_format):
template_src_path = os.path.join(args['template_dir'], filename)
template_dest_path = os.path.join(srcs_dir, filename)
if not os.path.isfile(template_dest_path):
copyfile(template_src_path, template_dest_path)
# Iterate throw all msgs/srvs
for idl_file in args['ros_interface_files']:
extension = os.path.splitext(idl_file)[1]
if extension == '.msg':
spec = parse_message_file(pkg_name, idl_file)
validate_field_types(spec, known_msg_types)
subfolder = os.path.basename(os.path.dirname(idl_file))
data = {
'spec': spec,
'pkg': spec.base_type.pkg_name,
'msg': spec.msg_name,
'type': spec.base_type.type,
'subfolder': subfolder,
}
data.update(functions)
# Generate source file path
src_file = os.path.join(srcs_dir, "%s_%s_%s.xml" % (spec.base_type.pkg_name, subfolder, spec.msg_name))
# Publisher
file_content = " <publisher profile_name=\"%s_%s_%s_p\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <topic profile_name=\"%s_%s_%s_t\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <kind>NO_KEY</kind>\n"
file_content += " <name>%s%s_%s_%s</name>\n" % (ros2_prefix, spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <dataType>%s::%s::dds_::%s_</dataType>\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <historyQos>\n"
file_content += " <kind>KEEP_LAST</kind>\n"
file_content += " <depth>5</depth>\n"
file_content += " </historyQos>\n"
file_content += " <durability>\n"
file_content += " <kind>TRANSIENT_LOCAL</kind>\n"
file_content += " </durability>\n"
file_content += " </topic>\n"
file_content += " </publisher>\n"
# Subscriber
file_content += " <subscriber profile_name=\"%s_%s_%s_s\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <topic profile_name=\"%s_%s_%s_t\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <kind>NO_KEY</kind>\n"
file_content += " <name>%s%s_%s_%s</name>\n" % (ros2_prefix, spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <dataType>%s::%s::dds_::%s_</dataType>\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <historyQos>\n"
file_content += " <kind>KEEP_LAST</kind>\n"
file_content += " <depth>5</depth>\n"
file_content += " </historyQos>\n"
file_content += " <durability>\n"
file_content += " <kind>TRANSIENT_LOCAL</kind>\n"
file_content += " </durability>\n"
file_content += " </topic>\n"
file_content += " </subscriber>\n"
# Topic
file_content += " <topic profile_name=\"%s_%s_%s_t\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <name>%s%s_%s_%s</name>\n" % (ros2_prefix, spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <dataType>%s::%s::dds_::%s_</dataType>\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " </topic>\n"
# Write file content
fd1 = open(src_file, "w")
if os.name == 'nt':
# Lock
hfile1 = win32file._get_osfhandle(fd1.fileno())
win32file.LockFileEx(hfile1, win32con.LOCKFILE_EXCLUSIVE_LOCK, 0, -0x10000, __overlapped)
# Write
fd1.write(file_content)
# Unlock
win32file.UnlockFileEx(hfile1, 0, -0x10000, __overlapped)
elif os.name == 'posix':
# Lock
fcntl.flock(fd1.fileno(), fcntl.LOCK_EX)
# Write
fd1.write(file_content)
# Unlock
fcntl.flock(fd1.fileno(), fcntl.LOCK_UN)
fd1.close()
# Open collect file
collec_file = os.path.join(args['output_dir'], "DEFAULT_FASTRTPS_PROFILES.xml")
fd2 = open(collec_file, "w")
if os.name == 'nt':
# Lock
hfile2 = win32file._get_osfhandle(fd2.fileno())
win32file.LockFileEx(hfile2, win32con.LOCKFILE_EXCLUSIVE_LOCK, 0, -0x10000, __overlapped)
# Generate head
fd2.write("<profiles>\n")
# Append all files contents
for filename in os.listdir(srcs_dir):
if filename.endswith(".xml"):
# Open
fd3 = open(os.path.join(srcs_dir, filename), "r+")
# Lock
hfile3 = win32file._get_osfhandle(fd3.fileno())
win32file.LockFileEx(hfile3, win32con.LOCKFILE_EXCLUSIVE_LOCK, 0, -0x10000, __overlapped)
# Write
fd2.write(fd3.read())
# Unlock
win32file.UnlockFileEx(hfile3, 0, -0x10000, __overlapped)
fd3.close()
# Generate tail
fd2.write("</profiles>\n")
# UnLock
win32file.UnlockFileEx(hfile2, 0, -0x10000, __overlapped)
elif os.name == 'posix':
# Lock
fcntl.flock(fd2.fileno(), fcntl.LOCK_EX)
# Generate head
fd2.write("<profiles>\n")
# Append all files contents
for filename in os.listdir(srcs_dir):
if filename.endswith(".xml"):
# Open
fd3 = open(os.path.join(srcs_dir, filename), "r+")
# Lock
fcntl.flock(fd3, fcntl.LOCK_EX)
# Write
fd2.write(fd3.read())
# Unlock
fcntl.flock(fd3.fileno(), fcntl.LOCK_UN)
# Close
fd3.close()
# Generate tail
fd2.write("</profiles>\n")
# UnLock
fcntl.flock(fd2.fileno(), fcntl.LOCK_UN)
# Close file
fd2.close()
#elif extension == '.srv':
#data = {'spec': spec}
#data.update(functions)
#if not os.path.exists(args['output_dir']):
# os.makedirs(args['output_dir'])
#f = open(os.path.join(args['output_dir'], 'demofile.txt'), 'w+')
#f.write("%s\n" % spec)
#f.close()
return 0
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env python3
import argparse
import os
import sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)),'..'))
from rosidl_cmake import read_generator_arguments
from rosidl_adapter.parser import UnknownMessageType
from micro_ros_agent import generate_XML
def main(argv=sys.argv[1:]):
parser = argparse.ArgumentParser(
description='Generate the C interfaces for Micro RTPS.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument(
'--generator-arguments-file',
required=True,
help='The location of the file containing the generator arguments')
args = parser.parse_args(argv)
generator_args = read_generator_arguments(args.generator_arguments_file)
rc = generate_XML(generator_args)
return rc
if __name__ == '__main__':
sys.exit(main())
@@ -0,0 +1,26 @@
#!/usr/bin/env python3
import os
import sys
import argparse
import xml.etree.ElementTree
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)),'..'))
from micro_ros_agent import *
def main(argv=sys.argv[1:]):
parser = argparse.ArgumentParser(
description='Import default xml files',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument(
'--default-xml-path',
required=True,
help='The location of the default profiles')
args = parser.parse_args(argv)
ReadDefaultXMLs(args.default_xml_path)
return 0
if __name__ == '__main__':
sys.exit(main())
+68
View File
@@ -0,0 +1,68 @@
# Copyright 2019 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.
include(ExternalProject)
unset(_deps)
enable_language(C)
enable_language(CXX)
unset(xrceagent_DIR CACHE)
find_package(xrceagent 2 EXACT QUIET)
if(NOT xrceagent_FOUND)
ExternalProject_Add(xrceagent
GIT_REPOSITORY
https://github.com/eProsima/Micro-XRCE-DDS-Agent.git
GIT_TAG
ros2
PREFIX
${PROJECT_BINARY_DIR}/agent
INSTALL_DIR
${CMAKE_INSTALL_PREFIX}
CMAKE_CACHE_ARGS
-DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER}
-DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER}
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}
-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}
-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS}
-DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS}
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-DCMAKE_PREFIX_PATH:PATH=<INSTALL_DIR>
-DCMAKE_SYSTEM_NAME:STRING=${CMAKE_SYSTEM_NAME}
-DUAGENT_USE_SYSTEM_FASTDDS:BOOL=ON
-DUAGENT_USE_SYSTEM_FASTCDR:BOOL=ON
-DUAGENT_USE_SYSTEM_LOGGER:BOOL=${UAGENT_USE_SYSTEM_LOGGER}
-DUAGENT_CED_PROFILE:BOOL=OFF
-DUAGENT_P2P_PROFILE:BOOL=OFF
-DUAGENT_BUILD_EXECUTABLE:BOOL=OFF
-DUAGENT_ISOLATED_INSTALL:BOOL=OFF
)
endif()
# Main project.
ExternalProject_Add(micro_ros_agent
SOURCE_DIR
${PROJECT_SOURCE_DIR}
BINARY_DIR
${CMAKE_CURRENT_BINARY_DIR}
CMAKE_CACHE_ARGS
-DMICROROSAGENT_SUPERBUILD:BOOL=OFF
INSTALL_COMMAND
""
DEPENDS
xrceagent
)
+55
View File
@@ -0,0 +1,55 @@
// Copyright 2020 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.
#ifndef _UROS_AGENT_AGENT_HPP
#define _UROS_AGENT_AGENT_HPP
#include <uxr/agent/AgentInstance.hpp>
#include <uxr/agent/middleware/Middleware.hpp>
#include <uxr/agent/middleware/utils/Callbacks.hpp>
#include <agent/graph_manager/graph_manager.hpp>
#include <map>
#include <memory>
// TODO(jamoralp): class Documentation
namespace uros {
namespace agent {
class Agent
{
public:
Agent();
~Agent() = default;
bool create(
int argc,
char** argv);
void run();
private:
eprosima::uxr::AgentInstance& xrce_dds_agent_instance_;
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);
};
} // namespace agent
} // namespace uros
#endif // _UROS_AGENT_AGENT_HPP
@@ -0,0 +1,316 @@
// Copyright 2020 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.
#ifndef _UROS_AGENT_GRAPH_MANAGER_HPP
#define _UROS_AGENT_GRAPH_MANAGER_HPP
#include "fastrtps/Domain.h"
#include <fastrtps/TopicDataType.h>
#include "fastrtps/attributes/ParticipantAttributes.h"
#include "fastrtps/participant/Participant.h"
#include "fastrtps/participant/ParticipantListener.h"
#include "fastrtps/attributes/PublisherAttributes.h"
#include "fastrtps/publisher/Publisher.h"
#include <fastrtps/publisher/PublisherListener.h>
#include <fastrtps/rtps/common/MatchingInfo.h>
#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
#include <fastdds/dds/domain/DomainParticipantListener.hpp>
#include <fastdds/dds/domain/qos/DomainParticipantQos.hpp>
#include <fastdds/dds/publisher/DataWriter.hpp>
#include <fastdds/dds/publisher/qos/DataWriterQos.hpp>
#include <fastdds/dds/publisher/Publisher.hpp>
#include <fastdds/dds/subscriber/DataReader.hpp>
#include <fastdds/dds/subscriber/qos/DataReaderQos.hpp>
#include <fastdds/dds/subscriber/SampleInfo.hpp>
#include <fastdds/dds/subscriber/Subscriber.hpp>
#include <fastdds/dds/subscriber/DataReaderListener.hpp>
#include "rmw/types.h"
#include "rmw/names_and_types.h"
#include "rmw/impl/cpp/key_value.hpp"
#include "rmw_dds_common/graph_cache.hpp"
#include "rmw_fastrtps_shared_cpp/create_rmw_gid.hpp"
#include "rmw_fastrtps_shared_cpp/qos.hpp"
#include "rcutils/types.h"
#include "rcutils/types/string_array.h"
#include "rosidl_typesupport_cpp/message_type_support.hpp"
#include "rosidl_typesupport_fastrtps_cpp/message_type_support.h"
#include "rmw_dds_common/msg/participant_entities_info.hpp"
#include "micro_ros_msgs/msg/graph.hpp"
#include "micro_ros_msgs/msg/node.hpp"
#include "micro_ros_msgs/msg/entity.hpp"
#include <uxr/agent/types/XRCETypes.hpp>
#include <agent/graph_manager/graph_typesupport.hpp>
#include <agent/utils/demangle.hpp>
#include <condition_variable>
#include <string>
#include <memory>
#include <map>
namespace uros {
namespace agent {
namespace graph_manager {
/**
* @brief Class that keeps track of the existing entities in the ROS 2 world,
* both coming from micro-ROS or from external ROS 2 applications.
*/
class GraphManager
{
public:
/**
* @brief Default constructor.
*/
GraphManager(eprosima::fastdds::dds::DomainId_t domain_id);
/**
* @brief Default destructor.
*/
~GraphManager() = default;
/**
* @brief Implementation of the notification logic that updates the micro-ROS graph.
*/
void publish_microros_graph();
/**
* @brief Adds a DDS participant to the graph tree.
* @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::fastdds::dds::DomainParticipant* participant,
bool from_microros = true,
const std::string& enclave = "/");
/**
* @brief Removes a DDS participant from the graph tree.
* @param participant eprosima::fastdds::dds::DomainParticipant to be removed.
*/
void remove_participant(
const eprosima::fastdds::dds::DomainParticipant* participant,
bool from_microros = true);
/**
* @brief Getter for the graph cache.
* @return Reference to inner graph cache
*/
rmw_dds_common::GraphCache& get_graph_cache() { return graphCache_; }
/**
* @brief Adds a DDS datawriter to the graph tree.
* @param datawriter_guid rtps::GUID_t of the datawriter to be added.
* @param participant Pointer to the participant which owns this datawriter.
* @param datawriter Pointer to the datawriter to be added.
*/
void add_datawriter(
const eprosima::fastrtps::rtps::GUID_t& datawriter_guid,
const eprosima::fastdds::dds::DomainParticipant* participant,
const eprosima::fastdds::dds::DataWriter* datawriter);
/**
* @brief Adds a DDS datawriter to the graph tree.
* @param datawriter_guid rtps::GUID_t of the datawriter to be added.
* @param topic_name Name of the topic to which the datawriter sends information to.
* @param type_name Type name of the sent topic.
* @param participant_guid rtps::GUID_t of the participant which owns this datawriter.
* @param writer_qos QOS of the datawriter to be included into the graph tree.
*/
void add_datawriter(
const eprosima::fastrtps::rtps::GUID_t& datawriter_guid,
const std::string& topic_name,
const std::string& type_name,
const eprosima::fastrtps::rtps::GUID_t& participant_guid,
const eprosima::fastdds::dds::DataWriterQos& writer_qos);
/**
* @brief Removes a DDS datawriter from the graph tree.
* @param datawriter_guid rtps::GUID_t of the datawriter to be removed.
*/
void remove_datawriter(
const eprosima::fastrtps::rtps::GUID_t& datawriter_guid);
/**
* @brief Adds a DDS datareader to the graph tree.
* @param datareader_guid rtps::GUID_t of the datareader to be added.
* @param participant Pointer to the participant which owns this datareader.
* @param datareader Pointer to the datareader to be added.
*/
void add_datareader(
const eprosima::fastrtps::rtps::GUID_t& datareader_guid,
const eprosima::fastdds::dds::DomainParticipant* participant,
const eprosima::fastdds::dds::DataReader* datareader);
/**
* @brief Adds a DDS datareader to the graph tree.
* @param datareader_guid rtps::GUID_t of the datareader to be added.
* @param topic_name Name of the topic to which the datareader sends information to.
* @param type_name Type name of the sent topic.
* @param participant_guid rtps::GUID_t of the participant which owns this datareader.
* @param writer_qos QOS of the datareader to be included into the graph tree.
*/
void add_datareader(
const eprosima::fastrtps::rtps::GUID_t& datareader_guid,
const std::string& topic_name,
const std::string& type_name,
const eprosima::fastrtps::rtps::GUID_t& participant_guid,
const eprosima::fastdds::dds::DataReaderQos& reader_qos);
/**
* @brief Removes a DDS datareader from the graph tree.
* @param datareader_guid rtps::GUID_t of the datareader to be removed.
*/
void remove_datareader(
const eprosima::fastrtps::rtps::GUID_t& datareader_guid);
/**
* @brief Associates a certain DDS entity with a provided participant.
* @param guid rtps::GUID_t identifier of the entity.
* @param participant Participant to be associated with.
* @param entity_kind Kind of the DDS entity.
*/
void associate_entity(
const eprosima::fastrtps::rtps::GUID_t& entity_guid,
const eprosima::fastdds::dds::DomainParticipant* participant,
const dds::xrce::ObjectKind& entity_kind);
private:
/**
* @brief Implementation of FastDDS' DomainParticipantListener abstract class.
*/
class ParticipantListener : public eprosima::fastdds::dds::DomainParticipantListener
{
public:
/**
* @brief Constructor.
* @param graph_manager Pointer to the GraphManager object which owns this ParticipantListener.
*/
ParticipantListener(
GraphManager* graph_manager);
private:
template <typename Info>
void process_discovery_info(
const Info& proxyData);
void on_participant_discovery(
eprosima::fastdds::dds::DomainParticipant* participant,
eprosima::fastrtps::rtps::ParticipantDiscoveryInfo&& info) override;
void on_subscriber_discovery(
eprosima::fastdds::dds::DomainParticipant* /*participant*/,
eprosima::fastrtps::rtps::ReaderDiscoveryInfo&& info) override;
void on_publisher_discovery(
eprosima::fastdds::dds::DomainParticipant* /*participant*/,
eprosima::fastrtps::rtps::WriterDiscoveryInfo&& info) override;
GraphManager* graphManager_from_;
};
/**
* @brief Implementation of FastDDS' DomainReaderListener abstract class.
*/
class DatareaderListener : public eprosima::fastdds::dds::DataReaderListener
{
public:
/**
* @brief Constructor.
* @param graph_manager Pointer to the GraphManager object which owns this DataReaderListener.
*/
DatareaderListener(
GraphManager* graph_manager);
private:
void on_data_available(
eprosima::fastdds::dds::DataReader* /*sub*/) override;
GraphManager* graphManager_from_;
};
/**
* @brief Convert FastDDS QOS object instance to RMW instance.
* @param fastdds_qos QOS instance to be converted.
* @returns RMW object representation of the given FastDDS QOS.
*/
template <typename FastDDSQos>
const rmw_qos_profile_t fastdds_qos_to_rmw_qos(
const FastDDSQos& fastdds_qos);
/**
* @brief Update micro-ROS graph information upon new data
* received in the 'ros_discovery_info' topic.
*/
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);
eprosima::fastdds::dds::DomainId_t domain_id_;
bool graph_changed_;
bool display_on_change_;
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_;
std::unique_ptr<eprosima::fastdds::dds::TypeSupport> participant_info_typesupport_;
std::unique_ptr<eprosima::fastdds::dds::TypeSupport> microros_graph_info_typesupport_;
std::unique_ptr<eprosima::fastdds::dds::DomainParticipant> participant_;
std::unique_ptr<eprosima::fastdds::dds::Publisher> publisher_;
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_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*,
eprosima::fastdds::dds::DataWriter*
> micro_ros_graph_datawriters_;
};
} // namespace graph_manager
} // namespace agent
} // namespace uros
#endif // _UROS_AGENT_GRAPH_MANAGER_HPP
@@ -0,0 +1,127 @@
// Copyright 2020 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.
#ifndef UROS_AGENT_GRAPH_PARTICIPANTS_TYPESUPPORT_HPP_
#define UROS_AGENT_GRAPH_PARTICIPANTS_TYPESUPPORT_HPP_
#include "fastrtps/Domain.h"
#include <fastrtps/TopicDataType.h>
#include "fastrtps/attributes/ParticipantAttributes.h"
#include "fastrtps/participant/Participant.h"
#include "fastrtps/participant/ParticipantListener.h"
#include "fastrtps/attributes/PublisherAttributes.h"
#include "fastrtps/publisher/Publisher.h"
#include <fastrtps/publisher/PublisherListener.h>
#include <fastrtps/rtps/common/MatchingInfo.h>
#include <fastdds/dds/domain/DomainParticipant.hpp>
#include <fastdds/dds/domain/qos/DomainParticipantQos.hpp>
#include "rmw/types.h"
#include "rmw/impl/cpp/key_value.hpp"
#include "rmw_dds_common/graph_cache.hpp"
#include "rmw_fastrtps_shared_cpp/create_rmw_gid.hpp"
#include "rmw_fastrtps_shared_cpp/qos.hpp"
#include "rcutils/types.h"
#include "rosidl_typesupport_cpp/message_type_support.hpp"
#include "rosidl_typesupport_fastrtps_cpp/message_type_support.h"
#include "rmw_dds_common/msg/participant_entities_info.hpp"
#include "micro_ros_msgs/msg/graph.hpp"
namespace uros {
namespace agent {
namespace graph_manager {
/**
* @brief Implementation of virtual class eprosima::fastdds::dds::TopicDataType.
* Is used to gather and send information about the entities present within a DDS domain,
* in the Agent's context.
*/
class ParticipantEntitiesInfoTypeSupport : public eprosima::fastdds::dds::TopicDataType
{
public:
ParticipantEntitiesInfoTypeSupport();
virtual bool serialize(
void* data,
eprosima::fastrtps::rtps::SerializedPayload_t* payload) override;
virtual bool deserialize(
eprosima::fastrtps::rtps::SerializedPayload_t* payload,
void* data) override;
virtual std::function<uint32_t()> getSerializedSizeProvider(
void* data) override;
virtual void* createData() override;
virtual void deleteData(void* data) override;
virtual bool getKey(
void* data,
eprosima::fastrtps::rtps::InstanceHandle_t* handle,
bool force_md5) override;
private:
const message_type_support_callbacks_t* callbacks_;
const rosidl_message_type_support_t* type_support_;
};
/**
* @brief Implementation of virtual class eprosima::fastdds::dds::TopicDataType.
* Is used to send graph information to Micro-ROS.
*/
class MicrorosGraphInfoTypeSupport : public eprosima::fastdds::dds::TopicDataType
{
public:
MicrorosGraphInfoTypeSupport();
virtual bool serialize(
void* data,
eprosima::fastrtps::rtps::SerializedPayload_t* payload) override;
virtual bool deserialize(
eprosima::fastrtps::rtps::SerializedPayload_t* payload,
void* data) override;
virtual std::function<uint32_t()> getSerializedSizeProvider(
void* data) override;
virtual void* createData() override;
virtual void deleteData(void* data) override;
virtual bool getKey(
void* data,
eprosima::fastrtps::rtps::InstanceHandle_t* handle,
bool force_md5) override;
private:
const message_type_support_callbacks_t* callbacks_;
const rosidl_message_type_support_t* type_support_;
};
} // namespace graph_manager
} // namespace agent
} // namespace uros
#endif // UROS_AGENT_GRAPH_PARTICIPANTS_TYPESUPPORT_HPP_
@@ -0,0 +1,125 @@
// Copyright 2020 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.
#ifndef UROS_AGENT_UTILS_DEMANGLE_HPP_
#define UROS_AGENT_UTILS_DEMANGLE_HPP_
#include <string>
namespace uros {
namespace agent {
namespace utils {
class Demangle
{
private:
/**
* @brief Default constructor. Creating instances of this class is not allowed.
*/
Demangle() = default;
/**
* @brief Default destructor.
*/
~Demangle() = default;
/**
* @brief Demangle service name for a given topic, prefix and service suffix,
* if the topic is part of a service; otherwise, return blank.
* @param prefix The ROS service prefix.
* @param topic_name Topic to be demangled.
* @param suffix The ROS service suffix.
* @returns The demangled service name.
*/
static std::string _demangle_service_from_topic(
const std::string& prefix,
const std::string& topic_name,
const std::string& suffix);
public:
/**
* @brief Demangle if passed topic is a ROS topic; otherwise, keep it intact.
* @param topic_name Topic to be demangled.
* @returns The demangled topic.
*/
static std::string demangle_if_ros_topic(
const std::string& topic_name);
/**
* @brief Demangle if passed type is a ROS type; otherwise, keep it intact.
* @param dds_type_string Type to be demangled.
* @returns The demangled type.
*/
static std::string demangle_if_ros_type(
const std::string& dds_type_string);
/**
* @brief Demangle topic name for a given topic if it is part of one;
* otherwise, return empty.
* @param topic_name Topic to be demangled.
* @returns The demangled topic name.
*/
static std::string demangle_ros_topic_from_topic(
const std::string& topic_name);
/**
* @brief Demangle the service name for a given topic if it is part of a service;
* otherwise, return empty.
* @param topic_name Topic to be demangled.
* @returns The demangled service name.
*/
static std::string demangle_service_from_topic(
const std::string& topic_name);
/**
* @brief Demangle the service name for a given topic if it is part
* of a service request; otherwise, return empty.
* @param topic_name Topic to be demangled.
* @returns The demangled service request name.
*/
static std::string demangle_service_request_from_topic(
const std::string& topic_name);
/**
* @brief Demangle the service name for a given topic if it is part
* of a service reply; otherwise, return empty.
* @param topic_name Topic to be demangled.
* @returns The demangled service reply name.
*/
static std::string demangle_service_reply_from_topic(
const std::string& topic_name);
/**
* @brief Demangle the service type name if it is a ROS srv type; otherwise, return empty.
* @param dds_type_name Type to be demangled.
* @returns The demangled service type.
*/
static std::string demangle_service_type_only(
const std::string& dds_type_name);
/**
* @brief Generic demangle function, used when ROS names are not mangled.
* @param name Generic name to be demangled.
* @returns The demangled name.
*/
static std::string identity_demangle(
const std::string& name);
};
} // namespace utils
} // namespace agent
} // namespace uros
#endif // UROS_AGENT_UTILS_DEMANGLE_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"]
)
])
+35
View File
@@ -0,0 +1,35 @@
<?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>micro_ros_agent</name>
<version>5.0.0</version>
<description>micro-ROS Agent package</description>
<maintainer email="pablogarrido@eprosima.com">Pablo Garrido</maintainer>
<maintainer email="antoniocuadros@eprosima.com">Antonio Cuadros</maintainer>
<license>Apache License 2.0</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<test_depend>rosidl_default_generators</test_depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<depend>rmw</depend>
<depend>rcutils</depend>
<depend>rmw_fastrtps_shared_cpp</depend>
<depend>rmw_dds_common</depend>
<depend>micro_ros_msgs</depend>
<test_depend>rosidl_typesupport_fastrtps_cpp</test_depend>
<test_depend>ament_cmake_gtest</test_depend>
<test_depend>builtin_interfaces</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
+24
View File
@@ -0,0 +1,24 @@
<participant profile_name="participant_profile">
<rtps>
<name>participant_profile</name>
</rtps>
</participant>
<data_writer profile_name="shapetype_data_writer">
<topic>
<kind>WITH_KEY</kind>
<name>Square</name>
<dataType>ShapeType</dataType>
</topic>
</data_writer>
<data_reader profile_name="shapetype_data_reader">
<topic>
<kind>WITH_KEY</kind>
<name>Square</name>
<dataType>ShapeType</dataType>
</topic>
</data_reader>
<topic profile_name="shapetype_topic">
<kind>WITH_KEY</kind>
<name>Square</name>
<dataType>ShapeType</dataType>
</topic>
+29
View File
@@ -0,0 +1,29 @@
<topic profile_name="parameter_events_t">
<name>rt/parameter_events</name>
<dataType>rcl_interfaces::msg::dds_::ParameterEvent_</dataType>
</topic>
<topic profile_name="clock_t">
<name>rt/clock</name>
<dataType>rosgraph_msgs::msg::dds_::Clock_</dataType>
</topic>
<data_writer profile_name="parameter_events_p">
<topic>
<kind>NO_KEY</kind>
<name>rt/parameter_events</name>
<dataType>rcl_interfaces::msg::dds_::ParameterEvent_</dataType>
</topic>
</data_writer>
<data_reader profile_name="clock_s">
<topic>
<kind>NO_KEY</kind>
<name>rt/clock</name>
<dataType>rosgraph_msgs::msg::dds_::Clock_</dataType>
</topic>
</data_reader>
<data_reader profile_name="parameter_events_s">
<topic>
<kind>NO_KEY</kind>
<name>rt/parameter_events</name>
<dataType>rcl_interfaces::msg::dds_::ParameterEvent_</dataType>
</topic>
</data_reader>
+313
View File
@@ -0,0 +1,313 @@
// Copyright 2020 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.
#ifndef _UROS_AGENT_AGENT_CPP
#define _UROS_AGENT_AGENT_CPP
#include <agent/Agent.hpp>
#include <utility>
#include <memory>
namespace uros {
namespace agent {
Agent::Agent()
: xrce_dds_agent_instance_(xrce_dds_agent_instance_.getInstance())
{
}
bool Agent::create(
int argc,
char** argv)
{
bool result = xrce_dds_agent_instance_.create(argc, argv);
if (result)
{
/**
* Add CREATE_PARTICIPANT callback.
*/
std::function<void (
const eprosima::fastdds::dds::DomainParticipant *)> on_create_participant
([&](
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(
eprosima::uxr::Middleware::Kind::FASTDDS,
eprosima::uxr::middleware::CallbackKind::CREATE_PARTICIPANT,
std::move(on_create_participant));
/**
* Add REMOVE_PARTICIPANT callback.
*/
std::function<void (
const eprosima::fastdds::dds::DomainParticipant *)> on_delete_participant
([&](
const eprosima::fastdds::dds::DomainParticipant* participant) -> void
{
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,
eprosima::uxr::middleware::CallbackKind::DELETE_PARTICIPANT,
std::move(on_delete_participant));
/**
* Add CREATE_DATAWRITER callback.
*/
std::function<void (
const eprosima::fastdds::dds::DomainParticipant *,
const eprosima::fastdds::dds::DataWriter *)> on_create_datawriter
([&](
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());
graph_manager_->add_datawriter(datawriter->guid(), participant, datawriter);
graph_manager_->associate_entity(
datawriter->guid(), participant, dds::xrce::OBJK_DATAWRITER);
});
xrce_dds_agent_instance_.add_middleware_callback(
eprosima::uxr::Middleware::Kind::FASTDDS,
eprosima::uxr::middleware::CallbackKind::CREATE_DATAWRITER,
std::move(on_create_datawriter));
/**
* Add DELETE_DATAWRITER callback.
*/
std::function<void (
const eprosima::fastdds::dds::DomainParticipant *,
const eprosima::fastdds::dds::DataWriter *)> on_delete_datawriter
([&](
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());
graph_manager_->remove_datawriter(datawriter->guid());
});
xrce_dds_agent_instance_.add_middleware_callback(
eprosima::uxr::Middleware::Kind::FASTDDS,
eprosima::uxr::middleware::CallbackKind::DELETE_DATAWRITER,
std::move(on_delete_datawriter));
/**
* Add CREATE_DATAREADER callback.
*/
std::function<void (
const eprosima::fastdds::dds::DomainParticipant *,
const eprosima::fastdds::dds::DataReader*)> on_create_datareader
([&](
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();
const eprosima::fastrtps::rtps::GUID_t datareader_guid =
eprosima::fastrtps::rtps::iHandle2GUID(instance_handle);
graph_manager_->add_datareader(datareader_guid, participant, datareader);
graph_manager_->associate_entity(
datareader_guid, participant, dds::xrce::OBJK_DATAREADER);
});
xrce_dds_agent_instance_.add_middleware_callback(
eprosima::uxr::Middleware::Kind::FASTDDS,
eprosima::uxr::middleware::CallbackKind::CREATE_DATAREADER,
std::move(on_create_datareader));
/**
* Add DELETE_DATAREADER callback.
*/
std::function<void (
const eprosima::fastdds::dds::DomainParticipant *,
const eprosima::fastdds::dds::DataReader *)> on_delete_datareader
([&](
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();
const eprosima::fastrtps::rtps::GUID_t datareader_guid =
eprosima::fastrtps::rtps::iHandle2GUID(instance_handle);
graph_manager_->remove_datareader(datareader_guid);
});
xrce_dds_agent_instance_.add_middleware_callback(
eprosima::uxr::Middleware::Kind::FASTDDS,
eprosima::uxr::middleware::CallbackKind::DELETE_DATAREADER,
std::move(on_delete_datareader));
/**
* Add CREATE_REQUESTER callback.
*/
std::function<void (
const eprosima::fastdds::dds::DomainParticipant *,
const eprosima::fastdds::dds::DataWriter *,
const eprosima::fastdds::dds::DataReader *)> on_create_requester
([&](
const eprosima::fastdds::dds::DomainParticipant* participant,
const eprosima::fastdds::dds::DataWriter* datawriter,
const eprosima::fastdds::dds::DataReader * datareader) -> void
{
auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
graph_manager_->add_datawriter(datawriter->guid(), participant, datawriter);
graph_manager_->associate_entity(
datawriter->guid(), participant, dds::xrce::OBJK_DATAWRITER);
// TODO(pablogs): Workaround for Fast-DDS bug #9977. Remove when fixed
const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
datareader->get_instance_handle();
const eprosima::fastrtps::rtps::GUID_t datareader_guid =
eprosima::fastrtps::rtps::iHandle2GUID(instance_handle);
graph_manager_->add_datareader(datareader_guid, participant, datareader);
graph_manager_->associate_entity(
datareader_guid, participant, dds::xrce::OBJK_DATAREADER);
});
xrce_dds_agent_instance_.add_middleware_callback(
eprosima::uxr::Middleware::Kind::FASTDDS,
eprosima::uxr::middleware::CallbackKind::CREATE_REQUESTER,
std::move(on_create_requester));
/**
* Add DELETE_REQUESTER callback.
*/
std::function<void (
const eprosima::fastdds::dds::DomainParticipant *,
const eprosima::fastdds::dds::DataWriter *,
const eprosima::fastdds::dds::DataReader *)> on_delete_requester
([&](
const eprosima::fastdds::dds::DomainParticipant* participant,
const eprosima::fastdds::dds::DataWriter* datawriter,
const eprosima::fastdds::dds::DataReader * datareader) -> void
{
auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
graph_manager_->remove_datawriter(datawriter->guid());
// TODO(pablogs): Workaround for Fast-DDS bug #9977. Remove when fixed
const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
datareader->get_instance_handle();
const eprosima::fastrtps::rtps::GUID_t datareader_guid =
eprosima::fastrtps::rtps::iHandle2GUID(instance_handle);
graph_manager_->remove_datareader(datareader_guid);
});
xrce_dds_agent_instance_.add_middleware_callback(
eprosima::uxr::Middleware::Kind::FASTDDS,
eprosima::uxr::middleware::CallbackKind::DELETE_REQUESTER,
std::move(on_delete_requester));
/**
* Add CREATE_REPLIER callback.
*/
std::function<void (
const eprosima::fastdds::dds::DomainParticipant *,
const eprosima::fastdds::dds::DataWriter *,
const eprosima::fastdds::dds::DataReader *)> on_create_replier
([&](
const eprosima::fastdds::dds::DomainParticipant* participant,
const eprosima::fastdds::dds::DataWriter* datawriter,
const eprosima::fastdds::dds::DataReader * datareader) -> void
{
auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
graph_manager_->add_datawriter(datawriter->guid(), participant, datawriter);
graph_manager_->associate_entity(
datawriter->guid(), participant, dds::xrce::OBJK_DATAWRITER);
// TODO(pablogs): Workaround for Fast-DDS bug #9977. Remove when fixed
const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
datareader->get_instance_handle();
const eprosima::fastrtps::rtps::GUID_t datareader_guid =
eprosima::fastrtps::rtps::iHandle2GUID(instance_handle);
graph_manager_->add_datareader(datareader_guid, participant, datareader);
graph_manager_->associate_entity(
datareader_guid, participant, dds::xrce::OBJK_DATAREADER);
});
xrce_dds_agent_instance_.add_middleware_callback(
eprosima::uxr::Middleware::Kind::FASTDDS,
eprosima::uxr::middleware::CallbackKind::CREATE_REPLIER,
std::move(on_create_replier));
/**
* Add DELETE_REPLIER callback.
*/
std::function<void (
const eprosima::fastdds::dds::DomainParticipant *,
const eprosima::fastdds::dds::DataWriter *,
const eprosima::fastdds::dds::DataReader *)> on_delete_replier
([&](
const eprosima::fastdds::dds::DomainParticipant* participant,
const eprosima::fastdds::dds::DataWriter* datawriter,
const eprosima::fastdds::dds::DataReader * datareader) -> void
{
auto graph_manager_ = find_or_create_graph_manager(participant->get_domain_id());
graph_manager_->remove_datawriter(datawriter->guid());
// TODO(pablogs): Workaround for Fast-DDS bug #9977. Remove when fixed
const eprosima::fastrtps::rtps::InstanceHandle_t instance_handle =
datareader->get_instance_handle();
const eprosima::fastrtps::rtps::GUID_t datareader_guid =
eprosima::fastrtps::rtps::iHandle2GUID(instance_handle);
graph_manager_->remove_datareader(datareader_guid);
});
xrce_dds_agent_instance_.add_middleware_callback(
eprosima::uxr::Middleware::Kind::FASTDDS,
eprosima::uxr::middleware::CallbackKind::DELETE_REPLIER,
std::move(on_delete_replier));
}
return result;
}
void Agent::run()
{
return xrce_dds_agent_instance_.run();
}
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
@@ -0,0 +1,773 @@
// Copyright 2020 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.
#ifndef _UROS_AGENT_GRAPH_MANAGER_CPP
#define _UROS_AGENT_GRAPH_MANAGER_CPP
#include <agent/graph_manager/graph_manager.hpp>
#include <memory>
#include <string>
#include <utility>
#include <vector>
namespace uros {
namespace agent {
namespace graph_manager {
GraphManager::GraphManager(eprosima::fastdds::dds::DomainId_t domain_id)
: domain_id_(domain_id)
, graph_changed_(false)
, display_on_change_(false)
, mtx_()
, cv_()
, graphCache_()
, participant_listener_(std::make_unique<ParticipantListener>(this))
, datareader_listener_(std::make_unique<DatareaderListener>(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()))
{
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();
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);
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(), par_mask));
// Register participant within 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));
// Create subscriber
subscriber_.reset(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_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));
// Create datawriters
datawriter_qos_ =
eprosima::fastdds::dds::DATAWRITER_QOS_DEFAULT;
datawriter_qos_.history().kind =
eprosima::fastdds::dds::HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS;
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 =
eprosima::fastdds::dds::PublishModeQosPolicyKind::ASYNCHRONOUS_PUBLISH_MODE;
datawriter_qos_.reliability().kind =
eprosima::fastdds::dds::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS;
datawriter_qos_.durability().kind =
eprosima::fastdds::dds::DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS;
eprosima::fastdds::dds::DataWriterQos ros_to_microros_datawriter_qos_ = datawriter_qos_;
ros_to_microros_datawriter_qos_.history().kind =
eprosima::fastdds::dds::HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS;
ros_to_microros_graph_datawriter_.reset(
publisher_->create_datawriter(ros_to_microros_graph_topic_.get(), ros_to_microros_datawriter_qos_));
// Create datareaders
eprosima::fastdds::dds::DataReaderQos datareader_qos =
eprosima::fastdds::dds::DATAREADER_QOS_DEFAULT;
datareader_qos.history().kind =
eprosima::fastdds::dds::HistoryQosPolicyKind::KEEP_LAST_HISTORY_QOS;
datareader_qos.history().depth = 1;
datareader_qos.endpoint().history_memory_policy =
eprosima::fastrtps::rtps::MemoryManagementPolicy::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;
datareader_qos.reliability().kind =
eprosima::fastdds::dds::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS;
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()));
// Set graph cache on change callback function
graphCache_.set_on_change_callback([this]()
{
{
std::unique_lock<std::mutex> lock(this->mtx_);
this->graph_changed_ = true;
}
this->cv_.notify_one();
});
microros_graph_publisher_ = std::thread(&GraphManager::publish_microros_graph, this);
}
inline void GraphManager::publish_microros_graph()
{
while (true)
{
{
std::unique_lock<std::mutex> lock(mtx_);
cv_.wait(lock, [this]()
{
return this->graph_changed_;
});
graph_changed_ = false;
}
if (display_on_change_)
{
std::cout << "Updated uros Graph: graph changed" << std::endl;
std::cout << graphCache_ << std::endl;
}
micro_ros_msgs::msg::Graph graph_message;
rcutils_string_array_t node_names = rcutils_get_zero_initialized_string_array();
rcutils_string_array_t node_namespaces = rcutils_get_zero_initialized_string_array();
rcutils_allocator_t allocator = rcutils_get_default_allocator();
graphCache_.get_node_names(&node_names, &node_namespaces, nullptr, &allocator);
for (size_t i = 0; i < node_names.size; ++i)
{
const std::string node_name(node_names.data[i]);
const std::string node_namespace(node_namespaces.data[i]);
micro_ros_msgs::msg::Node node_message;
node_message.node_namespace = std::move(node_namespace);
node_message.node_name = std::move(node_name);
// Get publishers info
rmw_names_and_types_t writer_names_and_types =
rmw_get_zero_initialized_names_and_types();
if (RMW_RET_OK != graphCache_.get_writer_names_and_types_by_node(node_name, node_namespace,
uros::agent::utils::Demangle::demangle_ros_topic_from_topic,
uros::agent::utils::Demangle::demangle_if_ros_type,
&allocator, &writer_names_and_types))
{
break;
}
for (size_t i = 0; i < writer_names_and_types.names.size; ++i)
{
micro_ros_msgs::msg::Entity entity_message;
entity_message.entity_type = micro_ros_msgs::msg::Entity::PUBLISHER;
entity_message.name = std::move(std::string(writer_names_and_types.names.data[i]));
for (size_t j = 0; j < writer_names_and_types.types[i].size; ++j)
{
entity_message.types.emplace_back(writer_names_and_types.types[i].data[j]);
}
node_message.entities.emplace_back(std::move(entity_message));
}
// Get subscribers info
rmw_names_and_types_t reader_names_and_types =
rmw_get_zero_initialized_names_and_types();
if (RMW_RET_OK != graphCache_.get_reader_names_and_types_by_node(node_name, node_namespace,
uros::agent::utils::Demangle::demangle_ros_topic_from_topic,
uros::agent::utils::Demangle::demangle_if_ros_type,
&allocator, &reader_names_and_types))
{
break;
}
for (size_t i = 0; i < reader_names_and_types.names.size; ++i)
{
micro_ros_msgs::msg::Entity entity_message;
entity_message.entity_type = micro_ros_msgs::msg::Entity::SUBSCRIBER;
entity_message.name = std::move(std::string(reader_names_and_types.names.data[i]));
for (size_t j = 0; j < reader_names_and_types.types[i].size; ++j)
{
entity_message.types.emplace_back(reader_names_and_types.types[i].data[j]);
}
node_message.entities.emplace_back(std::move(entity_message));
}
// Get services
//// Get servers
rmw_names_and_types_t service_server_names_and_types =
rmw_get_zero_initialized_names_and_types();
if (RMW_RET_OK != graphCache_.get_names_and_types(
uros::agent::utils::Demangle::demangle_service_request_from_topic,
uros::agent::utils::Demangle::demangle_service_type_only,
&allocator, &service_server_names_and_types))
{
break;
}
for (size_t i = 0; i < service_server_names_and_types.names.size; ++i)
{
micro_ros_msgs::msg::Entity entity_message;
entity_message.entity_type = micro_ros_msgs::msg::Entity::SERVICE_SERVER;
entity_message.name = std::move(std::string(service_server_names_and_types.names.data[i]));
for (size_t j = 0; j < service_server_names_and_types.types[i].size; ++j)
{
entity_message.types.emplace_back(service_server_names_and_types.types[i].data[j]);
}
node_message.entities.emplace_back(std::move(entity_message));
}
//// Get clients
rmw_names_and_types_t service_client_names_and_types =
rmw_get_zero_initialized_names_and_types();
if (RMW_RET_OK != graphCache_.get_names_and_types(
uros::agent::utils::Demangle::demangle_service_reply_from_topic,
uros::agent::utils::Demangle::demangle_service_type_only,
&allocator, &service_client_names_and_types))
{
break;
}
for (size_t i = 0; i < service_client_names_and_types.names.size; ++i)
{
micro_ros_msgs::msg::Entity entity_message;
entity_message.entity_type = micro_ros_msgs::msg::Entity::SERVICE_CLIENT;
entity_message.name = std::move(std::string(service_client_names_and_types.names.data[i]));
for (size_t j = 0; j < service_client_names_and_types.types[i].size; ++j)
{
entity_message.types.emplace_back(service_client_names_and_types.types[i].data[j]);
}
node_message.entities.emplace_back(std::move(entity_message));
}
graph_message.nodes.emplace_back(std::move(node_message));
if (RMW_RET_OK != rmw_names_and_types_fini(&writer_names_and_types) ||
RMW_RET_OK != rmw_names_and_types_fini(&reader_names_and_types) ||
RMW_RET_OK != rmw_names_and_types_fini(&service_server_names_and_types) ||
RMW_RET_OK != rmw_names_and_types_fini(&service_client_names_and_types))
{
std::cerr << "Problem while freeing resources in Micro-ROS Graph Manager"
<< ", file: '" << __FILE__ << "', line: '" << __LINE__ << "'." << std::endl;
return;
}
}
ros_to_microros_graph_datawriter_->write(static_cast<void *>(&graph_message));
if (RCUTILS_RET_OK != rcutils_string_array_fini(&node_names) ||
RCUTILS_RET_OK != rcutils_string_array_fini(&node_namespaces))
{
std::cerr << "Problem while freeing resources in Micro-ROS Graph Manager"
<< ", file: '" << __FILE__ << "', line: '" << __LINE__ << "'." << std::endl;
break;
}
}
}
void GraphManager::add_participant(
const eprosima::fastdds::dds::DomainParticipant* participant,
bool from_microros,
const std::string& enclave)
{
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);
// 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, isolated_node_name, isolated_namespace);
auto it = micro_ros_graph_datawriters_.find(participant);
if (it == micro_ros_graph_datawriters_.end())
{
// Create datawriter
eprosima::fastdds::dds::DataWriter * datawriter = publisher_->create_datawriter(ros_discovery_topic_.get(), datawriter_qos_);
it = micro_ros_graph_datawriters_.insert(
std::make_pair(participant, datawriter)).first;
}
it->second->write(static_cast<void *>(&info));
}
}
void GraphManager::remove_participant(
const eprosima::fastdds::dds::DomainParticipant* participant,
bool from_microros)
{
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));
publisher_->delete_datawriter(it->second);
micro_ros_graph_datawriters_.erase(participant);
}
}
void GraphManager::add_datawriter(
const eprosima::fastrtps::rtps::GUID_t& datawriter_guid,
const eprosima::fastdds::dds::DomainParticipant* participant,
const eprosima::fastdds::dds::DataWriter* datawriter)
{
const std::string& topic_name = datawriter->get_topic()->get_name();
const std::string& type_name = datawriter->get_topic()->get_type_name();
this->add_datawriter(datawriter_guid, topic_name, type_name,
participant->guid(), datawriter->get_qos());
}
void GraphManager::add_datawriter(
const eprosima::fastrtps::rtps::GUID_t& datawriter_guid,
const std::string& topic_name,
const std::string& type_name,
const eprosima::fastrtps::rtps::GUID_t& participant_guid,
const eprosima::fastdds::dds::DataWriterQos& writer_qos)
{
const rmw_gid_t datawriter_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
"rmw_fastrtps_cpp", datawriter_guid);
const rmw_gid_t participant_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
"rmw_fastrtps_cpp", participant_guid);
const rmw_qos_profile_t qos_profile = fastdds_qos_to_rmw_qos(writer_qos);
graphCache_.add_entity(datawriter_gid, topic_name, type_name,
rosidl_get_zero_initialized_type_hash(), participant_gid, qos_profile, false);
}
void GraphManager::remove_datawriter(
const eprosima::fastrtps::rtps::GUID_t& datawriter_guid)
{
const rmw_gid_t datawriter_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
"rmw_fastrtps_cpp", datawriter_guid);
graphCache_.remove_entity(datawriter_gid, false);
}
void GraphManager::add_datareader(
const eprosima::fastrtps::rtps::GUID_t& datareader_guid,
const eprosima::fastdds::dds::DomainParticipant* participant,
const eprosima::fastdds::dds::DataReader* datareader)
{
const std::string& topic_name = datareader->get_topicdescription()->get_name();
const std::string& type_name = datareader->get_topicdescription()->get_type_name();
this->add_datareader(datareader_guid, topic_name, type_name,
participant->guid(), datareader->get_qos());
}
void GraphManager::add_datareader(
const eprosima::fastrtps::rtps::GUID_t& datareader_guid,
const std::string& topic_name,
const std::string& type_name,
const eprosima::fastrtps::rtps::GUID_t& participant_guid,
const eprosima::fastdds::dds::DataReaderQos& reader_qos)
{
const rmw_gid_t datareader_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
"rmw_fastrtps_cpp", datareader_guid);
const rmw_gid_t participant_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
"rmw_fastrtps_cpp", participant_guid);
const rmw_qos_profile_t qos_profile = fastdds_qos_to_rmw_qos(reader_qos);
// TODO(acuadros95): Use typesupport to calculate type hash on micro-ROS and save and get it from reader_qos.user_data.
// Related PRs:
// https://github.com/ros2/rmw_dds_common/pull/70
// https://github.com/ros2/rmw_fastrtps/pull/671
// https://github.com/ros2/rmw_fastrtps/pull/680
graphCache_.add_entity(datareader_gid, topic_name, type_name,
rosidl_get_zero_initialized_type_hash(), participant_gid, qos_profile, true);
}
void GraphManager::remove_datareader(
const eprosima::fastrtps::rtps::GUID_t& datareader_guid)
{
const rmw_gid_t datareader_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
"rmw_fastrtps_cpp", datareader_guid);
graphCache_.remove_entity(datareader_gid, true);
}
void GraphManager::associate_entity(
const eprosima::fastrtps::rtps::GUID_t& entity_guid,
const eprosima::fastdds::dds::DomainParticipant* participant,
const dds::xrce::ObjectKind& entity_kind)
{
const rmw_gid_t entity_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
"rmw_fastrtps_cpp", entity_guid);
const rmw_gid_t participant_gid = rmw_fastrtps_shared_cpp::create_rmw_gid(
"rmw_fastrtps_cpp", participant->guid());
eprosima::fastdds::dds::DomainParticipantQos qos = participant->get_qos();
rmw_dds_common::msg::ParticipantEntitiesInfo info;
switch (entity_kind)
{
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, 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, isolated_node_name, isolated_namespace);
break;
}
default:
{
break;
}
}
auto it = micro_ros_graph_datawriters_.find(participant);
it->second->write(static_cast<void *>(&info));
}
template <typename FastDDSQos>
const rmw_qos_profile_t GraphManager::fastdds_qos_to_rmw_qos(
const FastDDSQos& fastdds_qos)
{
rmw_qos_profile_t rmw_qos = rmw_qos_profile_unknown;
switch (fastdds_qos.reliability().kind)
{
case eprosima::fastdds::dds::ReliabilityQosPolicyKind::BEST_EFFORT_RELIABILITY_QOS:
{
rmw_qos.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
break;
}
case eprosima::fastdds::dds::ReliabilityQosPolicyKind::RELIABLE_RELIABILITY_QOS:
{
rmw_qos.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
break;
}
default:
{
rmw_qos.reliability = RMW_QOS_POLICY_RELIABILITY_UNKNOWN;
break;
}
}
switch (fastdds_qos.durability().kind)
{
case eprosima::fastdds::dds::DurabilityQosPolicyKind::TRANSIENT_LOCAL_DURABILITY_QOS:
{
rmw_qos.durability = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
break;
}
case eprosima::fastdds::dds::DurabilityQosPolicyKind::VOLATILE_DURABILITY_QOS:
{
rmw_qos.durability = RMW_QOS_POLICY_DURABILITY_VOLATILE;
break;
}
default:
{
rmw_qos.durability = RMW_QOS_POLICY_DURABILITY_UNKNOWN;
break;
}
}
rmw_qos.deadline.sec = fastdds_qos.deadline().period.seconds;
rmw_qos.deadline.nsec = fastdds_qos.deadline().period.nanosec;
rmw_qos.lifespan.sec = fastdds_qos.lifespan().duration.seconds;
rmw_qos.lifespan.nsec = fastdds_qos.lifespan().duration.nanosec;
switch (fastdds_qos.liveliness().kind)
{
case eprosima::fastdds::dds::LivelinessQosPolicyKind::AUTOMATIC_LIVELINESS_QOS:
{
rmw_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC;
break;
}
case eprosima::fastdds::dds::LivelinessQosPolicyKind::MANUAL_BY_TOPIC_LIVELINESS_QOS:
{
rmw_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC;
break;
}
default:
{
rmw_qos.liveliness = RMW_QOS_POLICY_LIVELINESS_UNKNOWN;
break;
}
}
rmw_qos.liveliness_lease_duration.sec = fastdds_qos.liveliness().lease_duration.seconds;
rmw_qos.liveliness_lease_duration.nsec = fastdds_qos.liveliness().lease_duration.nanosec;
return rmw_qos;
}
void GraphManager::update_node_entities_info()
{
rmw_dds_common::msg::ParticipantEntitiesInfo entities_info;
eprosima::fastdds::dds::SampleInfo sample_info;
if (ros_discovery_datareader_->take_next_sample(&entities_info, &sample_info) ==
eprosima::fastrtps::types::ReturnCode_t::RETCODE_OK)
{
if (sample_info.instance_state == eprosima::fastdds::dds::InstanceStateKind::ALIVE_INSTANCE_STATE)
{
graphCache_.update_participant_entities(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()
, graphManager_from_(graph_manager)
{
}
void GraphManager::ParticipantListener::on_participant_discovery(
eprosima::fastdds::dds::DomainParticipant* /* participant */,
eprosima::fastrtps::rtps::ParticipantDiscoveryInfo&& info)
{
switch (info.status)
{
case eprosima::fastrtps::rtps::ParticipantDiscoveryInfo::DISCOVERED_PARTICIPANT:
{
auto map = rmw::impl::cpp::parse_key_value(info.info.m_userData);
auto name_found = map.find("enclave");
if (map.end() == name_found)
{
return;
}
const std::string enclave =
std::string(name_found->second.begin(), name_found->second.end());
const rmw_gid_t gid = rmw_fastrtps_shared_cpp::create_rmw_gid("rmw_fastrtps_cpp", info.info.m_guid);
graphManager_from_->get_graph_cache().add_participant(gid, enclave);
break;
}
case eprosima::fastrtps::rtps::ParticipantDiscoveryInfo::REMOVED_PARTICIPANT:
case eprosima::fastrtps::rtps::ParticipantDiscoveryInfo::DROPPED_PARTICIPANT:
{
const rmw_gid_t gid = rmw_fastrtps_shared_cpp::create_rmw_gid("rmw_fastrtps_cpp", info.info.m_guid);
graphManager_from_->get_graph_cache().remove_participant(gid);
break;
}
default:
{
break;
}
}
}
static eprosima::fastdds::dds::DataWriterQos writer_qos_conversion(
const eprosima::fastdds::dds::WriterQos& writer_qos)
{
eprosima::fastdds::dds::DataWriterQos datawriter_qos;
datawriter_qos.durability(writer_qos.m_durability);
datawriter_qos.durability_service(writer_qos.m_durabilityService);
datawriter_qos.deadline(writer_qos.m_deadline);
datawriter_qos.latency_budget(writer_qos.m_latencyBudget);
datawriter_qos.liveliness(writer_qos.m_liveliness);
datawriter_qos.reliability(writer_qos.m_reliability);
datawriter_qos.destination_order(writer_qos.m_destinationOrder);
datawriter_qos.lifespan(writer_qos.m_lifespan);
datawriter_qos.user_data(writer_qos.m_userData);
datawriter_qos.ownership(writer_qos.m_ownership);
datawriter_qos.ownership_strength(writer_qos.m_ownershipStrength);
datawriter_qos.publish_mode(writer_qos.m_publishMode);
datawriter_qos.representation(writer_qos.representation);
datawriter_qos.data_sharing(writer_qos.data_sharing);
return datawriter_qos;
}
static eprosima::fastdds::dds::DataReaderQos reader_qos_conversion(
const eprosima::fastdds::dds::ReaderQos& reader_qos)
{
eprosima::fastdds::dds::DataReaderQos datareader_qos;
datareader_qos.durability(reader_qos.m_durability);
datareader_qos.deadline(reader_qos.m_deadline);
datareader_qos.latency_budget(reader_qos.m_latencyBudget);
datareader_qos.liveliness(reader_qos.m_liveliness);
datareader_qos.reliability(reader_qos.m_reliability);
datareader_qos.destination_order(reader_qos.m_destinationOrder);
datareader_qos.user_data(reader_qos.m_userData);
datareader_qos.ownership(reader_qos.m_ownership);
datareader_qos.time_based_filter(reader_qos.m_timeBasedFilter);
datareader_qos.lifespan(reader_qos.m_lifespan);
datareader_qos.durability_service(reader_qos.m_durabilityService);
eprosima::fastdds::dds::TypeConsistencyQos consistency;
consistency.type_consistency = reader_qos.type_consistency;
datareader_qos.type_consistency(consistency);
datareader_qos.data_sharing(reader_qos.data_sharing);
return datareader_qos;
}
template <>
void GraphManager::ParticipantListener::process_discovery_info<eprosima::fastrtps::rtps::ReaderDiscoveryInfo>(
const eprosima::fastrtps::rtps::ReaderDiscoveryInfo& reader_info)
{
switch (reader_info.status)
{
case eprosima::fastrtps::rtps::ReaderDiscoveryInfo::CHANGED_QOS_READER:
{
return;
}
case eprosima::fastrtps::rtps::ReaderDiscoveryInfo::DISCOVERED_READER:
{
const std::string topic_name = reader_info.info.topicName().to_string();
const std::string type_name = reader_info.info.typeName().to_string();
graphManager_from_->add_datareader(reader_info.info.guid(), topic_name, type_name,
iHandle2GUID(reader_info.info.RTPSParticipantKey()), reader_qos_conversion(reader_info.info.m_qos));
break;
}
default:
{
graphManager_from_->remove_datareader(reader_info.info.guid());
break;
}
}
}
template <>
void GraphManager::ParticipantListener::process_discovery_info<eprosima::fastrtps::rtps::WriterDiscoveryInfo>(
const eprosima::fastrtps::rtps::WriterDiscoveryInfo& writer_info)
{
switch (writer_info.status)
{
case eprosima::fastrtps::rtps::WriterDiscoveryInfo::CHANGED_QOS_WRITER:
{
return;
}
case eprosima::fastrtps::rtps::WriterDiscoveryInfo::DISCOVERED_WRITER:
{
const std::string topic_name = writer_info.info.topicName().to_string();
const std::string type_name = writer_info.info.typeName().to_string();
graphManager_from_->add_datawriter(writer_info.info.guid(), topic_name, type_name,
iHandle2GUID(writer_info.info.RTPSParticipantKey()), writer_qos_conversion(writer_info.info.m_qos));
break;
}
default:
{
graphManager_from_->remove_datawriter(writer_info.info.guid());
break;
}
}
}
void GraphManager::ParticipantListener::on_subscriber_discovery(
eprosima::fastdds::dds::DomainParticipant* /*participant*/,
eprosima::fastrtps::rtps::ReaderDiscoveryInfo&& info)
{
process_discovery_info<eprosima::fastrtps::rtps::ReaderDiscoveryInfo>(info);
}
void GraphManager::ParticipantListener::on_publisher_discovery(
eprosima::fastdds::dds::DomainParticipant* /*participant*/,
eprosima::fastrtps::rtps::WriterDiscoveryInfo&& info)
{
process_discovery_info<eprosima::fastrtps::rtps::WriterDiscoveryInfo>(info);
}
GraphManager::DatareaderListener::DatareaderListener(
GraphManager* graph_manager)
: eprosima::fastdds::dds::DataReaderListener()
, graphManager_from_(graph_manager)
{
}
void GraphManager::DatareaderListener::on_data_available(
eprosima::fastdds::dds::DataReader* /*sub*/)
{
graphManager_from_->update_node_entities_info();
}
} // namespace graph_manager
} // namespace agent
} // namespace uros
#endif // _UROS_AGENT_GRAPH_MANAGER_CPP
@@ -0,0 +1,213 @@
// Copyright 2020 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.
#ifndef UROS_AGENT_GRAPH_PARTICIPANTS_TYPESUPPORT_CPP_
#define UROS_AGENT_GRAPH_PARTICIPANTS_TYPESUPPORT_CPP_
#include <agent/graph_manager/graph_typesupport.hpp>
#include <string>
namespace uros {
namespace agent {
namespace graph_manager {
ParticipantEntitiesInfoTypeSupport::ParticipantEntitiesInfoTypeSupport()
: TopicDataType()
{
type_support_ = rosidl_typesupport_cpp::get_message_type_support_handle<
rmw_dds_common::msg::ParticipantEntitiesInfo>();
type_support_ = get_message_typesupport_handle(type_support_,
"rosidl_typesupport_fastrtps_cpp");
callbacks_ = static_cast<const message_type_support_callbacks_t *>(type_support_->data);
std::ostringstream ss;
const std::string message_namespace(callbacks_->message_namespace_);
const std::string message_name(callbacks_->message_name_);
if (!message_namespace.empty())
{
ss << message_namespace << "::";
}
ss << "dds_::" << message_name << "_";
this->setName(ss.str().c_str());
char full_bounded;
m_typeSize = 4 + callbacks_->max_serialized_size(full_bounded);
}
bool ParticipantEntitiesInfoTypeSupport::serialize(
void * data,
eprosima::fastrtps::rtps::SerializedPayload_t * payload)
{
eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast<char *>(payload->data),
payload->max_size);
eprosima::fastcdr::Cdr scdr(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN,
eprosima::fastcdr::Cdr::DDS_CDR);
scdr.serialize_encapsulation();
if (callbacks_->cdr_serialize(data, scdr))
{
payload->encapsulation = (scdr.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS) ?
CDR_BE : CDR_LE;
payload->length = static_cast<uint32_t>(scdr.getSerializedDataLength());
return true;
}
else
{
return false;
}
}
bool ParticipantEntitiesInfoTypeSupport::deserialize(
eprosima::fastrtps::rtps::SerializedPayload_t * payload,
void * data)
{
eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast<char *>(payload->data),
payload->length);
eprosima::fastcdr::Cdr dcdr(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN,
eprosima::fastcdr::Cdr::DDS_CDR);
dcdr.read_encapsulation();
return callbacks_->cdr_deserialize(dcdr, data);
}
std::function<uint32_t()> ParticipantEntitiesInfoTypeSupport::getSerializedSizeProvider(
void * data)
{
return [data, this]() -> uint32_t
{
return static_cast<uint32_t>(4 + callbacks_->get_serialized_size(data));
};
}
void * ParticipantEntitiesInfoTypeSupport::createData()
{
return static_cast<void *>(nullptr);
}
void ParticipantEntitiesInfoTypeSupport::deleteData(
void * data)
{
(void) data;
}
bool ParticipantEntitiesInfoTypeSupport::getKey(
void * data,
eprosima::fastrtps::rtps::InstanceHandle_t * handle,
bool force_md5)
{
(void) data;
(void) handle;
(void) force_md5;
return m_isGetKeyDefined;
}
MicrorosGraphInfoTypeSupport::MicrorosGraphInfoTypeSupport()
: TopicDataType()
{
type_support_ = rosidl_typesupport_cpp::get_message_type_support_handle<
micro_ros_msgs::msg::Graph>();
type_support_ = get_message_typesupport_handle(type_support_,
"rosidl_typesupport_fastrtps_cpp");
callbacks_ = static_cast<const message_type_support_callbacks_t *>(type_support_->data);
std::ostringstream ss;
const std::string message_namespace(callbacks_->message_namespace_);
const std::string message_name(callbacks_->message_name_);
if (!message_namespace.empty())
{
ss << message_namespace << "::";
}
ss << "dds_::" << message_name << "_";
this->setName(ss.str().c_str());
char full_bounded;
m_typeSize = 4 + callbacks_->max_serialized_size(full_bounded);
}
bool MicrorosGraphInfoTypeSupport::serialize(
void * data,
eprosima::fastrtps::rtps::SerializedPayload_t * payload)
{
eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast<char *>(payload->data),
payload->max_size);
eprosima::fastcdr::Cdr scdr(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN,
eprosima::fastcdr::Cdr::DDS_CDR);
scdr.serialize_encapsulation();
if (callbacks_->cdr_serialize(data, scdr))
{
payload->encapsulation = (scdr.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS) ?
CDR_BE : CDR_LE;
payload->length = static_cast<uint32_t>(scdr.getSerializedDataLength());
return true;
}
else
{
return false;
}
}
bool MicrorosGraphInfoTypeSupport::deserialize(
eprosima::fastrtps::rtps::SerializedPayload_t * payload,
void * data)
{
eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast<char *>(payload->data),
payload->length);
eprosima::fastcdr::Cdr dcdr(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN,
eprosima::fastcdr::Cdr::DDS_CDR);
dcdr.read_encapsulation();
return callbacks_->cdr_deserialize(dcdr, data);
}
std::function<uint32_t()> MicrorosGraphInfoTypeSupport::getSerializedSizeProvider(
void * data)
{
return [data, this]() -> uint32_t
{
return static_cast<uint32_t>(4 + callbacks_->get_serialized_size(data));
};
}
void * MicrorosGraphInfoTypeSupport::createData()
{
return static_cast<void *>(nullptr);
}
void MicrorosGraphInfoTypeSupport::deleteData(
void * data)
{
(void) data;
}
bool MicrorosGraphInfoTypeSupport::getKey(
void * data,
eprosima::fastrtps::rtps::InstanceHandle_t * handle,
bool force_md5)
{
(void) data;
(void) handle;
(void) force_md5;
return m_isGetKeyDefined;
}
} // namespace graph_manager
} // namespace agent
} // namespace uros
#endif // UROS_AGENT_GRAPH_PARTICIPANTS_TYPESUPPORT_CPP_
@@ -0,0 +1,191 @@
// Copyright 2020 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.
#ifndef UROS_AGENT_UTILS_DEMANGLE_CPP_
#define UROS_AGENT_UTILS_DEMANGLE_CPP_
#include <algorithm>
#include <string>
#include <vector>
#include <rcpputils/find_and_replace.hpp>
#include <rcutils/logging_macros.h>
#include <rcutils/types.h>
#include <rmw_fastrtps_shared_cpp/namespace_prefix.hpp>
#include <agent/utils/demangle.hpp>
namespace uros {
namespace agent {
namespace utils {
std::string Demangle::demangle_if_ros_topic(
const std::string& topic_name)
{
return _strip_ros_prefix_if_exists(topic_name);
}
std::string Demangle::demangle_if_ros_type(
const std::string& dds_type_string)
{
if ('_' != dds_type_string[dds_type_string.size() - 1])
{
// not a ROS type
return dds_type_string;
}
const std::string dds_prefix("dds_::");
size_t dds_prefix_pos = dds_type_string.find(dds_prefix);
if (std::string::npos == dds_prefix_pos)
{
// not a ROS type
return dds_type_string;
}
std::string type_namespace = dds_type_string.substr(0, dds_prefix_pos);
type_namespace = rcpputils::find_and_replace(type_namespace, "::", "/");
size_t start = dds_prefix_pos + dds_prefix.size();
const std::string type_name =
dds_type_string.substr(start, dds_type_string.length() - start - 1);
return type_namespace + type_name;
}
std::string Demangle::demangle_ros_topic_from_topic(
const std::string& topic_name)
{
return _resolve_prefix(topic_name, ros_topic_prefix);
}
std::string Demangle::_demangle_service_from_topic(
const std::string& prefix,
const std::string& topic_name,
const std::string& suffix)
{
const std::string service_name = _resolve_prefix(topic_name, prefix);
if (service_name.empty())
{
return std::string();
}
size_t suffix_position = service_name.rfind(suffix);
if (std::string::npos == suffix_position)
{
RCUTILS_LOG_WARN_NAMED(
"rmw_fastrtps_shared_cpp",
"service topic has prefix but no suffix; report this: '%s'",
topic_name.c_str());
return std::string();
}
else
{
if (0 != (service_name.length() - suffix_position - suffix.length()))
{
RCUTILS_LOG_WARN_NAMED(
"rmw_fastrtps_shared_cpp",
"service topic has service prefix and a suffix"
", but not at the end; report this: '%s'",
topic_name.c_str());
return std::string();
}
}
return service_name.substr(0, suffix_position);
}
std::string Demangle::demangle_service_from_topic(
const std::string& topic_name)
{
const std::string demangled_topic = demangle_service_reply_from_topic(topic_name);
if (!demangled_topic.empty())
{
return demangled_topic;
}
return demangle_service_request_from_topic(topic_name);
}
std::string Demangle::demangle_service_request_from_topic(
const std::string& topic_name)
{
return _demangle_service_from_topic(ros_service_requester_prefix, topic_name, "Request");
}
std::string Demangle::demangle_service_reply_from_topic(
const std::string& topic_name)
{
return _demangle_service_from_topic(ros_service_response_prefix, topic_name, "Reply");
}
std::string Demangle::demangle_service_type_only(
const std::string& dds_type_name)
{
const std::string dds_prefix("dds_::");
auto suffixes = {std::string("_Response_"), std::string("_Request_")};
size_t dds_prefix_pos = dds_type_name.find(dds_prefix);
// Perform checks
if (std::string::npos == dds_prefix_pos)
{
// not a ROS service type
return std::string();
}
size_t suffix_position = std::string::npos;
for (const auto& suffix : suffixes)
{
suffix_position = dds_type_name.rfind(suffix);
if (std::string::npos != suffix_position)
{
if (0 != (dds_type_name.length() - suffix_position - suffix.length()))
{
RCUTILS_LOG_WARN_NAMED(
"rmw_fastrtps_shared_cpp",
"service type contains 'dds_::' and a suffix"
", but not at the end; repor this: '%s'",
dds_type_name.c_str());
continue;
}
break;
}
}
if (std::string::npos == suffix_position)
{
RCUTILS_LOG_WARN_NAMED(
"rmw_fastrtps_shared_cpp",
"service type contains 'dds_::' but"
" does not have a suffix; report this: '%s'",
dds_type_name.c_str());
return std::string();
}
// Everything is OK. Reformat it from '[type_namespace::]dds_::<type><suffix>'
// to '[type_namespace/]<type>'
std::string type_namespace = dds_type_name.substr(0, dds_prefix_pos);
type_namespace = rcpputils::find_and_replace(type_namespace, "::", "/");
size_t start = dds_prefix_pos + dds_prefix.length();
const std::string type_name = dds_type_name.substr(start, suffix_position - start);
return type_namespace + type_name;
}
std::string Demangle::identity_demangle(
const std::string& name)
{
return name;
}
} // namespace utils
} // namespace agent
} // namespace uros
#endif // UROS_AGENT_UTILS_DEMANGLE_CPP_
+93
View File
@@ -0,0 +1,93 @@
// Copyright 2017-present 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.
#include <agent/Agent.hpp>
#include <string>
#include <vector>
int main(int argc, char** argv)
{
uros::agent::Agent micro_ros_agent;
/** 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;
}
+216
View File
@@ -0,0 +1,216 @@
# 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.
import os
import sys
import xml.etree.ElementTree
from rosidl_cmake import convert_camel_case_to_lower_case_underscore
from rosidl_cmake import expand_template
from rosidl_cmake import get_newest_modification_time
from rosidl_adapter.parser import parse_message_file
from rosidl_adapter.parser import parse_service_file
from rosidl_adapter.parser import validate_field_types
from rosidl_cmake import generate_files
def GetPackage(Dir):
# ignore?
for f in os.listdir(Dir):
full_path = os.path.join(Dir, f)
if os.path.isfile(full_path):
if f == "COLCON_IGNORE":
return "COLCON_IGNORE"
# found package
found_package_path = ""
for f in os.listdir(Dir):
if f == "package.xml":
found_package_path = os.path.join(Dir, f)
found_package_path = os.path.abspath(found_package_path)
break
return found_package_path.replace("\\", "/")
def GetPackageList(Dir):
package_list = []
package_path = GetPackage(Dir)
if package_path == "":
for f in os.listdir(Dir):
full_path = os.path.join(Dir, f)
if os.path.isdir(full_path):
for l in GetPackageList(full_path):
package_list.append(l)
elif package_path != "COLCON_IGNORE":
package_list.append(package_path)
return package_list
def GetInterfacePackages(packages_list):
package_interface_list = []
for package in packages_list:
xml_root = xml.etree.ElementTree.parse(package).getroot()
for element in xml_root.findall('member_of_group'):
if element.text == "rosidl_interface_packages":
package_interface_list.append(package)
return package_interface_list
def GetPackageName(package_path):
xml_root = xml.etree.ElementTree.parse(package_path).getroot()
xml_name_elements = xml_root.findall('name')
if len(xml_name_elements) != 1:
return ""
else:
return xml_name_elements[0].text
def GetInterfacePackageMsgs(package_path):
msg_list = []
package_dir = os.path.dirname(package_path)
for root, dirs, files in os.walk(package_dir):
for file in files:
if file.endswith(".msg"):
full_path = os.path.join(root, file)
msg_list.append(full_path.replace("\\", "/"))
return msg_list
def GetInterfacePackageSrvs(package_path):
msg_list = []
package_dir = os.path.dirname(package_path)
for root, dirs, files in os.walk(package_dir):
for file in files:
if file.endswith(".srv"):
full_path = os.path.join(root, file)
msg_list.append(full_path.replace("\\", "/"))
return msg_list
def ReadDefaultXMLs(Path):
for f in os.listdir(Path):
full_path = os.path.join(Path, f)
if os.path.isfile(full_path) and f.endswith(".xml"):
#xml_root = xml.etree.ElementTree.parse(full_path).getroot()
#if xml_root.iselement():
fd = open(full_path)
print ("%s" % fd.read())
fd.close()
def generate_XML(args):
pkg_name = args['package_name']
#known_msg_types = extract_message_types(
# pkg_name, args['ros_interface_files'], args.get('ros_interface_dependencies', []))
functions = {
'get_header_filename_from_msg_name': convert_camel_case_to_lower_case_underscore,
}
# Set file format
ros2_prefix = "rt/"
# Check destination dir
dest_dir = args['output_dir']
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
# Check source dir
srcs_dir = os.path.join(dest_dir, "srcs")
if not os.path.exists(srcs_dir):
os.makedirs(srcs_dir)
# Iterate throw all msgs/srvs
for idl_file in args['ros_interface_files']:
extension = os.path.splitext(idl_file)[1]
if extension == '.msg':
spec = parse_message_file(pkg_name, idl_file)
#validate_field_types(spec, known_msg_types)
subfolder = os.path.basename(os.path.dirname(idl_file))
data = {
'spec': spec,
'pkg': spec.base_type.pkg_name,
'msg': spec.msg_name,
'type': spec.base_type.type,
'subfolder': subfolder,
}
data.update(functions)
# Generate source file path
src_file = os.path.join(srcs_dir, "%s_%s_%s.xml" % (spec.base_type.pkg_name, subfolder, spec.msg_name))
# Data writer
file_content = " <dds>\n"
file_content += " <data_writer profile_name=\"%s_%s_%s_p\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <topic profile_name=\"%s_%s_%s_t\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <kind>NO_KEY</kind>\n"
file_content += " <name>%s%s_%s_%s</name>\n" % (ros2_prefix, spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <dataType>%s::%s::dds_::%s_</dataType>\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " </topic>\n"
file_content += " </data_writer>\n"
file_content += " </dds>\n"
# Data reader
file_content += " <dds>\n"
file_content += " <data_reader profile_name=\"%s_%s_%s_s\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <topic profile_name=\"%s_%s_%s_t\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <kind>NO_KEY</kind>\n"
file_content += " <name>%s%s_%s_%s</name>\n" % (ros2_prefix, spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <dataType>%s::%s::dds_::%s_</dataType>\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " </topic>\n"
file_content += " </data_reader>\n"
file_content += " </dds>\n"
# Topic
file_content += " <dds>\n"
file_content += " <topic profile_name=\"%s_%s_%s_t\">\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <name>%s%s_%s_%s</name>\n" % (ros2_prefix, spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " <dataType>%s::%s::dds_::%s_</dataType>\n" % (spec.base_type.pkg_name, subfolder, spec.msg_name)
file_content += " </topic>\n"
file_content += " </dds>\n"
# Write file content
print ("%s" % file_content)
#elif extension == '.srv':
#data = {'spec': spec}
#data.update(functions)
#if not os.path.exists(args['output_dir']):
# os.makedirs(args['output_dir'])
#f = open(os.path.join(args['output_dir'], 'demofile.txt'), 'w+')
#f.write("%s\n" % spec)
#f.close()
return 0
-31
View File
@@ -1,31 +0,0 @@
<?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>micro_ros_agent</name>
<version>0.0.1</version>
<description>DDS-XCRE agent implementation </description>
<maintainer email="javiermoreno@eprosima.com">Javier Moreno</maintainer>
<license>Apache License 2.0</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<buildtool_export_depend>ament_cmake</buildtool_export_depend>
<exec_depend>rosidl_parser</exec_depend>
<depend>fastcdr</depend>
<depend>fastrtps</depend>
<depend>micrortps_agent</depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<member_of_group>rosidl_typesupport_c_packages</member_of_group>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
-39
View File
@@ -1,39 +0,0 @@
<participant profile_name="participant_profile">
<rtps>
<builtin>
<leaseDuration>
<durationbyname>INFINITE</durationbyname>
</leaseDuration>
<domainId>0</domainId>
</builtin>
<name>DataReader_participant_subscriber</name>
</rtps>
</participant>
<publisher profile_name="publisher_profile">
<topic>
<kind>WITH_KEY</kind>
<name>Square</name>
<dataType>ShapeType</dataType>
<historyQos>
<kind>KEEP_LAST</kind>
<depth>5</depth>
</historyQos>
<durability>
<kind>TRANSIENT_LOCAL</kind>
</durability>
</topic>
</publisher>
<subscriber profile_name="subscriber_profile">
<topic>
<kind>WITH_KEY</kind>
<name>Square</name>
<dataType>ShapeType</dataType>
<historyQos>
<kind>KEEP_LAST</kind>
<depth>5</depth>
</historyQos>
<durability>
<kind>TRANSIENT_LOCAL</kind>
</durability>
</topic>
</subscriber>
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]