rclnodejs 1.8.2 → 1.9.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -37
- package/index.js +62 -23
- package/lib/action/client.js +67 -3
- package/lib/action/server.js +1 -3
- package/lib/distro.js +2 -1
- package/lib/lifecycle_publisher.js +2 -2
- package/lib/message_info.js +94 -0
- package/lib/node.js +90 -14
- package/lib/parameter.js +5 -9
- package/lib/parameter_event_handler.js +468 -0
- package/lib/parameter_watcher.js +12 -12
- package/lib/service.js +8 -4
- package/lib/subscription.js +38 -5
- package/lib/time_source.js +3 -20
- package/lib/timer.js +2 -1
- package/lib/wait_for_message.js +111 -0
- package/package.json +7 -4
- package/prebuilds/linux-arm64/humble-jammy-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/jazzy-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-arm64/kilted-noble-arm64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/humble-jammy-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/jazzy-noble-x64-rclnodejs.node +0 -0
- package/prebuilds/linux-x64/kilted-noble-x64-rclnodejs.node +0 -0
- package/rosidl_gen/generate_worker.js +3 -13
- package/rosidl_gen/idl_generator.js +210 -0
- package/rosidl_gen/index.js +3 -12
- package/rosidl_gen/packages.js +1 -3
- package/rosidl_gen/primitive_types.js +2 -2
- package/rosidl_parser/idl_parser.py +437 -0
- package/rosidl_parser/parser.py +2 -4
- package/rosidl_parser/rosidl_parser.js +27 -0
- package/scripts/run_asan_test.sh +118 -0
- package/src/executor.cpp +37 -2
- package/src/executor.h +11 -0
- package/src/macros.h +2 -2
- package/src/rcl_action_client_bindings.cpp +88 -12
- package/src/rcl_action_server_bindings.cpp +24 -13
- package/src/rcl_client_bindings.cpp +13 -5
- package/src/rcl_context_bindings.cpp +10 -11
- package/src/rcl_graph_bindings.cpp +2 -2
- package/src/rcl_guard_condition_bindings.cpp +12 -3
- package/src/rcl_lifecycle_bindings.cpp +34 -15
- package/src/rcl_node_bindings.cpp +11 -4
- package/src/rcl_publisher_bindings.cpp +12 -3
- package/src/rcl_service_bindings.cpp +12 -3
- package/src/rcl_subscription_bindings.cpp +92 -21
- package/src/rcl_timer_bindings.cpp +24 -9
- package/src/rcl_type_description_service_bindings.cpp +9 -1
- package/src/rcl_utilities.cpp +2 -2
- package/tools/jsdoc/Makefile +5 -0
- package/tools/jsdoc/README.md +96 -0
- package/tools/jsdoc/build-index.js +610 -0
- package/tools/jsdoc/publish.js +854 -0
- package/tools/jsdoc/regenerate-published-docs.js +605 -0
- package/tools/jsdoc/static/fonts/OpenSans-Bold-webfont.eot +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Bold-webfont.svg +1830 -0
- package/tools/jsdoc/static/fonts/OpenSans-Bold-webfont.woff +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-BoldItalic-webfont.eot +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-BoldItalic-webfont.svg +1830 -0
- package/tools/jsdoc/static/fonts/OpenSans-BoldItalic-webfont.woff +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Italic-webfont.eot +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Italic-webfont.svg +1830 -0
- package/tools/jsdoc/static/fonts/OpenSans-Italic-webfont.woff +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Light-webfont.eot +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Light-webfont.svg +1831 -0
- package/tools/jsdoc/static/fonts/OpenSans-Light-webfont.woff +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-LightItalic-webfont.eot +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-LightItalic-webfont.svg +1835 -0
- package/tools/jsdoc/static/fonts/OpenSans-LightItalic-webfont.woff +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Regular-webfont.eot +0 -0
- package/tools/jsdoc/static/fonts/OpenSans-Regular-webfont.svg +1831 -0
- package/tools/jsdoc/static/fonts/OpenSans-Regular-webfont.woff +0 -0
- package/tools/jsdoc/static/scripts/linenumber.js +25 -0
- package/tools/jsdoc/static/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/tools/jsdoc/static/scripts/prettify/lang-css.js +36 -0
- package/tools/jsdoc/static/scripts/prettify/prettify.js +738 -0
- package/tools/jsdoc/static/styles/jsdoc-default.css +1012 -0
- package/tools/jsdoc/static/styles/prettify-jsdoc.css +111 -0
- package/tools/jsdoc/static/styles/prettify-tomorrow.css +132 -0
- package/tools/jsdoc/tmpl/augments.tmpl +10 -0
- package/tools/jsdoc/tmpl/container.tmpl +193 -0
- package/tools/jsdoc/tmpl/details.tmpl +143 -0
- package/tools/jsdoc/tmpl/example.tmpl +2 -0
- package/tools/jsdoc/tmpl/examples.tmpl +13 -0
- package/tools/jsdoc/tmpl/exceptions.tmpl +17 -0
- package/tools/jsdoc/tmpl/layout.tmpl +83 -0
- package/tools/jsdoc/tmpl/mainpage.tmpl +163 -0
- package/tools/jsdoc/tmpl/members.tmpl +43 -0
- package/tools/jsdoc/tmpl/method.tmpl +124 -0
- package/tools/jsdoc/tmpl/params.tmpl +133 -0
- package/tools/jsdoc/tmpl/properties.tmpl +110 -0
- package/tools/jsdoc/tmpl/returns.tmpl +12 -0
- package/tools/jsdoc/tmpl/source.tmpl +8 -0
- package/tools/jsdoc/tmpl/tutorial.tmpl +19 -0
- package/tools/jsdoc/tmpl/type.tmpl +7 -0
- package/types/action_client.d.ts +8 -0
- package/types/index.d.ts +34 -0
- package/types/message_info.d.ts +72 -0
- package/types/node.d.ts +21 -0
- package/types/parameter_event_handler.d.ts +139 -0
- package/types/subscription.d.ts +14 -2
- package/rosidl_convertor/README.md +0 -298
- package/rosidl_convertor/idl_convertor.js +0 -50
- package/rosidl_convertor/idl_convertor.py +0 -1250
- package/test_data_integrity.js +0 -108
- package/test_repro_exact.js +0 -57
- package/test_repro_hz.js +0 -86
- package/test_repro_pub.js +0 -36
- package/test_repro_stress.js +0 -83
- package/test_repro_sub.js +0 -64
- package/test_xproc_data.js +0 -64
- package/types/interfaces.d.ts +0 -8895
package/README.md
CHANGED
|
@@ -1,27 +1,33 @@
|
|
|
1
|
-
# rclnodejs
|
|
1
|
+
# rclnodejs
|
|
2
2
|
|
|
3
|
-
`rclnodejs` is a Node.js client for
|
|
3
|
+
`rclnodejs` is a Node.js client library for ROS 2 that provides JavaScript and TypeScript APIs for building ROS 2 applications.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Supported ROS 2 distributions include Humble, Jazzy, Kilted, and Rolling.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
```JavaScript
|
|
7
|
+
```javascript
|
|
10
8
|
const rclnodejs = require('rclnodejs');
|
|
11
9
|
rclnodejs.init().then(() => {
|
|
12
|
-
const node = rclnodejs.
|
|
10
|
+
const node = new rclnodejs.Node('publisher_example_node');
|
|
13
11
|
const publisher = node.createPublisher('std_msgs/msg/String', 'topic');
|
|
14
12
|
publisher.publish(`Hello ROS 2 from rclnodejs`);
|
|
15
|
-
|
|
13
|
+
node.spin();
|
|
16
14
|
});
|
|
17
15
|
```
|
|
18
16
|
|
|
17
|
+
This example assumes your ROS 2 environment is already sourced.
|
|
18
|
+
|
|
19
19
|
## Installation
|
|
20
20
|
|
|
21
21
|
### Prerequisites
|
|
22
22
|
|
|
23
23
|
- [Node.js](https://nodejs.org/en/) version >= 16.13.0
|
|
24
|
-
- [ROS 2 SDK](https://docs.ros.org/en/jazzy/Installation.html)
|
|
24
|
+
- [ROS 2 SDK](https://docs.ros.org/en/jazzy/Installation.html)
|
|
25
|
+
|
|
26
|
+
Before installing or running rclnodejs, source your ROS 2 environment:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
source /opt/ros/<distro>/setup.bash
|
|
30
|
+
```
|
|
25
31
|
|
|
26
32
|
### Install rclnodejs
|
|
27
33
|
|
|
@@ -29,11 +35,17 @@ rclnodejs.init().then(() => {
|
|
|
29
35
|
npm i rclnodejs
|
|
30
36
|
```
|
|
31
37
|
|
|
32
|
-
|
|
38
|
+
To install from GitHub instead of npm, run:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install RobotWebTools/rclnodejs#<branch>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or add `"rclnodejs":"RobotWebTools/rclnodejs#<branch>"` to your `package.json` dependencies.
|
|
33
45
|
|
|
34
46
|
### Prebuilt Binaries
|
|
35
47
|
|
|
36
|
-
rclnodejs ships with prebuilt native binaries for common Linux configurations since `v1.5.2`, eliminating the need for compilation during installation. This
|
|
48
|
+
rclnodejs ships with prebuilt native binaries for common Linux configurations since `v1.5.2`, eliminating the need for compilation during installation. This applies to supported Linux environments when installing the published npm package.
|
|
37
49
|
|
|
38
50
|
**Supported Platforms:**
|
|
39
51
|
|
|
@@ -42,26 +54,39 @@ rclnodejs ships with prebuilt native binaries for common Linux configurations si
|
|
|
42
54
|
- **Architectures:** x64, arm64
|
|
43
55
|
- **Node.js:** >= 16.20.2 (N-API compatible)
|
|
44
56
|
|
|
45
|
-
|
|
57
|
+
Installations outside this prebuilt matrix automatically fall back to building from source.
|
|
46
58
|
|
|
47
|
-
|
|
59
|
+
**Force Building from Source:**
|
|
48
60
|
|
|
49
61
|
```bash
|
|
50
62
|
export RCLNODEJS_FORCE_BUILD=1
|
|
51
63
|
npm install rclnodejs
|
|
52
64
|
```
|
|
53
65
|
|
|
54
|
-
## Documentation
|
|
66
|
+
## Documentation and Examples
|
|
55
67
|
|
|
56
|
-
API [
|
|
68
|
+
- API documentation: [robotwebtools.github.io/rclnodejs/docs](https://robotwebtools.github.io/rclnodejs/docs/index.html)
|
|
69
|
+
- Tutorials: [tutorials/](https://github.com/RobotWebTools/rclnodejs/tree/develop/tutorials)
|
|
70
|
+
- JavaScript examples: [example/](https://github.com/RobotWebTools/rclnodejs/tree/develop/example)
|
|
71
|
+
- TypeScript demos: [ts_demo/](https://github.com/RobotWebTools/rclnodejs/tree/develop/ts_demo)
|
|
72
|
+
- Electron demos: [electron_demo/](https://github.com/RobotWebTools/rclnodejs/tree/develop/electron_demo)
|
|
73
|
+
- Companion CLI: [rclnodejs-cli](https://github.com/RobotWebTools/rclnodejs-cli/)
|
|
57
74
|
|
|
58
|
-
##
|
|
75
|
+
## Message Generation
|
|
59
76
|
|
|
60
|
-
|
|
77
|
+
rclnodejs generates JavaScript message interfaces and TypeScript declarations during installation for `rclnodejs > 1.5.0`. If you install additional ROS packages later, rerun the generator in your project:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npx generate-ros-messages
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Generated files are written to `<your-project>/node_modules/rclnodejs/generated/`.
|
|
84
|
+
|
|
85
|
+
This step is only needed after adding ROS packages that were not present when rclnodejs was installed.
|
|
61
86
|
|
|
62
87
|
## Using rclnodejs with TypeScript
|
|
63
88
|
|
|
64
|
-
TypeScript declaration files are included in the
|
|
89
|
+
TypeScript declaration files are included in the package. In most projects, configuring your `tsconfig.json` is sufficient:
|
|
65
90
|
|
|
66
91
|
```jsonc
|
|
67
92
|
{
|
|
@@ -73,33 +98,17 @@ TypeScript declaration files are included in the `types/` folder. Configure your
|
|
|
73
98
|
}
|
|
74
99
|
```
|
|
75
100
|
|
|
76
|
-
TypeScript example:
|
|
77
|
-
|
|
78
101
|
```typescript
|
|
79
102
|
import * as rclnodejs from 'rclnodejs';
|
|
103
|
+
|
|
80
104
|
rclnodejs.init().then(() => {
|
|
81
|
-
const node = rclnodejs.
|
|
105
|
+
const node = new rclnodejs.Node('publisher_example_node');
|
|
82
106
|
const publisher = node.createPublisher('std_msgs/msg/String', 'topic');
|
|
83
107
|
publisher.publish(`Hello ROS 2 from rclnodejs`);
|
|
84
|
-
|
|
108
|
+
node.spin();
|
|
85
109
|
});
|
|
86
110
|
```
|
|
87
111
|
|
|
88
|
-
See [TypeScript demos](https://github.com/RobotWebTools/rclnodejs/tree/develop/ts_demo) for more examples.
|
|
89
|
-
|
|
90
|
-
**Note** that the interface.d.ts file is updated each time the generate_messages.js script is run.
|
|
91
|
-
|
|
92
|
-
## Electron-based Visualization
|
|
93
|
-
|
|
94
|
-
Create rich, interactive desktop applications using Electron and web technologies like Three.js. Build 3D visualizations, monitoring dashboards, and control interfaces that run on Windows, macOS, and Linux.
|
|
95
|
-
|
|
96
|
-
| Demo | Description | Screenshot |
|
|
97
|
-
| :-----------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: |
|
|
98
|
-
| **🐢 [turtle_tf2](https://github.com/RobotWebTools/rclnodejs/tree/develop/electron_demo/turtle_tf2)** | Real-time coordinate frame visualization with turtle control. Features TF2 transforms, keyboard control, and dynamic frame updates. |  |
|
|
99
|
-
| **🦾 [manipulator](https://github.com/RobotWebTools/rclnodejs/tree/develop/electron_demo/manipulator)** | Interactive two-joint robotic arm simulation. Features 3D joint visualization, manual/automatic control, and visual movement markers. |  |
|
|
100
|
-
|
|
101
|
-
Explore more examples in [electron_demo](https://github.com/RobotWebTools/rclnodejs/tree/develop/electron_demo).
|
|
102
|
-
|
|
103
112
|
## License
|
|
104
113
|
|
|
105
114
|
Apache License Version 2.0
|
package/index.js
CHANGED
|
@@ -63,7 +63,10 @@ const {
|
|
|
63
63
|
const ParameterClient = require('./lib/parameter_client.js');
|
|
64
64
|
const errors = require('./lib/errors.js');
|
|
65
65
|
const ParameterWatcher = require('./lib/parameter_watcher.js');
|
|
66
|
+
const ParameterEventHandler = require('./lib/parameter_event_handler.js');
|
|
67
|
+
const waitForMessage = require('./lib/wait_for_message.js');
|
|
66
68
|
const MessageIntrospector = require('./lib/message_introspector.js');
|
|
69
|
+
const MessageInfo = require('./lib/message_info.js');
|
|
67
70
|
const ObservableSubscription = require('./lib/observable_subscription.js');
|
|
68
71
|
const { spawn } = require('child_process');
|
|
69
72
|
const {
|
|
@@ -85,7 +88,7 @@ async function getCurrentGeneratorVersion() {
|
|
|
85
88
|
const jsonFilePath = path.join(generator.generatedRoot, 'generator.json');
|
|
86
89
|
|
|
87
90
|
return new Promise((resolve, reject) => {
|
|
88
|
-
fs.
|
|
91
|
+
fs.readFile(jsonFilePath, 'utf8', (err, data) => {
|
|
89
92
|
if (err) {
|
|
90
93
|
if (err.code === 'ENOENT') {
|
|
91
94
|
resolve(null);
|
|
@@ -93,13 +96,11 @@ async function getCurrentGeneratorVersion() {
|
|
|
93
96
|
reject(err);
|
|
94
97
|
}
|
|
95
98
|
} else {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
});
|
|
99
|
+
try {
|
|
100
|
+
resolve(JSON.parse(data).version);
|
|
101
|
+
} catch (parseErr) {
|
|
102
|
+
reject(parseErr);
|
|
103
|
+
}
|
|
103
104
|
}
|
|
104
105
|
});
|
|
105
106
|
});
|
|
@@ -245,6 +246,12 @@ let rcl = {
|
|
|
245
246
|
/** {@link ParameterWatcher} class */
|
|
246
247
|
ParameterWatcher: ParameterWatcher,
|
|
247
248
|
|
|
249
|
+
/** {@link ParameterEventHandler} class */
|
|
250
|
+
ParameterEventHandler: ParameterEventHandler,
|
|
251
|
+
|
|
252
|
+
/** {@link MessageInfo} class */
|
|
253
|
+
MessageInfo: MessageInfo,
|
|
254
|
+
|
|
248
255
|
/** {@link ObservableSubscription} class */
|
|
249
256
|
ObservableSubscription: ObservableSubscription,
|
|
250
257
|
|
|
@@ -389,23 +396,35 @@ let rcl = {
|
|
|
389
396
|
|
|
390
397
|
rclnodejs.init(context.handle, argv, context._domainId);
|
|
391
398
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
399
|
+
try {
|
|
400
|
+
if (_rosVersionChecked) {
|
|
401
|
+
// no further processing required
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
396
404
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
+
const version = await getCurrentGeneratorVersion();
|
|
406
|
+
const forced =
|
|
407
|
+
version === null || compareVersions(version, generator.version(), '<');
|
|
408
|
+
if (forced) {
|
|
409
|
+
debug(
|
|
410
|
+
'The generator will begin to create JavaScript code from ROS IDL files...'
|
|
411
|
+
);
|
|
412
|
+
}
|
|
405
413
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
414
|
+
await generator.generateAll(forced);
|
|
415
|
+
// TODO determine if tsd generateAll() should be here
|
|
416
|
+
_rosVersionChecked = true;
|
|
417
|
+
} catch (error) {
|
|
418
|
+
try {
|
|
419
|
+
context.tryShutdown();
|
|
420
|
+
} catch (shutdownError) {
|
|
421
|
+
const initError =
|
|
422
|
+
error instanceof Error ? error : new Error(String(error));
|
|
423
|
+
initError.message += ` (rollback also failed: ${shutdownError.message})`;
|
|
424
|
+
throw initError;
|
|
425
|
+
}
|
|
426
|
+
throw error;
|
|
427
|
+
}
|
|
409
428
|
},
|
|
410
429
|
|
|
411
430
|
/**
|
|
@@ -448,6 +467,26 @@ let rcl = {
|
|
|
448
467
|
node.spinOnce(timeout);
|
|
449
468
|
},
|
|
450
469
|
|
|
470
|
+
/**
|
|
471
|
+
* Wait for a single message on a topic.
|
|
472
|
+
*
|
|
473
|
+
* Creates a temporary subscription, waits for the first message to arrive,
|
|
474
|
+
* and returns it. The temporary subscription is always cleaned up, even on
|
|
475
|
+
* timeout or error. The node must be spinning before calling this function.
|
|
476
|
+
*
|
|
477
|
+
* This is the rclnodejs equivalent of rclpy's `wait_for_message`.
|
|
478
|
+
*
|
|
479
|
+
* @param {function|string|object} typeClass - The ROS message type class.
|
|
480
|
+
* @param {Node} node - The node to create the temporary subscription on.
|
|
481
|
+
* @param {string} topic - The topic name to listen on.
|
|
482
|
+
* @param {object} [options] - Options.
|
|
483
|
+
* @param {number} [options.timeout] - Timeout in milliseconds. If omitted, waits indefinitely.
|
|
484
|
+
* @param {object} [options.qos] - QoS profile for the subscription.
|
|
485
|
+
* @returns {Promise<object>} - Resolves with the received message.
|
|
486
|
+
* @throws {Error} If timeout expires before a message arrives.
|
|
487
|
+
*/
|
|
488
|
+
waitForMessage: waitForMessage,
|
|
489
|
+
|
|
451
490
|
/**
|
|
452
491
|
* Shutdown an RCL environment identified by a context. The shutdown process will
|
|
453
492
|
* destroy all nodes and related resources in the context. If no context is
|
package/lib/action/client.js
CHANGED
|
@@ -51,6 +51,12 @@ class ActionClient extends Entity {
|
|
|
51
51
|
* @param {QoS} options.qos.feedbackSubQosProfile - Quality of service option for the feedback subscription,
|
|
52
52
|
* default: new QoS(QoS.HistoryPolicy.RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT, 10).
|
|
53
53
|
* @param {QoS} options.qos.statusSubQosProfile - Quality of service option for the status subscription, default: QoS.profileActionStatusDefault.
|
|
54
|
+
* @param {boolean} options.enableFeedbackMsgOptimization - Enable feedback subscription content filter to
|
|
55
|
+
* optimize the handling of feedback messages. When enabled, the content filter is used to configure
|
|
56
|
+
* the goal ID for the subscription, which helps avoid the reception of irrelevant feedback messages.
|
|
57
|
+
* An action client can handle up to 6 goals simultaneously with this optimization. If the number
|
|
58
|
+
* of goals exceeds the limit or the RMW doesn't support content filter, optimization is automatically
|
|
59
|
+
* disabled. Default: false.
|
|
54
60
|
*/
|
|
55
61
|
constructor(node, typeClass, actionName, options) {
|
|
56
62
|
super(null, null, options);
|
|
@@ -87,6 +93,15 @@ class ActionClient extends Entity {
|
|
|
87
93
|
checkTypes: true,
|
|
88
94
|
};
|
|
89
95
|
|
|
96
|
+
// Enable feedback subscription content filter optimization.
|
|
97
|
+
// Only supported on ROS2 Rolling and only effective when the native
|
|
98
|
+
// binding provides the required functions AND the RMW implementation
|
|
99
|
+
// actually supports content filtering on the feedback subscription.
|
|
100
|
+
this._enableFeedbackMsgOptimization =
|
|
101
|
+
this._options.enableFeedbackMsgOptimization === true &&
|
|
102
|
+
DistroUtils.getDistroId() >= DistroUtils.DistroId.ROLLING &&
|
|
103
|
+
typeof rclnodejs.actionConfigureFeedbackSubFilterAddGoalId === 'function';
|
|
104
|
+
|
|
90
105
|
let type = this.typeClass.type();
|
|
91
106
|
|
|
92
107
|
this._handle = rclnodejs.actionCreateClient(
|
|
@@ -126,6 +141,13 @@ class ActionClient extends Entity {
|
|
|
126
141
|
}
|
|
127
142
|
|
|
128
143
|
this._goalHandles.set(uuid, goalHandle);
|
|
144
|
+
this._feedbackSubFilterAddGoalId(goalHandle.goalId);
|
|
145
|
+
} else {
|
|
146
|
+
// Clean up feedback callback for rejected goals
|
|
147
|
+
let uuid = ActionUuid.fromMessage(
|
|
148
|
+
this._sequenceNumberGoalIdMap.get(sequence)
|
|
149
|
+
).toString();
|
|
150
|
+
this._feedbackCallbacks.delete(uuid);
|
|
129
151
|
}
|
|
130
152
|
|
|
131
153
|
this._pendingGoalRequests.get(sequence).setResult(goalHandle);
|
|
@@ -199,6 +221,9 @@ class ActionClient extends Entity {
|
|
|
199
221
|
status === ActionInterfaces.GoalStatus.STATUS_ABORTED
|
|
200
222
|
) {
|
|
201
223
|
this._goalHandles.delete(uuid);
|
|
224
|
+
this._feedbackSubFilterRemoveGoalId(
|
|
225
|
+
statusMessage.goal_info.goal_id
|
|
226
|
+
);
|
|
202
227
|
}
|
|
203
228
|
}
|
|
204
229
|
} else {
|
|
@@ -387,6 +412,8 @@ class ActionClient extends Entity {
|
|
|
387
412
|
this._removePendingCancelRequest(sequenceNumber)
|
|
388
413
|
);
|
|
389
414
|
|
|
415
|
+
this._feedbackSubFilterRemoveGoalId(goalHandle.goalId);
|
|
416
|
+
|
|
390
417
|
return deferred.promise;
|
|
391
418
|
}
|
|
392
419
|
|
|
@@ -436,9 +463,10 @@ class ActionClient extends Entity {
|
|
|
436
463
|
goalHandle.status = result.status;
|
|
437
464
|
return result.result;
|
|
438
465
|
});
|
|
439
|
-
deferred.setDoneCallback(() =>
|
|
440
|
-
this._removePendingResultRequest(sequenceNumber)
|
|
441
|
-
|
|
466
|
+
deferred.setDoneCallback(() => {
|
|
467
|
+
this._removePendingResultRequest(sequenceNumber);
|
|
468
|
+
this._feedbackSubFilterRemoveGoalId(goalHandle.goalId);
|
|
469
|
+
});
|
|
442
470
|
|
|
443
471
|
this._pendingResultRequests.set(sequenceNumber, deferred);
|
|
444
472
|
|
|
@@ -458,6 +486,42 @@ class ActionClient extends Entity {
|
|
|
458
486
|
this._pendingCancelRequests.delete(sequenceNumber);
|
|
459
487
|
}
|
|
460
488
|
|
|
489
|
+
/**
|
|
490
|
+
* Add a goal ID to the feedback subscription content filter.
|
|
491
|
+
* @ignore
|
|
492
|
+
* @param {object} goalId - The goal UUID message.
|
|
493
|
+
*/
|
|
494
|
+
_feedbackSubFilterAddGoalId(goalId) {
|
|
495
|
+
if (!this._enableFeedbackMsgOptimization) return;
|
|
496
|
+
try {
|
|
497
|
+
rclnodejs.actionConfigureFeedbackSubFilterAddGoalId(
|
|
498
|
+
this.handle,
|
|
499
|
+
Buffer.from(goalId.uuid)
|
|
500
|
+
);
|
|
501
|
+
} catch (e) {
|
|
502
|
+
this._enableFeedbackMsgOptimization = false;
|
|
503
|
+
this._node.getLogger().warn(`${e.message}`);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Remove a goal ID from the feedback subscription content filter.
|
|
509
|
+
* @ignore
|
|
510
|
+
* @param {object} goalId - The goal UUID message.
|
|
511
|
+
*/
|
|
512
|
+
_feedbackSubFilterRemoveGoalId(goalId) {
|
|
513
|
+
if (!this._enableFeedbackMsgOptimization) return;
|
|
514
|
+
try {
|
|
515
|
+
rclnodejs.actionConfigureFeedbackSubFilterRemoveGoalId(
|
|
516
|
+
this.handle,
|
|
517
|
+
Buffer.from(goalId.uuid)
|
|
518
|
+
);
|
|
519
|
+
} catch (e) {
|
|
520
|
+
this._enableFeedbackMsgOptimization = false;
|
|
521
|
+
this._node.getLogger().warn(`${e.message}`);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
461
525
|
/**
|
|
462
526
|
* Destroy the underlying action client handle.
|
|
463
527
|
* @return {undefined}
|
package/lib/action/server.js
CHANGED
|
@@ -437,10 +437,8 @@ class ActionServer extends Entity {
|
|
|
437
437
|
|
|
438
438
|
_executeExpiredGoals(result, count) {
|
|
439
439
|
for (let i = 0; i < count; i++) {
|
|
440
|
-
const goal = result.data[i];
|
|
441
|
-
|
|
442
440
|
const goalInfo = new ActionInterfaces.GoalInfo();
|
|
443
|
-
goalInfo.deserialize(
|
|
441
|
+
goalInfo.deserialize(result._refArray[i]);
|
|
444
442
|
|
|
445
443
|
let uuid = ActionUuid.fromBytes(goalInfo.goal_id.uuid).toString();
|
|
446
444
|
this._goalHandles.delete(uuid);
|
package/lib/distro.js
CHANGED
|
@@ -65,7 +65,8 @@ const DistroUtils = {
|
|
|
65
65
|
return process.env.ROS_DISTRO;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
const result = [...DistroNameIdMap].find(([, val]) => val == distroId);
|
|
69
|
+
return result ? result[0] : undefined;
|
|
69
70
|
},
|
|
70
71
|
|
|
71
72
|
getKnownDistroNames: function () {
|
|
@@ -30,7 +30,7 @@ class LifecyclePublisher extends Publisher {
|
|
|
30
30
|
super(handle, typeClass, /*topic=*/ '', options);
|
|
31
31
|
|
|
32
32
|
this._enabled = false;
|
|
33
|
-
this.
|
|
33
|
+
this._logger = Logging.getLogger('LifecyclePublisher');
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
|
@@ -42,7 +42,7 @@ class LifecyclePublisher extends Publisher {
|
|
|
42
42
|
*/
|
|
43
43
|
publish(message) {
|
|
44
44
|
if (!this._enabled) {
|
|
45
|
-
this.
|
|
45
|
+
this._logger.warn(
|
|
46
46
|
`Trying to publish message on the topic ${this.topic}, but the publisher is not activated`
|
|
47
47
|
);
|
|
48
48
|
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// Copyright (c) 2026, The Robot Web Tools Contributors
|
|
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
|
+
/**
|
|
18
|
+
* @class MessageInfo
|
|
19
|
+
*
|
|
20
|
+
* Contains metadata about a received message, including timestamps,
|
|
21
|
+
* sequence numbers, and the publisher's globally unique identifier (GID).
|
|
22
|
+
*
|
|
23
|
+
* This is the rclnodejs equivalent of rclpy's MessageInfo.
|
|
24
|
+
* It is passed as the second argument to subscription callbacks when the
|
|
25
|
+
* callback accepts two parameters.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* node.createSubscription(
|
|
29
|
+
* 'std_msgs/msg/String',
|
|
30
|
+
* 'topic',
|
|
31
|
+
* (msg, messageInfo) => {
|
|
32
|
+
* console.log('Source timestamp:', messageInfo.sourceTimestamp);
|
|
33
|
+
* console.log('Received at:', messageInfo.receivedTimestamp);
|
|
34
|
+
* console.log('Publisher GID:', messageInfo.publisherGid);
|
|
35
|
+
* }
|
|
36
|
+
* );
|
|
37
|
+
*/
|
|
38
|
+
class MessageInfo {
|
|
39
|
+
/**
|
|
40
|
+
* Create a MessageInfo from a raw info object returned by the native layer.
|
|
41
|
+
*
|
|
42
|
+
* @param {object} rawInfo - Raw message info from rclTakeWithInfo
|
|
43
|
+
* @hideconstructor
|
|
44
|
+
*/
|
|
45
|
+
constructor(rawInfo) {
|
|
46
|
+
/**
|
|
47
|
+
* The timestamp when the message was published (nanoseconds since epoch).
|
|
48
|
+
* @type {bigint}
|
|
49
|
+
*/
|
|
50
|
+
this.sourceTimestamp = rawInfo.source_timestamp;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The timestamp when the message was received by the subscription (nanoseconds since epoch).
|
|
54
|
+
* @type {bigint}
|
|
55
|
+
*/
|
|
56
|
+
this.receivedTimestamp = rawInfo.received_timestamp;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The publication sequence number assigned by the publisher.
|
|
60
|
+
* @type {bigint}
|
|
61
|
+
*/
|
|
62
|
+
this.publicationSequenceNumber = rawInfo.publication_sequence_number;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* The reception sequence number assigned by the subscriber.
|
|
66
|
+
* @type {bigint}
|
|
67
|
+
*/
|
|
68
|
+
this.receptionSequenceNumber = rawInfo.reception_sequence_number;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The globally unique identifier (GID) of the publisher.
|
|
72
|
+
* A Buffer containing the raw GID bytes.
|
|
73
|
+
* @type {Buffer}
|
|
74
|
+
*/
|
|
75
|
+
this.publisherGid = rawInfo.publisher_gid;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Convert to a plain object representation.
|
|
80
|
+
*
|
|
81
|
+
* @returns {object} Plain object with all metadata fields
|
|
82
|
+
*/
|
|
83
|
+
toPlainObject() {
|
|
84
|
+
return {
|
|
85
|
+
sourceTimestamp: this.sourceTimestamp,
|
|
86
|
+
receivedTimestamp: this.receivedTimestamp,
|
|
87
|
+
publicationSequenceNumber: this.publicationSequenceNumber,
|
|
88
|
+
receptionSequenceNumber: this.receptionSequenceNumber,
|
|
89
|
+
publisherGid: this.publisherGid,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = MessageInfo;
|