Skip to content

Commit

Permalink
Introducing ros2 parameters and name remapping (#576)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
wayneparrott authored Feb 27, 2020
1 parent 8006534 commit 6857dd2
Show file tree
Hide file tree
Showing 29 changed files with 3,799 additions and 38 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ cpplint.py
generated
types/interfaces.d.ts
dist
build
install
log
.vscode
.project
1 change: 1 addition & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
'libraries': [
'-lrcl',
'-lrcutils',
'-lrcl_yaml_param_parser',
'-lrmw',
'-lrosidl_generator_c',
],
Expand Down
50 changes: 50 additions & 0 deletions example/parameter-declaration-example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) 2020 Wayne Parrott. All rights reserved.
//
// 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.

'use strict';

const rclnodejs = require('../index.js');

const ParameterType = rclnodejs.Parameters.ParameterType;
const Parameter = rclnodejs.Parameters.Parameter;
const ParameterDescriptor = rclnodejs.Parameters.ParameterDescriptor;

async function main() {
await rclnodejs.init();

const node = rclnodejs.createNode('my_node');

const parameter = new Parameter(
'param1',
ParameterType.PARAMETER_STRING,
'hello world'
);
const parameterDescriptor = new ParameterDescriptor(
'param1',
ParameterType.PARAMETER_STRING
);

node.declareParameter(parameter, parameterDescriptor);
console.log(`Declared parameter: ${parameter.name}`);

if (!node.hasParameter('param1')) {
console.error(`Unable to find parameter: ${parameter.name}`);
return;
}

console.log('Parameter details: ', node.getParameter('param1'));
console.log(node.getParameterDescriptor('param1'));
}

main();
54 changes: 54 additions & 0 deletions example/parameter-override-example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// 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.

'use strict';

const rclnodejs = require('../index.js');

const ParameterType = rclnodejs.Parameters.ParameterType;
const Parameter = rclnodejs.Parameters.Parameter;
const ParameterDescriptor = rclnodejs.Parameters.ParameterDescriptor;

async function main() {
const NODE_NAME = 'my_node';

// commandline override of param1
const argv = ['--ros-args', '-p', NODE_NAME + ':param1:=hello ros2'];

// initialize rclnodejs with commandline argv
await rclnodejs.init(rclnodejs.Context.defaultContext(), argv);

const node = rclnodejs.createNode(NODE_NAME);

// define param
const parameter = new Parameter(
'param1',
ParameterType.PARAMETER_STRING,
'hello world'
);
const parameterDescriptor = new ParameterDescriptor(
'param1',
ParameterType.PARAMETER_STRING
);

// declare param1
node.declareParameter(parameter, parameterDescriptor);
console.log(`Declared parameter: ${parameter.name}`);

if (!node.hasParameter('param1')) {
console.error(`Unable to find parameter: ${parameter.name}`);
return;
}

console.log('Parameter overridden: ', node.getParameter('param1'));
console.log(node.getParameterDescriptor('param1'));
}

main();
37 changes: 32 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const generator = require('./rosidl_gen/index.js');
const loader = require('./lib/interface_loader.js');
const logging = require('./lib/logging.js');
const Node = require('./lib/node.js');
const NodeOptions = require('./lib/node_options.js');
const Parameters = require('./lib/parameter.js');
const path = require('path');
const QoS = require('./lib/qos.js');
const rclnodejs = require('bindings')('rclnodejs');
Expand Down Expand Up @@ -73,6 +75,9 @@ let rcl = {
_initialized: false,
_nodes: [],

/** {@link Context} class */
Context: Context,

/** {@link QoS} class */
QoS: QoS,

Expand All @@ -97,28 +102,41 @@ let rcl = {
/** {@link Duration} class */
Duration: Duration,

/** {@link NodeOptions} class */
NodeOptions: NodeOptions,

/** {@link Parameters} */
Parameters: Parameters,

/**
* Create a node.
* @param {string} nodeName - The name used to register in ROS.
* @param {string} namespace - The namespace used in ROS, default is an empty string.
* @param {Context} context - The context, default is Context.defaultContext().
* @param {NodeOptions} options - The options to configure the new node behavior.
* @return {Node} The instance of Node.
*/
createNode(nodeName, namespace = '', context = Context.defaultContext()) {
createNode(
nodeName,
namespace = '',
context = Context.defaultContext(),
options = NodeOptions.defaultOptions
) {
if (typeof nodeName !== 'string' || typeof namespace !== 'string') {
throw new TypeError('Invalid argument.');
}

let handle = rclnodejs.createNode(nodeName, namespace, context.handle());
let node = new rclnodejs.ShadowNode();
node.handle = handle;

node.init(nodeName, namespace);
node.init(nodeName, namespace, context, options);
debug(
'Finish initializing node, name = %s and namespace = %s.',
nodeName,
namespace
);
node.handle = handle;

node.context = context;
this._nodes.push(node);
return node;
Expand All @@ -127,10 +145,19 @@ let rcl = {
/**
* Init the module.
* @param {Context} context - The context, default is Context.defaultContext().
* @param {string[]} argv - Process commandline arguments.
* @return {Promise<undefined>} A Promise.
*/
init(context = Context.defaultContext()) {
init(context = Context.defaultContext(), argv = process.argv) {
return new Promise((resolve, reject) => {
// check argv for correct value and state
if (!Array.isArray(argv)) {
throw new TypeError('argv must be an array.');
}
if (argv.reduce((hasNull, arg) => typeof arg !== 'string', false)) {
throw new TypeError('argv elements must not be null');
}

let that = this;
if (!this._initialized) {
getCurrentGeneratorVersion()
Expand All @@ -150,7 +177,7 @@ let rcl = {
.generateAll(forced)
.then(() => {
this._context = context;
rclnodejs.init(context.handle());
rclnodejs.init(context.handle(), argv);
this._initialized = true;
resolve();
})
Expand Down
Loading

0 comments on commit 6857dd2

Please sign in to comment.