Skip to content

Commit 6857dd2

Browse files
authored
Introducing ros2 parameters and name remapping (#576)
This PR introduces ROS2 parameter and name remapping support. Parameter Use-cases: Declare Parameters Override Declared Parameters Override Declared Parameters from yaml parameters file List Parameters Describe Parameters Get Parameters Set Parameters Set Parameters Atomically Remap Use-cases: Remap node name Remap node namespace name Remap publisher topic name Remap service name 1. Name remapping and paramter overrides w/ yaml file support is delegated to rcl api. 2. index#init() modified to accept an argv array with --ros-args commandline arguments. 3. index#createNode() accepts NodeOptions for programmatic defined parameter overrides. 4. Added parameter.js with ParameterType Parameter ParameterDescription FloatingPointRange IntegerRange 5. Added is-close module dependency for use in the FloatingPointRange class. 6. New rcl_bindings functions: getParameterOverrides() getTopic() getServiceName() 7. Node.js changes: added instance vars: _parameters _parameterDescriptors _parameterService _parameterEventPublisher init() function changes: sets up parameter-overrides optionally declares parameters from parameter-overrides starts parameterService creates parameterEventPublisher Node methods: getParameterOverrides() hasParameter() declareParameter() declareParameters() undeclareParameter() getParameter() getParameters() hasParameterDescriptor() getParameterDescriptor() getParameterDescriptors() setParameter() setParameters() setParameterAtomically() setParametersAtomically() _getNativeParameterOverrides() _valdateParameters() 8. Tests files: test-parameters.js test-parameter-service.js test-remapping.js 9. Examples: parameter-declaration-example.js parameter-override-example.js Fix #414, #415, #416, #421.
1 parent 8006534 commit 6857dd2

29 files changed

+3799
-38
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,8 @@ cpplint.py
1616
generated
1717
types/interfaces.d.ts
1818
dist
19+
build
20+
install
21+
log
1922
.vscode
2023
.project

binding.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
'libraries': [
4040
'-lrcl',
4141
'-lrcutils',
42+
'-lrcl_yaml_param_parser',
4243
'-lrmw',
4344
'-lrosidl_generator_c',
4445
],
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) 2020 Wayne Parrott. All rights reserved.
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+
'use strict';
16+
17+
const rclnodejs = require('../index.js');
18+
19+
const ParameterType = rclnodejs.Parameters.ParameterType;
20+
const Parameter = rclnodejs.Parameters.Parameter;
21+
const ParameterDescriptor = rclnodejs.Parameters.ParameterDescriptor;
22+
23+
async function main() {
24+
await rclnodejs.init();
25+
26+
const node = rclnodejs.createNode('my_node');
27+
28+
const parameter = new Parameter(
29+
'param1',
30+
ParameterType.PARAMETER_STRING,
31+
'hello world'
32+
);
33+
const parameterDescriptor = new ParameterDescriptor(
34+
'param1',
35+
ParameterType.PARAMETER_STRING
36+
);
37+
38+
node.declareParameter(parameter, parameterDescriptor);
39+
console.log(`Declared parameter: ${parameter.name}`);
40+
41+
if (!node.hasParameter('param1')) {
42+
console.error(`Unable to find parameter: ${parameter.name}`);
43+
return;
44+
}
45+
46+
console.log('Parameter details: ', node.getParameter('param1'));
47+
console.log(node.getParameterDescriptor('param1'));
48+
}
49+
50+
main();
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// You may obtain a copy of the License at
2+
//
3+
// http://www.apache.org/licenses/LICENSE-2.0
4+
//
5+
// Unless required by applicable law or agreed to in writing, software
6+
// distributed under the License is distributed on an "AS IS" BASIS,
7+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
8+
// See the License for the specific language governing permissions and
9+
// limitations under the License.
10+
11+
'use strict';
12+
13+
const rclnodejs = require('../index.js');
14+
15+
const ParameterType = rclnodejs.Parameters.ParameterType;
16+
const Parameter = rclnodejs.Parameters.Parameter;
17+
const ParameterDescriptor = rclnodejs.Parameters.ParameterDescriptor;
18+
19+
async function main() {
20+
const NODE_NAME = 'my_node';
21+
22+
// commandline override of param1
23+
const argv = ['--ros-args', '-p', NODE_NAME + ':param1:=hello ros2'];
24+
25+
// initialize rclnodejs with commandline argv
26+
await rclnodejs.init(rclnodejs.Context.defaultContext(), argv);
27+
28+
const node = rclnodejs.createNode(NODE_NAME);
29+
30+
// define param
31+
const parameter = new Parameter(
32+
'param1',
33+
ParameterType.PARAMETER_STRING,
34+
'hello world'
35+
);
36+
const parameterDescriptor = new ParameterDescriptor(
37+
'param1',
38+
ParameterType.PARAMETER_STRING
39+
);
40+
41+
// declare param1
42+
node.declareParameter(parameter, parameterDescriptor);
43+
console.log(`Declared parameter: ${parameter.name}`);
44+
45+
if (!node.hasParameter('param1')) {
46+
console.error(`Unable to find parameter: ${parameter.name}`);
47+
return;
48+
}
49+
50+
console.log('Parameter overridden: ', node.getParameter('param1'));
51+
console.log(node.getParameterDescriptor('param1'));
52+
}
53+
54+
main();

index.js

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ const generator = require('./rosidl_gen/index.js');
2121
const loader = require('./lib/interface_loader.js');
2222
const logging = require('./lib/logging.js');
2323
const Node = require('./lib/node.js');
24+
const NodeOptions = require('./lib/node_options.js');
25+
const Parameters = require('./lib/parameter.js');
2426
const path = require('path');
2527
const QoS = require('./lib/qos.js');
2628
const rclnodejs = require('bindings')('rclnodejs');
@@ -73,6 +75,9 @@ let rcl = {
7375
_initialized: false,
7476
_nodes: [],
7577

78+
/** {@link Context} class */
79+
Context: Context,
80+
7681
/** {@link QoS} class */
7782
QoS: QoS,
7883

@@ -97,28 +102,41 @@ let rcl = {
97102
/** {@link Duration} class */
98103
Duration: Duration,
99104

105+
/** {@link NodeOptions} class */
106+
NodeOptions: NodeOptions,
107+
108+
/** {@link Parameters} */
109+
Parameters: Parameters,
110+
100111
/**
101112
* Create a node.
102113
* @param {string} nodeName - The name used to register in ROS.
103114
* @param {string} namespace - The namespace used in ROS, default is an empty string.
104115
* @param {Context} context - The context, default is Context.defaultContext().
116+
* @param {NodeOptions} options - The options to configure the new node behavior.
105117
* @return {Node} The instance of Node.
106118
*/
107-
createNode(nodeName, namespace = '', context = Context.defaultContext()) {
119+
createNode(
120+
nodeName,
121+
namespace = '',
122+
context = Context.defaultContext(),
123+
options = NodeOptions.defaultOptions
124+
) {
108125
if (typeof nodeName !== 'string' || typeof namespace !== 'string') {
109126
throw new TypeError('Invalid argument.');
110127
}
111128

112129
let handle = rclnodejs.createNode(nodeName, namespace, context.handle());
113130
let node = new rclnodejs.ShadowNode();
131+
node.handle = handle;
114132

115-
node.init(nodeName, namespace);
133+
node.init(nodeName, namespace, context, options);
116134
debug(
117135
'Finish initializing node, name = %s and namespace = %s.',
118136
nodeName,
119137
namespace
120138
);
121-
node.handle = handle;
139+
122140
node.context = context;
123141
this._nodes.push(node);
124142
return node;
@@ -127,10 +145,19 @@ let rcl = {
127145
/**
128146
* Init the module.
129147
* @param {Context} context - The context, default is Context.defaultContext().
148+
* @param {string[]} argv - Process commandline arguments.
130149
* @return {Promise<undefined>} A Promise.
131150
*/
132-
init(context = Context.defaultContext()) {
151+
init(context = Context.defaultContext(), argv = process.argv) {
133152
return new Promise((resolve, reject) => {
153+
// check argv for correct value and state
154+
if (!Array.isArray(argv)) {
155+
throw new TypeError('argv must be an array.');
156+
}
157+
if (argv.reduce((hasNull, arg) => typeof arg !== 'string', false)) {
158+
throw new TypeError('argv elements must not be null');
159+
}
160+
134161
let that = this;
135162
if (!this._initialized) {
136163
getCurrentGeneratorVersion()
@@ -150,7 +177,7 @@ let rcl = {
150177
.generateAll(forced)
151178
.then(() => {
152179
this._context = context;
153-
rclnodejs.init(context.handle());
180+
rclnodejs.init(context.handle(), argv);
154181
this._initialized = true;
155182
resolve();
156183
})

0 commit comments

Comments
 (0)