├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ ├── config.yml
│ └── feature_request.yml
└── workflows
│ ├── codespell.yaml
│ ├── humble-nightly.yml
│ ├── humble.yml
│ ├── jazzy-nightly.yml
│ ├── jazzy.yml
│ ├── kilted-nightly.yml
│ ├── kilted.yml
│ ├── mirror-rolling-to-master.yaml
│ ├── rolling-nightly.yml
│ └── rolling.yml
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── codespell.cfg
├── codespell_dictionary.txt
├── codespell_whitelist.txt
├── docker
└── Dockerfile
├── images
├── QR.png
└── overview_architecture.png
├── presentation
├── ros2_parameter_server.html
├── ros2_parameter_server.md
└── ros2_parameter_server.pdf
├── requirements.txt
├── scripts
├── build-verification.sh
└── docker_release.sh
├── server
├── CHANGELOG.rst
├── CMakeLists.txt
├── include
│ └── parameter_server.h
├── launch
│ └── parameter_server.launch.py
├── package.xml
├── param
│ ├── parameter_server.yaml
│ ├── parameters_via_cli.yaml
│ └── parameters_via_launch.yaml
└── src
│ ├── main.cpp
│ └── parameter_server.cpp
└── test
├── CMakeLists.txt
├── include
└── persist_parameter_client.hpp
├── launch
└── test.launch.py
├── package.xml
├── src
├── persist_parameter_client.cpp
└── test.cpp
└── test.py
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: File a bug report.
3 | labels: ["bug"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: "**Required Info:**"
8 | - type: checkboxes
9 | attributes:
10 | label: Is there an existing issue for this?
11 | description: Please search to see if an issue already exists for the bug you encountered.
12 | options:
13 | - label: I have searched the existing issues
14 | required: true
15 | - type: textarea
16 | id: regression
17 | attributes:
18 | label: Regression
19 | description: Is the reported bug a regression? If so, what is the last version of ROS where it still worked fine?
20 | - type: input
21 | id: os
22 | attributes:
23 | label: "Operating System:"
24 | description: |
25 | Please try to be specific.
26 | For Linux, please use the command `uname -a` from a terminal and copy paste its output here.
27 | For Windows, open a terminal (Win key + R and type `cmd`), type the command `ver` and press enter.
28 | Then copy paste the output here.
29 | validations:
30 | required: true
31 | - type: input
32 | id: version
33 | attributes:
34 | label: "ROS version or commit hash:"
35 | description: |
36 | **Examples:** *humble*, *jazzy*, ...
37 | validations:
38 | required: true
39 | - type: input
40 | id: rmw
41 | attributes:
42 | label: "RMW implementation:"
43 | description: |
44 | **Examples:** *rmw_fastrtps_cpp*, *rmw_connextdds*, *rmw_cyclonedds_cpp*, ...
45 | You can check the ROS Middleware (RMW) implementation with the command: `ros2 doctor --report`
46 | Find the line starting with `middleware name` in the report.
47 | validations:
48 | required: true
49 | - type: input
50 | id: clientlib
51 | attributes:
52 | label: "Client library (if applicable):"
53 | description: |
54 | **Examples:** *rclcpp*, *rclpy*, ...
55 | Client libraries are the APIs that allow users to implement their ROS 2 code.
56 | validations:
57 | required: false
58 | - type: textarea
59 | id: doctor
60 | attributes:
61 | label: "'ros2 doctor --report' output"
62 | description: |
63 | It can help us knowing the details of your ROS environment.
64 | Please use the command `ros2 doctor --report` and copy paste its output here.
65 | render: Formatted
66 | validations:
67 | required: false
68 | - type: textarea
69 | id: repro
70 | attributes:
71 | label: "Steps to reproduce issue"
72 | description: |
73 | How do you trigger this bug? Please walk us through it step by step.
74 | Include all the commands you ran in the exact order you ran them so that anyone can reproduce the bug.
75 | placeholder: |
76 | 1.
77 | 2.
78 | 3.
79 | ...
80 | validations:
81 | required: true
82 | - type: textarea
83 | id: expected
84 | attributes:
85 | label: "Expected behavior"
86 | validations:
87 | required: true
88 | - type: textarea
89 | id: actual
90 | attributes:
91 | label: "Actual behavior"
92 | validations:
93 | required: true
94 | - type: textarea
95 | id: addinfo
96 | attributes:
97 | label: "Additional information"
98 | validations:
99 | required: false
100 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | contact_links:
3 | - name: Robotics Stack Exchange
4 | url: https://robotics.stackexchange.com/
5 | about: Please ask and answer questions here.
6 | - name: Documentation for Active ROS Distributions
7 | url: https://docs.ros.org/
8 | about: Please check our documentation here.
9 | - name: ROS Discourse
10 | url: https://discourse.ros.org/
11 | about: Discussion on ROS and ROS-related things.
12 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: File a feature request.
3 | labels: ["enhancement"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: "Thanks for taking the time to fill out this feature request form!"
8 | - type: textarea
9 | id: description
10 | attributes:
11 | label: Feature description
12 | description: |
13 | Description in a few sentences what the feature consists of and what problem it will solve.
14 | validations:
15 | required: true
16 | - type: textarea
17 | id: motivation
18 | attributes:
19 | label: Feature Motivation
20 | description: |
21 | Description what you are trying to solve, what is the problem to address with this Feature Request.
22 | validations:
23 | required: true
24 | - type: textarea
25 | id: implementation
26 | attributes:
27 | label: Implementation considerations
28 | validations:
29 | required: false
30 | description: |
31 | Relevant information on how the feature could be implemented and pros and cons of the different solutions.
32 | - type: textarea
33 | id: information
34 | attributes:
35 | label: Additional Information
36 | validations:
37 | required: false
38 | description: |
39 | If you have more details information, please describe here.
40 |
--------------------------------------------------------------------------------
/.github/workflows/codespell.yaml:
--------------------------------------------------------------------------------
1 | name: codespell
2 |
3 | on: pull_request
4 |
5 | jobs:
6 | spellcheck:
7 | runs-on: ubuntu-22.04
8 | steps:
9 | - name: Checkout
10 | uses: actions/checkout@v4
11 |
12 | - name: Setup Python
13 | uses: actions/setup-python@v5
14 | with:
15 | python-version: '3.10'
16 |
17 | - name: Install dependencies with pip
18 | run: pip install --no-warn-script-location --user -r requirements.txt
19 |
20 | - name: Spellcheck
21 | run: codespell --config codespell.cfg
22 |
--------------------------------------------------------------------------------
/.github/workflows/humble-nightly.yml:
--------------------------------------------------------------------------------
1 | name: Nightly Build for humble
2 |
3 | on:
4 | schedule:
5 | - cron: '0 13 * * *' # Runs every day at midnight, 13:00 UTC
6 |
7 | # Allows you to run this workflow manually from the Actions tab
8 | workflow_dispatch:
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | container:
14 | image: ros:humble
15 | env:
16 | ROS_DISTRO: humble
17 | steps:
18 | - name: Check out repository code
19 | uses: actions/checkout@v3
20 | - name: Build and Test with ROS humble
21 | shell: bash
22 | run: |
23 | ./scripts/build-verification.sh
24 |
--------------------------------------------------------------------------------
/.github/workflows/humble.yml:
--------------------------------------------------------------------------------
1 | # This is workflow for parameter server with humble
2 | name: humble
3 |
4 | on:
5 | push:
6 | branches: [ "rolling" ]
7 | pull_request:
8 | branches: [ "rolling" ]
9 |
10 | # Allows you to run this workflow manually from the Actions tab
11 | workflow_dispatch:
12 |
13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
14 | jobs:
15 |
16 | # each job goes for each ros supported distribution.
17 | # each job description absorb the distribution dependency as much as possible,
18 | # so that build verification script can be agnostic from distribution dependency.
19 |
20 | build:
21 | runs-on: ubuntu-latest
22 | container:
23 | image: ros:humble
24 | env:
25 | ROS_DISTRO: humble
26 | steps:
27 | - name: Check out repository code
28 | uses: actions/checkout@v3
29 | - name: Build with ROS humble
30 | shell: bash
31 | run: |
32 | ./scripts/build-verification.sh
33 |
--------------------------------------------------------------------------------
/.github/workflows/jazzy-nightly.yml:
--------------------------------------------------------------------------------
1 | name: Nightly Build for jazzy
2 |
3 | on:
4 | schedule:
5 | - cron: '0 13 * * *' # Runs every day at midnight, 13:00 UTC
6 |
7 | # Allows you to run this workflow manually from the Actions tab
8 | workflow_dispatch:
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | container:
14 | image: ros:jazzy
15 | env:
16 | ROS_DISTRO: jazzy
17 | steps:
18 | - name: Check out repository code
19 | uses: actions/checkout@v3
20 | - name: Build and Test with ROS jazzy
21 | shell: bash
22 | run: |
23 | ./scripts/build-verification.sh
24 |
--------------------------------------------------------------------------------
/.github/workflows/jazzy.yml:
--------------------------------------------------------------------------------
1 | # This is workflow for parameter server with jazzy
2 | name: jazzy
3 |
4 | on:
5 | push:
6 | branches: [ "rolling" ]
7 | pull_request:
8 | branches: [ "rolling" ]
9 |
10 | # Allows you to run this workflow manually from the Actions tab
11 | workflow_dispatch:
12 |
13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
14 | jobs:
15 |
16 | # each job goes for each ros supported distribution.
17 | # each job description absorb the distribution dependency as much as possible,
18 | # so that build verification script can be agnostic from distribution dependency.
19 |
20 | build:
21 | runs-on: ubuntu-latest
22 | container:
23 | image: ros:jazzy
24 | env:
25 | ROS_DISTRO: jazzy
26 | steps:
27 | - name: Check out repository code
28 | uses: actions/checkout@v3
29 | - name: Build with ROS jazzy
30 | shell: bash
31 | run: |
32 | ./scripts/build-verification.sh
33 |
--------------------------------------------------------------------------------
/.github/workflows/kilted-nightly.yml:
--------------------------------------------------------------------------------
1 | name: Nightly Build for kilted
2 |
3 | on:
4 | schedule:
5 | - cron: '0 13 * * *' # Runs every day at midnight, 13:00 UTC
6 |
7 | # Allows you to run this workflow manually from the Actions tab
8 | workflow_dispatch:
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | container:
14 | image: ros:kilted
15 | env:
16 | ROS_DISTRO: kilted
17 | steps:
18 | - name: Check out repository code
19 | uses: actions/checkout@v3
20 | - name: Build and Test with ROS kilted
21 | shell: bash
22 | run: |
23 | ./scripts/build-verification.sh
24 |
--------------------------------------------------------------------------------
/.github/workflows/kilted.yml:
--------------------------------------------------------------------------------
1 | # This is workflow for parameter server with kilted
2 | name: kilted
3 |
4 | on:
5 | push:
6 | branches: [ "rolling" ]
7 | pull_request:
8 | branches: [ "rolling" ]
9 |
10 | # Allows you to run this workflow manually from the Actions tab
11 | workflow_dispatch:
12 |
13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
14 | jobs:
15 |
16 | # each job goes for each ros supported distribution.
17 | # each job description absorb the distribution dependency as much as possible,
18 | # so that build verification script can be agnostic from distribution dependency.
19 |
20 | build:
21 | runs-on: ubuntu-latest
22 | container:
23 | image: ros:kilted
24 | env:
25 | ROS_DISTRO: kilted
26 | steps:
27 | - name: Check out repository code
28 | uses: actions/checkout@v3
29 | - name: Build with ROS kilted
30 | shell: bash
31 | run: |
32 | ./scripts/build-verification.sh
33 |
--------------------------------------------------------------------------------
/.github/workflows/mirror-rolling-to-master.yaml:
--------------------------------------------------------------------------------
1 | name: Mirror rolling to master
2 |
3 | on:
4 | push:
5 | branches: [ rolling ]
6 |
7 | jobs:
8 | mirror-to-master:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: zofrex/mirror-branch@v1
12 | with:
13 | target-branch: master
14 |
--------------------------------------------------------------------------------
/.github/workflows/rolling-nightly.yml:
--------------------------------------------------------------------------------
1 | name: Nightly Build for rolling
2 |
3 | on:
4 | schedule:
5 | - cron: '0 13 * * *' # Runs every day at midnight, 13:00 UTC
6 |
7 | # Allows you to run this workflow manually from the Actions tab
8 | workflow_dispatch:
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | container:
14 | image: ros:rolling
15 | env:
16 | ROS_DISTRO: rolling
17 | steps:
18 | - name: Check out repository code
19 | uses: actions/checkout@v3
20 | - name: Build and Test with ROS rolling
21 | shell: bash
22 | run: |
23 | ./scripts/build-verification.sh
24 |
--------------------------------------------------------------------------------
/.github/workflows/rolling.yml:
--------------------------------------------------------------------------------
1 | # This is workflow for parameter server with rolling
2 | name: rolling
3 |
4 | on:
5 | push:
6 | branches: [ "rolling" ]
7 | pull_request:
8 | branches: [ "rolling" ]
9 |
10 | # Allows you to run this workflow manually from the Actions tab
11 | workflow_dispatch:
12 |
13 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
14 | jobs:
15 |
16 | # each job goes for each ros supported distribution.
17 | # each job description absorb the distribution dependency as much as possible,
18 | # so that build verification script can be agnostic from distribution dependency.
19 |
20 | build:
21 | runs-on: ubuntu-latest
22 | container:
23 | image: ros:rolling
24 | env:
25 | ROS_DISTRO: rolling
26 | steps:
27 | - name: Check out repository code
28 | uses: actions/checkout@v3
29 | - name: Build with ROS rolling
30 | shell: bash
31 | run: |
32 | ./scripts/build-verification.sh
33 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Any contribution that you make to this repository will
2 | be under the Apache 2 License, as dictated by that
3 | [license](http://www.apache.org/licenses/LICENSE-2.0.html):
4 |
5 | ~~~
6 | 5. Submission of Contributions. Unless You explicitly state otherwise,
7 | any Contribution intentionally submitted for inclusion in the Work
8 | by You to the Licensor shall be under the terms and conditions of
9 | this License, without any additional terms or conditions.
10 | Notwithstanding the above, nothing herein shall supersede or modify
11 | the terms of any separate license agreement you may have executed
12 | with Licensor regarding such Contributions.
13 | ~~~
14 |
15 | Contributors must sign-off each commit by adding a `Signed-off-by: ...`
16 | line to commit messages to certify that they have the right to submit
17 | the code they are contributing to the project according to the
18 | [Developer Certificate of Origin (DCO)](https://developercertificate.org/).
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://github.com/fujitatomoya/ros2_persist_parameter_server/actions/workflows/humble.yml) [](https://github.com/fujitatomoya/ros2_persist_parameter_server/actions/workflows/jazzy.yml) [](https://github.com/fujitatomoya/ros2_persist_parameter_server/actions/workflows/kilted.yml) [](https://github.com/fujitatomoya/ros2_persist_parameter_server/actions/workflows/rolling.yml)
2 | [](https://github.com/fujitatomoya/ros2_persist_parameter_server/actions/workflows/humble-nightly.yml) [](https://github.com/fujitatomoya/ros2_persist_parameter_server/actions/workflows/jazzy-nightly.yml) [](https://github.com/fujitatomoya/ros2_persist_parameter_server/actions/workflows/kilted-nightly.yml) [](https://github.com/fujitatomoya/ros2_persist_parameter_server/actions/workflows/rolling-nightly.yml)
3 |
4 | # ROS2 Persistent Parameter Server
5 |
6 | ROS 2 Persistent Parameter Server, that resides in the ROS 2 system to serve the parameter daemon. The other nodes(e.g the client demo provided in the code) can write/read the parameter in Parameter Server, and ***Parameter Server is able to store the parameter into the persistent storage which user can specify such as tmpfs, nfs, or disk.***
7 |
8 | See [overview slide deck](https://raw.githack.com/fujitatomoya/ros2_persist_parameter_server/rolling/presentation/ros2_parameter_server.html) for general information.
9 |
10 |
11 |
12 | - [ROS2 Persistent Parameter Server](#ros2-persistent-parameter-server)
13 | - [Background](#background)
14 | - [Overview](#overview)
15 | - [Persistent Parameter Registration](#persistent-parameter-registration)
16 | - [Persistent Prefix](#persistent-prefix)
17 | - [Scope Overview](#scope-overview)
18 | - [Configurable Options](#configurable-options)
19 | - [Sequence](#sequence)
20 | - [Getting Started](#getting-started)
21 | - [Supported Distribution](#supported-distribution)
22 | - [Docker Container](#docker-container)
23 | - [Dependent Packages](#dependent-packages)
24 | - [Prerequisites](#prerequisites)
25 | - [Build](#build)
26 | - [Run](#run)
27 | - [Test](#test)
28 | - [Run](#run-1)
29 | - [Known Issues](#known-issues)
30 | - [Authors](#authors)
31 | - [License](#license)
32 |
33 |
34 |
35 | ## Background
36 |
37 | The discussion is opened [here](https://discourse.ros.org/t/ros2-global-parameter-server-status/10114/13), and centralized parameter server is not a good affinity to ROS 2 distributed system architecture. One of the most valuable things about ROS APIs is that we make sure that the messages have specific semantic meaning so that they can’t be misinterpreted. As we develop the ROS 2 tools and best practices we should make sure to bring that same level of rigor to parameters too for greater reusability and correctness.
38 |
39 | Although, it is expected to be the following requirement.
40 |
41 | - Global configuration that many nodes share (e.g. RTOS priorities, vehicle dimensions, …)
42 | - Generic ROS 2 system property server.
43 | - Persistent storage support to re-initialize the system. parameters are modified in runtime and cache it into persistent volume as well. and next boot or next re-spawn, modified parameter will be loaded at initialization. (parameter lifetime is dependent on use case, sometimes system lifetime, sometimes node lifetime.)
44 | - Using ROS1 based application with Parameter Server.
45 |
46 | ## Overview
47 |
48 | 
49 |
50 | Generally ROS 2 Parameter Server is simple blackboard to write/read parameters on that. The other nodes can write/read the parameter on the server to share them in the ROS 2 system. there is a new concept for "Persistent Parameter" which is described later.
51 |
52 | ROS 2 Parameter Server is constructed on ROS parameter API's, nothing specific API's are provided to connect to the server from the client. Also, about the security it just relies on ROS 2 security aspect.
53 |
54 | ### Persistent Parameter Registration
55 |
56 | #### Persistent Prefix
57 |
58 | persistent parameter must have prefix ***"persistent"***
59 |
60 | #### Scope Overview
61 |
62 | parameter server has the following scope for persistent parameter. since parameter server is built on top of ROS 2 Parameter API, parameter server supports "persistent" parameter based on **/parameter_events** topic.
63 |
64 | | Category | Supported | Description |
65 | | ---- | ---- | ---- |
66 | | Parameter API | YES | ROS 2 Parameter Client API supported, since this activity can be detected via **/parameter_events**. |
67 | | Persistent Parameter File | YES | parameter server dedicated argument to specify the file to load as parameters. in addition, all of the persistent parameters will be stored into this file during shutdown. e.g) --file-path /tmp/parameter_server.yaml |
68 | | Parameter Arguments | NO | e.g) --ros-args -p persistent.some_int:=42 some_int cannot be registered as persistent parameter, since this cannot be notified via **/parameter_events** to parameter server. |
69 | | Parameter File Arguments | NO | e.g) --ros-args --params-file ./parameters_via_cli.yaml same with parameter arguments, cannot be registered as persistent parameter, since these cannot be notified via **/parameter_events** to parameter server. |
70 | | Launch Parameter | NO | e.g) ros2 launch parameter_server parameter_server.launch.py same with parameter arguments, cannot be registered as persistent parameter, since these cannot be notified via **/parameter_events** to parameter server. |
71 |
72 | ### Configurable Options
73 |
74 | - Node Name
75 | Since ROS 2 parameter is owned by node, node name will be needed to access the parameters, this is designed to clarify semantics for the parameters and owners. Node name will be "parameter_server" if node name is not specifies. so the other nodes can use "parameter_server" as well to access in the same system Parameter Server. If there must exist multiple parameter servers, these parameter servers need to specify a different node name, such as "parameter_server_[special_string]", please notice that ROS 2 node name can only contains alphanumerics and '_'.
76 | - Persistent Volume
77 | Definition of "Persistent" is different from user and use cases, so it should be configurable to set the path to store the persistent --file-path FILE_PATH parameter. Expecting if the parameter's lifespan is system boot, path would be "/tmp" because user wants a fresh start via reboot. Or maybe physical persistent volume is chosen if users want to keep the parameter into the hardware storage. At the initialization time, Parameter Server will load the parameters from the storage which is specified by user.
78 | - Node Options
79 | there are two important options,
80 | allow_undeclared_parameters: (default true)
81 | automatically_declare_parameters_from_overrides: (default true)
82 |
83 | all of the configuration options will be passed via arguments as following.
84 |
85 |
86 |
87 |
88 |
Options
89 |
CLI
90 |
Description
91 |
92 |
93 |
94 |
95 |
Node Name
96 |
--ros-args --remap __node:=NODENAME
97 |
in default, "parameter_server" will be used.
98 |
99 |
100 |
Help
101 |
--help
102 |
show usage.
103 |
104 |
105 |
File Path
106 |
--file-path FILE_PATH
107 |
in default, "/tmp/parameter_server.yaml" will be used. if specified, that path will be used to store/load the parameter yaml file.
108 |
109 |
110 |
Node Options
111 |
--allow-declare true/false
112 |
default enabled, if specified allow any parameter name to be set on parameter server without declaration by itself. Otherwise it does not.
113 |
114 |
115 |
--allow-override true/false
116 |
default enabled, if specified true iterate through the node's parameter overrides or implicitly declare any that have not already been declared.
117 |
118 |
119 |
120 |
121 | ## Sequence
122 |
123 | 1. parameter server is initialized via __params:=
124 | this is just a initial parameter(not persistent) to load into the parameter server's memory.
125 | 2. parameter server loads parameter specified yaml file via --file-path.
126 | and then parameter server will overwrite or declare parameters.
127 | (*) at #1 parameters might be overwritten.
128 | 3. parameter server starts the main loop with callback for parameter changes.
129 | 4. if the parameter changes are on "/persistent" that will be stored in storage at this time.
130 | 5. at the finalization, flash all of the "/persistent" parameters into the file system.
131 |
132 | ## Getting Started
133 |
134 | ### Supported Distribution
135 |
136 | - [ROS 2 Rolling Ridley](https://docs.ros.org/en/rolling/index.html)
137 | - [ROS 2 Kilted Kaiju](https://docs.ros.org/en/kilted/index.html)
138 | - [ROS 2 Jazzy Jalisco](https://docs.ros.org/en/jazzy/index.html)
139 | - [ROS 2 Humble Hawksbill](https://docs.ros.org/en/humble/index.html)
140 |
141 | #### Docker Container
142 |
143 | see available images for [tomoyafujita/ros2_param_server@dockerhub](https://hub.docker.com/repository/docker/tomoyafujita/ros2_param_server/general)
144 |
145 | ```bash
146 | docker run -it --rm --net=host tomoyafujita/ros2_param_server:humble
147 | ```
148 |
149 | ### Dependent Packages
150 |
151 | ```bash
152 | apt install libyaml-cpp-dev libboost-program-options-dev libboost-filesystem-dev
153 | ```
154 |
155 | ### Prerequisites
156 |
157 | ros2 source build environment([Linux-Development-Setup/](https://index.ros.org/doc/ros2/Installation/Rolling/Linux-Development-Setup/)) is required to build and run the parameter server.
158 |
159 | ### Build
160 |
161 | to install local colcon workspace,
162 |
163 | ```bash
164 | # cd /src
165 | # git clone https://github.com/fujitatomoya/ros2_persist_parameter_server
166 | # cd
167 | # colcon build --symlink-install --packages-select parameter_server ros2_persistent_parameter_server_test
168 | # source install/local_setup.bash
169 | ```
170 |
171 | ### Run
172 |
173 | 1. start parameter server.
174 |
175 | ```bash
176 | # cp /src/ros2_persist_parameter_server/server/param/parameter_server.yaml /tmp/
177 | # ros2 run parameter_server server
178 | [INFO] [parameter_server]: Parameter Server node named: '/parameter_server' started and ready, and serving '9' parameters already!
179 | ...
180 | ```
181 |
182 | 2. update persistent parameter.
183 |
184 | ```bash
185 | # ros2 param set /parameter_server persistent.some_int 81
186 | Set parameter successful
187 | # ros2 param set /parameter_server persistent.a_string Konnichiwa
188 | Set parameter successful
189 | # ros2 param set /parameter_server persistent.pi 3.14159265359
190 | Set parameter successful
191 | # ros2 param set /parameter_server persistent.some_lists.some_integers 81,82,83,84
192 | Set parameter successful
193 | ```
194 |
195 | 3. restart parameter server.
196 |
197 | ```bash
198 | # ros2 run parameter_server server
199 | [INFO] [parameter_server]: Parameter Server node named: '/parameter_server' started and ready, and serving '9' parameters already!
200 | ...
201 | ```
202 |
203 | 4. check persistent parameter is precisely cached and loaded into parameter server.
204 |
205 | ```bash
206 | # ros2 param get /parameter_server persistent.a_string
207 | String value is: Konnichiwa
208 | # ros2 param get /parameter_server persistent.pi
209 | Double value is: 3.14159265359
210 | # ros2 param get /parameter_server persistent.some_int
211 | Integer value is: 81
212 | # ros2 param get /parameter_server persistent.some_lists.some_integers
213 | String value is: 81,82,83,84
214 | ```
215 |
216 | ## Test
217 |
218 | These samples verify the following functions.
219 |
220 | - persistent parameter can be read/stored to/from the file system.
221 | - persistent parameter can be read/modified from parameter client.
222 | - non-persistent parameter cannot be read/stored to/from the file system.
223 | - non-persistent parameter can be read/modified from parameter client
224 |
225 | make sure to add the path of `launch` package to the PATH environment.
226 |
227 | ```bash
228 | # source /install/setup.bash
229 | ```
230 |
231 | ### Run
232 |
233 | [test.py](./test/test.py) is the entry for test.
234 |
235 | [test.py](./test/test.py) will call [test.launch.py](./test/launch/test.launch.py) file to start persistent parameter server and the test client, it also creates a thread to kill parameter server after specified time. All function tests are finished in client.
236 |
237 | !!!NOTE The test script will load the yaml file that should existed in `/tmp/test`, therefore, before executing test demo, you need to copy the yaml file existing in `server` directory to `/tmp/test`.
238 |
239 | ```bash
240 | # mkdir -p /tmp/test
241 | # cp /src/ros2_persist_parameter/server/param/parameter_server.yaml /tmp/test
242 | # .//src/ros2_persist_parameter/test/test.py
243 | ```
244 |
245 | All of the test is listed with result as following
246 |
247 | !!!NOTE Client has a 5-seconds sleep during server restarts.
248 |
249 | ```bash
250 | ...... // omit some output logs
251 |
252 | [ros2-2] [INFO] [1601447662.145760479] [client]: ***************************************************************************
253 | [ros2-2] [INFO] [1601447662.145794365] [client]: *********************************Test Result*******************************
254 | [ros2-2] [INFO] [1601447662.145817265] [client]: a. Read Normal Parameter : PASS
255 | [ros2-2] [INFO] [1601447662.145842530] [client]: b. Read Persistent Parameter : PASS
256 | [ros2-2] [INFO] [1601447662.145863430] [client]: c. Modify Existed Normal parameter : PASS
257 | [ros2-2] [INFO] [1601447662.145885082] [client]: d. Modify Existed Persistent parameter : PASS
258 | [ros2-2] [INFO] [1601447662.145906067] [client]: e. Add New Normal parameter : PASS
259 | [ros2-2] [INFO] [1601447662.145926790] [client]: f. Add New Persistent parameter : PASS
260 | [ros2-2] [INFO] [1601447662.145948146] [client]: g. Test Normal Parameter Not Stores To File : PASS
261 | [ros2-2] [INFO] [1601447662.145969623] [client]: h. Test Persistent Parameter Stores To File : PASS
262 | [ros2-2] [INFO] [1601447662.145990707] [client]: i. Test New Added Normal Parameter Not Stores To File : PASS
263 | [ros2-2] [INFO] [1601447662.146011312] [client]: j. Test New Added Persistent Parameter Stores To File : PASS
264 | ```
265 |
266 | ## Known Issues
267 |
268 | - [Error when loading a persistent parameter of type array](https://github.com/fujitatomoya/ros2_persist_parameter_server/issues/13)
269 | - `[1.0,1.1]` is deduced as `[1, 1.1000000000000001]` because of [yaml-cpp bug](https://github.com/jbeder/yaml-cpp/issues/1016), this will leads to `Failed to parse parameters` exception when loading the persistent parameters from yaml file.
270 | - The work-around is to use string sequence `["1.0", "1.1"]` instead of double type, then change it into `float()` in the program.
271 |
272 | - [Signal2(2) needs to be injected to the server executable](https://github.com/fujitatomoya/ros2_persist_parameter_server/issues/24)
273 | - Because of https://github.com/ros2/ros2cli/pull/899 and [What is main process in container](https://docs.docker.com/engine/containers/multi-service_container/), signal (SIGINT/SIGTERM) does not directly go to the server process. This causes the server not to store the persistent parameters in the file system, since the server expects the signal to shutdown the process and store the all persistent parameters in the specified file system.
274 | - The work-around is that, configure container main process with the server executables (not using `ros2 run` until https://github.com/ros2/ros2cli/pull/899 is solved) or send the signal from the host system to the server process in the container using `docker exec kill -SIGINT `.
275 |
276 | ## Authors
277 |
278 | - **Tomoya Fujita** --- Tomoya.Fujita@sony.com
279 |
280 | ## License
281 |
282 | Apache 2.0
283 |
--------------------------------------------------------------------------------
/codespell.cfg:
--------------------------------------------------------------------------------
1 | [codespell]
2 |
3 | # Enable built-in dictionaries/rules.
4 | # See more details for https://github.com/codespell-project/codespell/tree/main/codespell_lib/data.
5 | builtin = clear,rare,informal,code
6 |
7 | # Ignore words listed in this file.
8 | ignore-words = codespell_whitelist.txt
9 |
10 | # Add custom dictionary file.
11 | dictionary = codespell_dictionary.txt,-
12 |
13 | # Skip checking files or directories.
14 | skip = *.pdf,*.html,*.png
15 |
--------------------------------------------------------------------------------
/codespell_dictionary.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fujitatomoya/ros2_persist_parameter_server/9e3af2cd7b02b32b6f98ac4d06a7de6ab60909b7/codespell_dictionary.txt
--------------------------------------------------------------------------------
/codespell_whitelist.txt:
--------------------------------------------------------------------------------
1 | thead
2 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | # Build:
2 | # docker build --pull --rm -f ./docker/Dockerfile --build-arg="ROS_DISTRO=rolling" --build-arg="COLCON_WS=/root/colcon_ws" -t /ros2_param_server:rolling .
3 | #
4 | # Usage:
5 | # docker pull /ros2_param_server:rolling
6 |
7 | # An ARG declared before a FROM is outside of a build stage,
8 | # so it can’t be used in any instruction after a FROM.
9 | # To use the default value of an ARG declared before the first FROM
10 | # use an ARG instruction without a value inside of a build stage:
11 | ARG ROS_DISTRO=rolling
12 | ARG COLCON_WS=/root/colcon_ws
13 |
14 | FROM ros:${ROS_DISTRO}
15 |
16 | LABEL maintainer="Tomoya Fujita "
17 | LABEL version="1.0"
18 | LABEL description="ros2 persistent parameter server ${ROS_DISTRO} docker image"
19 |
20 | ARG ROS_DISTRO
21 | ARG COLCON_WS
22 |
23 | SHELL ["/bin/bash","-c"]
24 |
25 | RUN mkdir -p ${COLCON_WS}/src
26 | COPY . ${COLCON_WS}/src/ros2_persistent_parameter_server
27 |
28 | # All apt-get commands start with an update, then install
29 | # and finally, a cache cleanup to keep the image size small.
30 |
31 | # Install packages
32 | RUN apt-get update \
33 | && apt-get upgrade -y \
34 | && apt-get install -y \
35 | # required packages for ros2 persistent parameter server
36 | libyaml-cpp-dev libboost-program-options-dev libboost-filesystem-dev \
37 | --no-install-recommends \
38 | && rm -rf /var/lib/apt/lists/*
39 |
40 | # Build and source colcon workspace
41 | RUN cd $COLCON_WS \
42 | && source /opt/ros/$ROS_DISTRO/setup.bash \
43 | && colcon build --symlink-install --packages-select parameter_server
44 |
45 | # Add source environment in .bashrc
46 | RUN echo -n -e "\n" >> /root/.bashrc
47 | RUN echo "### ros2 persistent parameter server workspace setting" >> /root/.bashrc
48 | RUN echo "cd $COLCON_WS && source ./install/setup.bash" >> /root/.bashrc
49 |
50 | # Overwrite as environmental variable so that entrypoint can rely on those.
51 | ENV COLCON_WS=${COLCON_WS}
52 | ENV ROS_DISTRO=${ROS_DISTRO}
53 | #ENTRYPOINT ["/ros_entrypoint.sh"]
54 |
--------------------------------------------------------------------------------
/images/QR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fujitatomoya/ros2_persist_parameter_server/9e3af2cd7b02b32b6f98ac4d06a7de6ab60909b7/images/QR.png
--------------------------------------------------------------------------------
/images/overview_architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fujitatomoya/ros2_persist_parameter_server/9e3af2cd7b02b32b6f98ac4d06a7de6ab60909b7/images/overview_architecture.png
--------------------------------------------------------------------------------
/presentation/ros2_parameter_server.html:
--------------------------------------------------------------------------------
1 |
Comment Here
Supported platforms
Comment Here
Comment Here
--------------------------------------------------------------------------------
/presentation/ros2_parameter_server.md:
--------------------------------------------------------------------------------
1 | ---
2 | marp: true
3 | theme: default
4 | header: "__ROS 2 Persistent Parameter Server__"
5 | footer: "[fujitatomoya@github](https://github.com/fujitatomoya)"
6 | ---
7 |
8 | ## [ROS 2 Persistent Parameter Server](https://github.com/fujitatomoya/ros2_persist_parameter_server)
9 |
10 | 
11 |
12 | - inspired by ROS 1 parameter server.
13 | - can set/get any parameters in this global server.
14 | - can save/load the parameters in storage.
15 |
16 |
19 |
20 | ---
21 |
22 | 
23 | 
24 | 
25 | 
26 |
27 |
30 |
31 | ---
32 |
33 | ## Why we need this?
34 |
35 | - Global configuration that many nodes share (e.g. RTOS priorities, vehicle dimensions, …)
36 | - Generic ROS 2 system or localhost wide parameter server.
37 | - Persistent storage support to re-initialize the system.
38 | - **parameters are modified in runtime and cached into persistent volume as well. and next boot or next re-spawn, modified parameters will be loaded at initialization. (parameter lifetime is dependent on use case, sometimes system lifetime, sometimes node lifetime.)**
39 | - Using ROS 1 based application with Parameter Server.
40 |
41 |
44 |
45 | ---
46 |
47 | 
48 |
49 | ---
50 |
51 | ## Issues and PRs are always welcome 🚀
52 |
53 | https://github.com/fujitatomoya/ros2_persist_parameter_server
54 |
55 | 
56 |
57 |
60 |
--------------------------------------------------------------------------------
/presentation/ros2_parameter_server.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fujitatomoya/ros2_persist_parameter_server/9e3af2cd7b02b32b6f98ac4d06a7de6ab60909b7/presentation/ros2_parameter_server.pdf
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | codespell
2 |
--------------------------------------------------------------------------------
/scripts/build-verification.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #####################################################################
4 | # ROS 2 Persistent Parameter Server
5 | #
6 | # This script builds parameter server within ros docker images.
7 | #
8 | # To avoid updating and modifying the files under `.github/workflows`,
9 | # this scripts should be adjusted building process accordingly.
10 | # And `.github/workflows` just calls this script in the workflow pipeline.
11 | # This allows us to maintain the workflow process easier for contributors.
12 | #
13 | #####################################################################
14 |
15 | ########################
16 | # Function Definitions #
17 | ########################
18 |
19 | function mark {
20 | export $1=`pwd`;
21 | }
22 |
23 | function exit_trap() {
24 | if [ $? != 0 ]; then
25 | echo "Command [$BASH_COMMAND] is failed"
26 | exit 1
27 | fi
28 | }
29 |
30 | function install_prerequisites () {
31 | trap exit_trap ERR
32 | echo "[${FUNCNAME[0]}]: update and install dependent packages."
33 | apt update && apt upgrade -y
34 | apt install -y ros-${ROS_DISTRO}-desktop ros-${ROS_DISTRO}-rmw-cyclonedds-cpp --no-install-recommends
35 | apt install -y libyaml-cpp-dev libboost-program-options-dev libboost-filesystem-dev
36 | cd $there
37 | }
38 |
39 | function setup_build_colcon_env () {
40 | trap exit_trap ERR
41 | echo "[${FUNCNAME[0]}]: set up colcon build environment."
42 | mkdir -p ${COLCON_WORKSPACE}/src
43 | cd ${COLCON_WORKSPACE}
44 | cp -rf $there ${COLCON_WORKSPACE}/src
45 | }
46 |
47 | function build_parameter_server () {
48 | trap exit_trap ERR
49 | echo "[${FUNCNAME[0]}]: build ROS 2 parameter server."
50 | source /opt/ros/${ROS_DISTRO}/setup.bash
51 | cd ${COLCON_WORKSPACE}
52 | colcon build --symlink-install --packages-select parameter_server ros2_persistent_parameter_server_test
53 | }
54 |
55 | function test_parameter_server () {
56 | trap exit_trap ERR
57 | echo "[${FUNCNAME[0]}]: test ROS 2 parameter server."
58 | source /opt/ros/${ROS_DISTRO}/setup.bash
59 | cd ${COLCON_WORKSPACE}
60 |
61 | # TODO(@fujitatomoya): currently unit tests are missing for parameter server with `colcon test`.
62 |
63 | # source the parameter server local packages
64 | source ./install/local_setup.bash
65 | # setup and execute the system test
66 | mkdir /tmp/test
67 | cp ./src/ros2_persist_parameter_server/server/param/parameter_server.yaml /tmp/test
68 | ./src/ros2_persist_parameter_server/test/test.py
69 | }
70 |
71 | ########
72 | # Main #
73 | ########
74 |
75 | export DEBIAN_FRONTEND=noninteractive
76 | export COLCON_WORKSPACE=/tmp/colcon_ws
77 |
78 | # mark the working space root directory, so that we can come back anytime with `cd $there`
79 | mark there
80 |
81 | # set the trap on error
82 | trap exit_trap ERR
83 |
84 | # call install functions in sequence
85 | install_prerequisites
86 | setup_build_colcon_env
87 | build_parameter_server
88 | test_parameter_server
89 |
90 | exit 0
91 |
--------------------------------------------------------------------------------
/scripts/docker_release.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #################################################################################
4 | # This script builds and releases ros2 persistent parameter server docker images.
5 | #################################################################################
6 |
7 | ################
8 | # User Setting #
9 | ################
10 |
11 | DOCKERHUB_USERNAME="${DOCKERHUB_USERNAME:-tomoyafujita}"
12 | COLCON_WS="${COLCON_WS:-/root/colcon_ws}"
13 |
14 | ros_distros=(
15 | "humble"
16 | "jazzy"
17 | "kilted"
18 | "rolling"
19 | )
20 |
21 | ######################
22 | # Options (defaults) #
23 | ######################
24 |
25 | build_image=false
26 | upload_image=false
27 |
28 | ########################
29 | # Function Definitions #
30 | ########################
31 |
32 | function print_usage() {
33 | echo "Usage: $0 [-b] [-u]"
34 | echo "Options(default):"
35 | echo " -b : build docker container images (default: false)"
36 | echo " -u : upload images to DockerHub (default: false)"
37 | exit 1
38 | }
39 |
40 | function exit_trap() {
41 | # shellcheck disable=SC2317 # Don't warn about unreachable commands in this function
42 | if [ $? != 0 ]; then
43 | echo "Command [$BASH_COMMAND] is failed"
44 | exit 1
45 | fi
46 | }
47 |
48 | function check_dockerhub_setting () {
49 | trap exit_trap ERR
50 | echo "[${FUNCNAME[0]}]: checking dockerhub setting and configuration."
51 | if [ -z "$DOCKERHUB_USERNAME" ]; then
52 | echo "DOCKERHUB_USERNAME is not set."
53 | exit 1
54 | fi
55 | # check if docker login succeeds
56 | docker login
57 | }
58 |
59 | function command_exist() {
60 | trap exit_trap ERR
61 | echo "[${FUNCNAME[0]}]: checking $1 command exists."
62 | if command -v "$1" >/dev/null 2>&1; then
63 | echo "$1 exists."
64 | else
65 | echo "Error: $1 not found."
66 | exit 1
67 | fi
68 | }
69 |
70 | function build_images() {
71 | trap exit_trap ERR
72 | echo "[${FUNCNAME[0]}]: building ros2 persistent parameter server docker container images."
73 | for distro in "${ros_distros[@]}"; do
74 | echo "----- $distro image building"
75 | docker build --pull --rm -f ./docker/Dockerfile --build-arg="ROS_DISTRO=$distro" --build-arg="COLCON_WS=$COLCON_WS" -t $DOCKERHUB_USERNAME/ros2_param_server:$distro .
76 | done
77 | echo "----- all images successfully generated!!! -----"
78 | }
79 |
80 | function upload_images() {
81 | trap exit_trap ERR
82 | echo "[${FUNCNAME[0]}]: uploading ros2 persistent parameter server docker container images."
83 | for distro in "${ros_distros[@]}"; do
84 | echo "----- $distro image uploading"
85 | # TODO@fujitatomoya: support multi-arch docker images
86 | docker push $DOCKERHUB_USERNAME/ros2_param_server:$distro
87 | done
88 | echo "----- all images successfully verified!!! -----"
89 | }
90 |
91 | ########
92 | # Main #
93 | ########
94 |
95 | # set the trap on error
96 | trap exit_trap ERR
97 |
98 | # parse command line options
99 | while getopts ":bvu" opt; do
100 | case $opt in
101 | b)
102 | build_image=true
103 | ;;
104 | u)
105 | upload_image=true
106 | ;;
107 | \?)
108 | echo "Invalid option: -$OPTARG"
109 | print_usage
110 | ;;
111 | esac
112 | done
113 | shift $((OPTIND-1))
114 |
115 | # check settings
116 | command_exist docker
117 | check_dockerhub_setting
118 |
119 | # building images
120 | if [ "$build_image" = true ]; then
121 | build_images
122 | fi
123 |
124 | # upload images
125 | if [ "$upload_image" = true ]; then
126 | upload_images
127 | fi
128 |
129 | exit 0
130 |
--------------------------------------------------------------------------------
/server/CHANGELOG.rst:
--------------------------------------------------------------------------------
1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 | Changelog for package ros2 persistent parameter_server
3 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4 |
5 | 1.0.0 (2019-11-18)
6 | ------------------
7 | * 1st commit for basic functions.
8 | * Contributors: Tomoya Fujita
9 |
--------------------------------------------------------------------------------
/server/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.5)
2 | project(parameter_server VERSION 1.0.1)
3 |
4 | # Set Release build if no build type was specified
5 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
6 | set(CMAKE_BUILD_TYPE "Release" CACHE STRING
7 | "Build type for the build. Possible values are: Debug, Release, RelWithDebInfo, MinSizeRel"
8 | FORCE)
9 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
10 | "Debug" "Release" "RelWithDebInfo" "MinSizeRel")
11 | endif()
12 |
13 | # Default to C++17
14 | if(NOT CMAKE_CXX_STANDARD)
15 | set(CMAKE_CXX_STANDARD 17)
16 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
17 | endif()
18 |
19 | # Enable additional warnings and warnings as errors
20 | if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
21 | add_compile_options(-Wall -Wextra -Wpedantic)
22 | endif()
23 |
24 | find_package(ament_cmake REQUIRED)
25 |
26 | find_package(rclcpp REQUIRED)
27 | find_package(rclcpp_components REQUIRED)
28 | find_package(rcutils REQUIRED)
29 | find_package(std_msgs REQUIRED)
30 | find_package(rmw REQUIRED)
31 |
32 | find_package(Boost REQUIRED COMPONENTS program_options filesystem)
33 | find_package(yaml_cpp_vendor REQUIRED)
34 |
35 | add_executable(server
36 | src/parameter_server.cpp
37 | src/main.cpp
38 | )
39 |
40 | # yaml-cpp updates CMake thing significantly on v0.8.0 or later.
41 | # so we ended up having the if statement to process differently instead of creating branches.
42 | # see https://github.com/jbeder/yaml-cpp/releases/tag/0.8.0
43 | find_package(yaml-cpp 0.8.0 QUIET)
44 | if (yaml-cpp_FOUND)
45 | message(STATUS "yaml-cpp package is greater equal than version 0.8.0")
46 | target_link_libraries(server
47 | rclcpp::rclcpp
48 | rclcpp_components::component
49 | rcutils::rcutils
50 | yaml-cpp::yaml-cpp
51 | ${std_msgs_TARGETS}
52 | ${Boost_LIBRARIES}
53 | )
54 | else()
55 | message(STATUS "yaml-cpp package is less than version 0.8.0")
56 | find_package(yaml-cpp REQUIRED)
57 | target_link_libraries(server
58 | rclcpp::rclcpp
59 | rclcpp_components::component
60 | rcutils::rcutils
61 | yaml-cpp
62 | ${std_msgs_TARGETS}
63 | ${Boost_LIBRARIES}
64 | )
65 | endif()
66 |
67 | target_include_directories(server
68 | PUBLIC
69 | $
70 | )
71 |
72 | install(TARGETS server DESTINATION lib/${PROJECT_NAME})
73 |
74 | # Install launch files.
75 | install(DIRECTORY
76 | launch
77 | param
78 | DESTINATION share/${PROJECT_NAME}/
79 | )
80 |
81 | ament_package()
82 |
--------------------------------------------------------------------------------
/server/include/parameter_server.h:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Sony Corporation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #ifndef __PARAMETER_SERVER_H__
16 | #define __PARAMETER_SERVER_H__
17 |
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | #include "rclcpp/rclcpp.hpp"
24 | #include "rclcpp_components/register_node_macro.hpp"
25 | #include "yaml-cpp/yaml.h"
26 |
27 | class ParameterServer : public rclcpp::Node
28 | {
29 | public:
30 | RCLCPP_SMART_PTR_DEFINITIONS(ParameterServer)
31 |
32 | ParameterServer(
33 | const std::string & node_name,
34 | const rclcpp::NodeOptions & options,
35 | const std::string & persistent_yaml_file,
36 | unsigned int storing_period);
37 | ~ParameterServer();
38 |
39 | private:
40 | // Using custom yaml file same as yaml format of ros2 parameter as much as possible,
41 | // so use rcl_yaml_param_parser functions directly to load custom persistent yaml file.
42 | void LoadYamlFile();
43 |
44 | // To store yaml into a file, think it's more convenient to use yaml_cpp than libyaml.
45 | // (rcl_yaml_param_parser/libyaml not contain store function)
46 | void StoreYamlFile();
47 |
48 | // To check whether yaml file is valid
49 | void CheckYamlFile();
50 | void ValidateYamlFile(YAML::Node node, const std::string& key = "");
51 | void SaveNode(YAML::Emitter& out, YAML::Node node, const std::string& key = "");
52 |
53 | // Check whether parameter name contains "persistent." in the parameter list
54 | bool CheckPersistentParam(const std::vector & parameters);
55 |
56 | // Check flag to store file
57 | std::atomic_bool param_update_;
58 |
59 | // yaml file to load/store
60 | std::string persistent_yaml_file_;
61 |
62 | // store changed(add, update) parameter name contains "persistent." after checking in 'parameter_events' callback
63 | std::set changed_parameter_lists_;
64 |
65 | // To adapt the original yaml format that contain namespace(optional) and nodename(can be /**)
66 | bool parameter_use_stars_ = false;
67 | bool parameter_ns_exist_ = false;
68 | bool parameter_name_exist_ = false;
69 | std::string node_name_;
70 |
71 | // set parameters callback handler
72 | OnSetParametersCallbackHandle::SharedPtr callback_handler_;
73 |
74 | // for periodic storing to the file system
75 | rclcpp::TimerBase::SharedPtr timer_;
76 | };
77 |
78 | #endif // __PARAMETER_SERVER_H__
79 |
--------------------------------------------------------------------------------
/server/launch/parameter_server.launch.py:
--------------------------------------------------------------------------------
1 | # Copyright 2019 Sony Corporation
2 | #
3 | # Licensed under the Apache License, Version 2.0 (the "License");
4 | # you may not use this file except in compliance with the License.
5 | # You may obtain a copy of the License at
6 | #
7 | # http://www.apache.org/licenses/LICENSE-2.0
8 | #
9 | # Unless required by applicable law or agreed to in writing, software
10 | # distributed under the License is distributed on an "AS IS" BASIS,
11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | # See the License for the specific language governing permissions and
13 | # limitations under the License.
14 |
15 | """Launch a server."""
16 |
17 | from launch import LaunchDescription
18 | from launch.substitutions import EnvironmentVariable
19 | import launch_ros.actions
20 | import os
21 | import pathlib
22 |
23 | parameters_file_name = 'parameters_via_launch.yaml'
24 |
25 | def generate_launch_description():
26 | parameters_file_path = str(pathlib.Path(__file__).parents[1]) # get current path and go one level up
27 | parameters_file_path += '/param/' + parameters_file_name
28 | return LaunchDescription(
29 | [
30 | launch_ros.actions.Node(
31 | package="parameter_server",
32 | executable="server",
33 | output="screen",
34 | # respawn in 5.0 seconds
35 | respawn=True,
36 | respawn_delay=5.0,
37 | # these parameters in parameters_file_path cannot be registered as persistent parameters,
38 | # these will be loaded as normal parameter without event on /parameter_events topic.
39 | parameters=[parameters_file_path],
40 | # this example to load persistent parameter files into parameter server,
41 | # these parameters described in parameter_server.yaml with prefix "persistent" will be registered as persistent parameter.
42 | # arguments=[
43 | # "--file-path",
44 | # "/tmp/parameter_server.yaml",
45 | # "--allow-declare",
46 | # "true",
47 | # "--allow-override",
48 | # "true",
49 | # "--storing-period",
50 | # "60",
51 | # ],
52 | )
53 | ]
54 | )
55 |
--------------------------------------------------------------------------------
/server/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | parameter_server
5 | 1.0.1
6 |
7 | ros2 parameter server that other nodes can write/read parameters including persistent parameters.
8 |
9 | Tomoya Fujita
10 | Apache License 2.0
11 | Tomoya Fujita>
12 |
13 | ament_cmake
14 |
15 | rclcpp
16 | rclcpp_components
17 | rcutils
18 | rmw
19 | rmw_implementation_cmake
20 | std_msgs
21 | yaml_cpp_vendor
22 |
23 | launch_ros
24 |
25 | ament_cmake_pytest
26 | ament_lint_auto
27 | ament_lint_common
28 | launch
29 |
30 |
31 | ament_cmake
32 |
33 |
34 |
--------------------------------------------------------------------------------
/server/param/parameter_server.yaml:
--------------------------------------------------------------------------------
1 | /**:
2 | ros__parameters:
3 | # This file is expected to be used as following,
4 | # > ros2 run parameter_server server --file-path /tmp/parameter_server.yaml
5 | #
6 | # Not persistent parameter.
7 | # These just will be loaded as normal parameters.
8 | some_int: 1
9 | a_string: "Hello world"
10 | pi: 3.14
11 | some_lists:
12 | some_integers: [1, 2, 3, 4]
13 | # persistent parameter.
14 | # these parameters will be registered as persistent parameter,
15 | # so during shutdown, these will be stored back in the storage if any updates available.
16 | persistent:
17 | some_int: 1
18 | a_string: 'Hello world'
19 | pi: 3.14
20 | some_lists:
21 | some_integers: [1, 2, 3, 4]
22 |
--------------------------------------------------------------------------------
/server/param/parameters_via_cli.yaml:
--------------------------------------------------------------------------------
1 | /**:
2 | ros__parameters:
3 | # This file is expected to be used
4 | # > ros2 run parameter_server server --ros-args --params-file /parameters_via_cli.yaml
5 | #
6 | # all of the parameters here cannot be registered as persistent parameter,
7 | # since these are set internally with library and not able to detect via /parameter_events topic.
8 | some_int: 1
9 | a_string: "Hello world"
10 | pi: 3.14
11 | some_lists:
12 | some_integers: [1, 2, 3, 4]
13 | persistent:
14 | some_int: 1
15 | a_string: 'Hello world'
16 | pi: 3.14
17 | some_lists:
18 | some_integers: [1, 2, 3, 4]
19 |
--------------------------------------------------------------------------------
/server/param/parameters_via_launch.yaml:
--------------------------------------------------------------------------------
1 | /**:
2 | ros__parameters:
3 | # This file is expected to be used with ros2 launch
4 | # > ros2 launch parameter_server parameter_server.launch.py
5 | #
6 | # all of the parameters here cannot be registered as persistent parameter,
7 | # since these are set internally with library and not able to detect via /parameter_events topic.
8 | some_int: 1
9 | a_string: "Hello world"
10 | pi: 3.14
11 | some_lists:
12 | some_integers: [1, 2, 3, 4]
13 | persistent:
14 | some_int: 1
15 | a_string: 'Hello world'
16 | pi: 3.14
17 | some_lists:
18 | some_integers: [1, 2, 3, 4]
19 |
--------------------------------------------------------------------------------
/server/src/main.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Sony Corporation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include
16 |
17 | #include "parameter_server.h"
18 |
19 | using namespace std;
20 | using namespace boost::program_options;
21 |
22 | int main(int argc, char **argv)
23 | {
24 | int ret = EXIT_SUCCESS;
25 | // Force flush of the stdout buffer.
26 | setvbuf(stdout, NULL, _IONBF, BUFSIZ);
27 |
28 | // To call rclcpp::init_and_remove_ros_arguments at the beginning to prevent
29 | // from using new arguments "--ros-args" to support remapping node name
30 | // (such as "--ros-args --remap __node:=test1")
31 | // that boost program options failed to parse arguments
32 | auto nonros_args = rclcpp::init_and_remove_ros_arguments(argc, argv);
33 |
34 | options_description description("ROS2 parameter server command line interfaces");
35 | description.add_options()
36 | ("help,h", "help message to show interfaces")
37 | ("file-path,f", value()->default_value("/tmp/parameter_server.yaml"),
38 | "volume path to load/store parameters in yaml format (default /tmp/parameter_server.yaml)")
39 | ("allow-declare,d", value()->default_value(true),
40 | "enable(true) / disable(false) allow_undeclared_parameters via node option (default true)")
41 | ("allow-override,o", value()->default_value(true),
42 | "enable(true) / disable(false) automatically_declare_parameters_from_overrides via node option (default true)")
43 | ("storing-period,s", value()->default_value(60),
44 | "period in seconds for periodic persistent parameter storing (default 60). No periodic storing is performed if this parameter is set to 0");
45 |
46 | variables_map vm;
47 | store(basic_command_line_parser(nonros_args).options(description).run(), vm);
48 | notify(vm);
49 |
50 | std::string node_name = "parameter_server";
51 | string opt_file("/tmp/parameter_server.yaml");
52 | bool opt_allow_declare = true;
53 | bool opt_allow_override = true;
54 | unsigned int storing_period = 60;
55 |
56 | if (vm.count("help"))
57 | {
58 | cout << description << endl;
59 | rclcpp::shutdown();
60 | return ret;
61 | }
62 | else
63 | {
64 | opt_file = vm["file-path"].as();
65 | opt_allow_declare = vm["allow-declare"].as();
66 | opt_allow_override = vm["allow-override"].as();
67 | storing_period = vm["storing-period"].as();
68 | }
69 |
70 | rclcpp::NodeOptions options = (
71 | rclcpp::NodeOptions()
72 | .allow_undeclared_parameters(opt_allow_declare)
73 | .automatically_declare_parameters_from_overrides(opt_allow_override)
74 | );
75 |
76 | ParameterServer::SharedPtr node = nullptr;
77 | try
78 | {
79 | node = ParameterServer::make_shared(node_name, options, opt_file, storing_period);
80 | if (node == nullptr)
81 | {
82 | throw std::bad_alloc();
83 | }
84 |
85 | RCLCPP_INFO(node->get_logger(),
86 | "Parameter Server node named: '%s' started and ready, and serving '%zu' parameters already!",
87 | node->get_fully_qualified_name(),
88 | node->list_parameters({}, rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE).names.size());
89 |
90 | rclcpp::spin(node);
91 | }
92 | catch (const std::exception& e)
93 | {
94 | std::cerr << "Catch exception: " << e.what() << std::endl;
95 | ret = EXIT_FAILURE;
96 | }
97 |
98 | rclcpp::shutdown();
99 | return ret;
100 | }
101 |
--------------------------------------------------------------------------------
/server/src/parameter_server.cpp:
--------------------------------------------------------------------------------
1 | // Copyright 2019 Sony Corporation
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | #include "parameter_server.h"
16 |
17 | #include
18 | #include
19 | #include