rclnodejs 1.8.3 → 1.9.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 +39 -0
- package/lib/action/client.js +61 -3
- package/lib/action/server_goal_handle.js +26 -1
- package/lib/message_info.js +94 -0
- package/lib/node.js +260 -13
- package/lib/parameter_event_handler.js +566 -0
- package/lib/parameter_watcher.js +12 -12
- package/lib/qos_overriding_options.js +358 -0
- package/lib/subscription.js +38 -5
- package/lib/timer.js +3 -2
- 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/scripts/run_asan_test.sh +118 -0
- package/src/executor.cpp +36 -2
- package/src/executor.h +11 -0
- package/src/rcl_action_client_bindings.cpp +70 -1
- package/src/rcl_context_bindings.cpp +3 -3
- package/src/rcl_graph_bindings.cpp +2 -2
- package/src/rcl_subscription_bindings.cpp +70 -2
- package/src/rcl_timer_bindings.cpp +21 -2
- 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 +90 -5
- package/types/parameter_event_handler.d.ts +150 -0
- package/types/qos.d.ts +55 -0
- package/types/subscription.d.ts +14 -2
- package/types/timer.d.ts +3 -2
- 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
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<section class="doc-section prose-section tutorial-section">
|
|
2
|
+
|
|
3
|
+
<header class="doc-page-header">
|
|
4
|
+
<?js if (children.length > 0) { ?>
|
|
5
|
+
<ul class="tutorial-children"><?js
|
|
6
|
+
var self = this;
|
|
7
|
+
children.forEach(function(t) { ?>
|
|
8
|
+
<li><?js= self.tutoriallink(t.name) ?></li>
|
|
9
|
+
<?js }); ?></ul>
|
|
10
|
+
<?js } ?>
|
|
11
|
+
|
|
12
|
+
<h2 class="doc-heading"><?js= header ?></h2>
|
|
13
|
+
</header>
|
|
14
|
+
|
|
15
|
+
<article class="prose-card">
|
|
16
|
+
<?js= content ?>
|
|
17
|
+
</article>
|
|
18
|
+
|
|
19
|
+
</section>
|
package/types/action_client.d.ts
CHANGED
|
@@ -142,6 +142,14 @@ declare module 'rclnodejs' {
|
|
|
142
142
|
options?: Options<ActionQoS> & {
|
|
143
143
|
validateGoals?: boolean;
|
|
144
144
|
validationOptions?: MessageValidationOptions;
|
|
145
|
+
/**
|
|
146
|
+
* Enable feedback subscription content filter to optimize the handling
|
|
147
|
+
* of feedback messages. When enabled, the content filter is used to
|
|
148
|
+
* configure the goal ID for the subscription, avoiding reception of
|
|
149
|
+
* irrelevant feedback messages. An action client can handle up to 6
|
|
150
|
+
* goals simultaneously with this optimization. Default: false.
|
|
151
|
+
*/
|
|
152
|
+
enableFeedbackMsgOptimization?: boolean;
|
|
145
153
|
}
|
|
146
154
|
);
|
|
147
155
|
|
package/types/index.d.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
/// <reference path="./clock_event.d.ts" />
|
|
3
3
|
/// <reference path="./clock_change.d.ts" />
|
|
4
4
|
/// <reference path="./message_validation.d.ts" />
|
|
5
|
+
/// <reference path="./parameter_event_handler.d.ts" />
|
|
6
|
+
/// <reference path="./message_info.d.ts" />
|
|
5
7
|
|
|
6
8
|
import { ChildProcess } from 'child_process';
|
|
7
9
|
|
|
@@ -85,6 +87,38 @@ declare module 'rclnodejs' {
|
|
|
85
87
|
* @deprecated since 0.18.0, Use Node.spinOnce(timeout)*/
|
|
86
88
|
function spinOnce(node: Node, timeout?: number): void;
|
|
87
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Options for waitForMessage.
|
|
92
|
+
*/
|
|
93
|
+
interface WaitForMessageOptions {
|
|
94
|
+
/** Timeout in milliseconds. If omitted, waits indefinitely. */
|
|
95
|
+
timeout?: number;
|
|
96
|
+
/** QoS profile for the temporary subscription. */
|
|
97
|
+
qos?: QoS;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Wait for a single message on a topic.
|
|
102
|
+
*
|
|
103
|
+
* Creates a temporary subscription, waits for the first message to arrive,
|
|
104
|
+
* and returns it. The node must be spinning before calling this function.
|
|
105
|
+
*
|
|
106
|
+
* This is the rclnodejs equivalent of rclpy's `wait_for_message`.
|
|
107
|
+
*
|
|
108
|
+
* @param typeClass - The ROS message type class.
|
|
109
|
+
* @param node - The node to create the temporary subscription on.
|
|
110
|
+
* @param topic - The topic name to listen on.
|
|
111
|
+
* @param options - Options including timeout and QoS.
|
|
112
|
+
* @returns Resolves with the received message.
|
|
113
|
+
* @throws Error if timeout expires before a message arrives.
|
|
114
|
+
*/
|
|
115
|
+
function waitForMessage<T extends TypeClass<MessageTypeClassName>>(
|
|
116
|
+
typeClass: T,
|
|
117
|
+
node: Node,
|
|
118
|
+
topic: string,
|
|
119
|
+
options?: WaitForMessageOptions
|
|
120
|
+
): Promise<MessageType<T>>;
|
|
121
|
+
|
|
88
122
|
/**
|
|
89
123
|
* Stop all activity, destroy all nodes and node components.
|
|
90
124
|
*
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
declare module 'rclnodejs' {
|
|
16
|
+
/**
|
|
17
|
+
* Contains metadata about a received message, including timestamps,
|
|
18
|
+
* sequence numbers, and the publisher's globally unique identifier (GID).
|
|
19
|
+
*
|
|
20
|
+
* Passed as the second argument to subscription callbacks when the
|
|
21
|
+
* callback accepts two parameters.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* node.createSubscription(
|
|
26
|
+
* 'std_msgs/msg/String',
|
|
27
|
+
* 'topic',
|
|
28
|
+
* (msg: rclnodejs.std_msgs.msg.String, info: MessageInfo) => {
|
|
29
|
+
* console.log('Source timestamp:', info.sourceTimestamp);
|
|
30
|
+
* }
|
|
31
|
+
* );
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
class MessageInfo {
|
|
35
|
+
/**
|
|
36
|
+
* The timestamp when the message was published (nanoseconds since epoch).
|
|
37
|
+
*/
|
|
38
|
+
readonly sourceTimestamp: bigint;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The timestamp when the message was received by the subscription (nanoseconds since epoch).
|
|
42
|
+
*/
|
|
43
|
+
readonly receivedTimestamp: bigint;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* The publication sequence number assigned by the publisher.
|
|
47
|
+
*/
|
|
48
|
+
readonly publicationSequenceNumber: bigint;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The reception sequence number assigned by the subscriber.
|
|
52
|
+
*/
|
|
53
|
+
readonly receptionSequenceNumber: bigint;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* The globally unique identifier (GID) of the publisher.
|
|
57
|
+
* A Buffer containing the raw GID bytes.
|
|
58
|
+
*/
|
|
59
|
+
readonly publisherGid: Buffer;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Convert to a plain object representation.
|
|
63
|
+
*/
|
|
64
|
+
toPlainObject(): {
|
|
65
|
+
sourceTimestamp: bigint;
|
|
66
|
+
receivedTimestamp: bigint;
|
|
67
|
+
publicationSequenceNumber: bigint;
|
|
68
|
+
receptionSequenceNumber: bigint;
|
|
69
|
+
publisherGid: Buffer;
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
package/types/node.d.ts
CHANGED
|
@@ -80,6 +80,13 @@ declare module 'rclnodejs' {
|
|
|
80
80
|
* inspect and limit messages that it accepts.
|
|
81
81
|
*/
|
|
82
82
|
contentFilter?: SubscriptionContentFilter;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* If provided, declares read-only ROS parameters for the specified QoS policies.
|
|
86
|
+
* These can be overridden at startup via `--ros-args -p` or `--params-file`.
|
|
87
|
+
* If qos is a profile string, it will be resolved to a mutable QoS object.
|
|
88
|
+
*/
|
|
89
|
+
qosOverridingOptions?: QoSOverridingOptions;
|
|
83
90
|
}
|
|
84
91
|
|
|
85
92
|
/**
|
|
@@ -97,14 +104,24 @@ declare module 'rclnodejs' {
|
|
|
97
104
|
*/
|
|
98
105
|
const DEFAULT_OPTIONS: Options;
|
|
99
106
|
|
|
107
|
+
interface TimerInfo {
|
|
108
|
+
expectedCallTime: bigint;
|
|
109
|
+
actualCallTime: bigint;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
interface TimerOptions {
|
|
113
|
+
autostart?: boolean;
|
|
114
|
+
}
|
|
115
|
+
|
|
100
116
|
/**
|
|
101
117
|
* Callback for receiving periodic interrupts from a Timer.
|
|
118
|
+
* Receives timer metadata when the underlying ROS distro exposes it.
|
|
102
119
|
*
|
|
103
120
|
* @remarks
|
|
104
121
|
* See {@link Node.createTimer | Node.createTimer}
|
|
105
122
|
* See {@link Timer}
|
|
106
123
|
*/
|
|
107
|
-
type TimerRequestCallback = () => void;
|
|
124
|
+
type TimerRequestCallback = (timerInfo?: TimerInfo) => void;
|
|
108
125
|
|
|
109
126
|
/**
|
|
110
127
|
* Callback indicating parameters are about to be declared or set.
|
|
@@ -123,6 +140,19 @@ declare module 'rclnodejs' {
|
|
|
123
140
|
parameters: Parameter[]
|
|
124
141
|
) => rcl_interfaces.msg.SetParametersResult;
|
|
125
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Callback invoked before parameter validation and setting.
|
|
145
|
+
* Receives the parameter list, must return a (possibly modified) parameter list.
|
|
146
|
+
* Returning an empty list rejects the set.
|
|
147
|
+
*/
|
|
148
|
+
type PreSetParametersCallback = (parameters: Parameter[]) => Parameter[];
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Callback invoked after parameters have been successfully set.
|
|
152
|
+
* For side effects only (return value is ignored).
|
|
153
|
+
*/
|
|
154
|
+
type PostSetParametersCallback = (parameters: Parameter[]) => void;
|
|
155
|
+
|
|
126
156
|
/**
|
|
127
157
|
* Standard result of Node.getXXXNamesAndTypes() queries
|
|
128
158
|
*
|
|
@@ -293,15 +323,18 @@ declare module 'rclnodejs' {
|
|
|
293
323
|
/**
|
|
294
324
|
* Create a Timer.
|
|
295
325
|
*
|
|
296
|
-
* @param period - Elapsed time between interrupt events
|
|
297
|
-
* @param callback - Called
|
|
298
|
-
* @param
|
|
326
|
+
* @param period - Elapsed time between interrupt events in nanoseconds.
|
|
327
|
+
* @param callback - Called when the timer fires. Receives a `TimerInfo` argument when available.
|
|
328
|
+
* @param optionsOrClock - Optional timer options or clock to use for the timer.
|
|
329
|
+
* Supports `{ autostart?: boolean }` when an options object is provided.
|
|
330
|
+
* @param clock - Optional clock to use for the timer when options are provided.
|
|
299
331
|
* @returns New instance of Timer.
|
|
300
332
|
*/
|
|
301
333
|
createTimer(
|
|
302
334
|
period: bigint,
|
|
303
335
|
callback: TimerRequestCallback,
|
|
304
|
-
|
|
336
|
+
optionsOrClock?: TimerOptions | Clock | null,
|
|
337
|
+
clock?: Clock | null
|
|
305
338
|
): Timer;
|
|
306
339
|
|
|
307
340
|
/**
|
|
@@ -511,6 +544,27 @@ declare module 'rclnodejs' {
|
|
|
511
544
|
*/
|
|
512
545
|
destroyParameterWatcher(watcher: ParameterWatcher): void;
|
|
513
546
|
|
|
547
|
+
/**
|
|
548
|
+
* Create a ParameterEventHandler that monitors parameter changes on any node.
|
|
549
|
+
*
|
|
550
|
+
* Unlike ParameterWatcher which watches specific parameters on a single
|
|
551
|
+
* remote node, ParameterEventHandler can register callbacks for parameters
|
|
552
|
+
* on any node in the ROS 2 graph by subscribing to /parameter_events.
|
|
553
|
+
*
|
|
554
|
+
* @param options - Options for the handler.
|
|
555
|
+
* @returns An instance of ParameterEventHandler.
|
|
556
|
+
*/
|
|
557
|
+
createParameterEventHandler(
|
|
558
|
+
options?: ParameterEventHandlerOptions
|
|
559
|
+
): ParameterEventHandler;
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* Destroy a ParameterEventHandler.
|
|
563
|
+
*
|
|
564
|
+
* @param handler - ParameterEventHandler to be destroyed.
|
|
565
|
+
*/
|
|
566
|
+
destroyParameterEventHandler(handler: ParameterEventHandler): void;
|
|
567
|
+
|
|
514
568
|
/**
|
|
515
569
|
* Destroy a Timer.
|
|
516
570
|
*
|
|
@@ -728,6 +782,37 @@ declare module 'rclnodejs' {
|
|
|
728
782
|
*/
|
|
729
783
|
removeOnSetParametersCallback(call: SetParametersCallback): void;
|
|
730
784
|
|
|
785
|
+
/**
|
|
786
|
+
* Add a callback invoked before parameter validation.
|
|
787
|
+
* The callback receives the parameter list and must return a (possibly modified)
|
|
788
|
+
* parameter list. Returning an empty list rejects the set.
|
|
789
|
+
*
|
|
790
|
+
* @param callback - The callback to add.
|
|
791
|
+
*/
|
|
792
|
+
addPreSetParametersCallback(callback: PreSetParametersCallback): void;
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* Remove a pre-set parameters callback.
|
|
796
|
+
*
|
|
797
|
+
* @param callback - The callback to remove.
|
|
798
|
+
*/
|
|
799
|
+
removePreSetParametersCallback(callback: PreSetParametersCallback): void;
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* Add a callback invoked after parameters are successfully set.
|
|
803
|
+
* Useful for triggering side effects (e.g., reconfiguring a component).
|
|
804
|
+
*
|
|
805
|
+
* @param callback - The callback to add.
|
|
806
|
+
*/
|
|
807
|
+
addPostSetParametersCallback(callback: PostSetParametersCallback): void;
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* Remove a post-set parameters callback.
|
|
811
|
+
*
|
|
812
|
+
* @param callback - The callback to remove.
|
|
813
|
+
*/
|
|
814
|
+
removePostSetParametersCallback(callback: PostSetParametersCallback): void;
|
|
815
|
+
|
|
731
816
|
/**
|
|
732
817
|
* Get a remote node's published topics.
|
|
733
818
|
*
|
|
@@ -0,0 +1,150 @@
|
|
|
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
|
+
declare module 'rclnodejs' {
|
|
16
|
+
/**
|
|
17
|
+
* Options for ParameterEventHandler constructor.
|
|
18
|
+
*/
|
|
19
|
+
export interface ParameterEventHandlerOptions {
|
|
20
|
+
/**
|
|
21
|
+
* QoS profile for the parameter_events subscription.
|
|
22
|
+
*/
|
|
23
|
+
qos?: QoS;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Opaque handle returned when adding a parameter callback.
|
|
28
|
+
* Used to remove the callback later via removeParameterCallback().
|
|
29
|
+
*/
|
|
30
|
+
class ParameterCallbackHandle {
|
|
31
|
+
readonly parameterName: string;
|
|
32
|
+
readonly nodeName: string;
|
|
33
|
+
readonly callback: (parameter: any) => void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Opaque handle returned when adding a parameter event callback.
|
|
38
|
+
* Used to remove the callback later via removeParameterEventCallback().
|
|
39
|
+
*/
|
|
40
|
+
class ParameterEventCallbackHandle {
|
|
41
|
+
readonly callback: (event: any) => void;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* ParameterEventHandler - Monitors and responds to parameter changes
|
|
46
|
+
* on any node in the ROS 2 graph.
|
|
47
|
+
*
|
|
48
|
+
* Subscribes to `/parameter_events` and dispatches callbacks when
|
|
49
|
+
* parameters are added, changed, or deleted on any node.
|
|
50
|
+
*
|
|
51
|
+
* Two types of callbacks:
|
|
52
|
+
* - **Parameter callbacks**: for a specific parameter on a specific node
|
|
53
|
+
* - **Event callbacks**: for every ParameterEvent message received
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const handler = node.createParameterEventHandler();
|
|
58
|
+
*
|
|
59
|
+
* const handle = handler.addParameterCallback(
|
|
60
|
+
* 'my_param', '/my_node',
|
|
61
|
+
* (param) => console.log(`Changed: ${param.name}`)
|
|
62
|
+
* );
|
|
63
|
+
*
|
|
64
|
+
* handler.removeParameterCallback(handle);
|
|
65
|
+
* handler.destroy();
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
class ParameterEventHandler {
|
|
69
|
+
/**
|
|
70
|
+
* Add a callback for a specific parameter on a specific node.
|
|
71
|
+
*
|
|
72
|
+
* @param parameterName - Name of the parameter to monitor.
|
|
73
|
+
* @param nodeName - Fully qualified name of the node (e.g., '/my_node').
|
|
74
|
+
* @param callback - Called with the parameter message when it changes.
|
|
75
|
+
* @returns A handle for removing this callback later.
|
|
76
|
+
*/
|
|
77
|
+
addParameterCallback(
|
|
78
|
+
parameterName: string,
|
|
79
|
+
nodeName: string,
|
|
80
|
+
callback: (parameter: any) => void
|
|
81
|
+
): ParameterCallbackHandle;
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Remove a previously added parameter callback.
|
|
85
|
+
*
|
|
86
|
+
* @param handle - The handle returned by addParameterCallback.
|
|
87
|
+
*/
|
|
88
|
+
removeParameterCallback(handle: ParameterCallbackHandle): void;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Add a callback that is invoked for every parameter event.
|
|
92
|
+
*
|
|
93
|
+
* @param callback - Called with the full ParameterEvent message.
|
|
94
|
+
* @returns A handle for removing this callback later.
|
|
95
|
+
*/
|
|
96
|
+
addParameterEventCallback(
|
|
97
|
+
callback: (event: any) => void
|
|
98
|
+
): ParameterEventCallbackHandle;
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Configure which node parameter events will be received.
|
|
102
|
+
*
|
|
103
|
+
* If nodeNames is omitted or empty, the node filter is cleared.
|
|
104
|
+
* Relative names are resolved against the handler node namespace.
|
|
105
|
+
*
|
|
106
|
+
* @param nodeNames - Node names to filter parameter events from.
|
|
107
|
+
* @returns True if the filter is active or was successfully cleared.
|
|
108
|
+
*/
|
|
109
|
+
configureNodesFilter(nodeNames?: string[]): boolean;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Remove a previously added parameter event callback.
|
|
113
|
+
*
|
|
114
|
+
* @param handle - The handle returned by addParameterEventCallback.
|
|
115
|
+
*/
|
|
116
|
+
removeParameterEventCallback(handle: ParameterEventCallbackHandle): void;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Check if the handler has been destroyed.
|
|
120
|
+
*/
|
|
121
|
+
isDestroyed(): boolean;
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Destroy the handler and clean up resources.
|
|
125
|
+
*/
|
|
126
|
+
destroy(): void;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get a specific parameter from a ParameterEvent message.
|
|
130
|
+
*
|
|
131
|
+
* @param event - A ParameterEvent message.
|
|
132
|
+
* @param parameterName - The parameter name to look for.
|
|
133
|
+
* @param nodeName - The node name to match.
|
|
134
|
+
* @returns The matching parameter message, or null.
|
|
135
|
+
*/
|
|
136
|
+
static getParameterFromEvent(
|
|
137
|
+
event: any,
|
|
138
|
+
parameterName: string,
|
|
139
|
+
nodeName: string
|
|
140
|
+
): any | null;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get all parameters from a ParameterEvent message (new + changed).
|
|
144
|
+
*
|
|
145
|
+
* @param event - A ParameterEvent message.
|
|
146
|
+
* @returns Array of parameter messages.
|
|
147
|
+
*/
|
|
148
|
+
static getParametersFromEvent(event: any): any[];
|
|
149
|
+
}
|
|
150
|
+
}
|
package/types/qos.d.ts
CHANGED
|
@@ -134,4 +134,59 @@ declare module 'rclnodejs' {
|
|
|
134
134
|
RMW_QOS_POLICY_LIVELINESS_BEST_AVAILABLE = 5,
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Enum of overridable QoS policy kinds.
|
|
140
|
+
*/
|
|
141
|
+
enum QoSPolicyKind {
|
|
142
|
+
HISTORY = 1,
|
|
143
|
+
DEPTH = 2,
|
|
144
|
+
RELIABILITY = 3,
|
|
145
|
+
DURABILITY = 4,
|
|
146
|
+
LIVELINESS = 5,
|
|
147
|
+
AVOID_ROS_NAMESPACE_CONVENTIONS = 6,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Options for overriding QoS policies via ROS parameters.
|
|
152
|
+
*
|
|
153
|
+
* When passed to `createPublisher()` or `createSubscription()`, the node
|
|
154
|
+
* declares read-only parameters for each specified policy kind. These
|
|
155
|
+
* parameters can be overridden at startup via `--ros-args -p` or `--params-file`.
|
|
156
|
+
*
|
|
157
|
+
* Parameter naming convention:
|
|
158
|
+
* `qos_overrides.<topic>.<publisher|subscription>[_<entityId>].<policy>`
|
|
159
|
+
*/
|
|
160
|
+
class QoSOverridingOptions {
|
|
161
|
+
/**
|
|
162
|
+
* @param policyKinds - Which QoS policies to expose as parameters.
|
|
163
|
+
* @param opts - Optional callback and entityId.
|
|
164
|
+
*/
|
|
165
|
+
constructor(
|
|
166
|
+
policyKinds: QoSPolicyKind[],
|
|
167
|
+
opts?: {
|
|
168
|
+
callback?: (qos: QoS) => { successful: boolean; reason?: string };
|
|
169
|
+
entityId?: string;
|
|
170
|
+
}
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
/** Which QoS policies are exposed as parameters. */
|
|
174
|
+
readonly policyKinds: QoSPolicyKind[];
|
|
175
|
+
|
|
176
|
+
/** Optional validation callback. */
|
|
177
|
+
readonly callback:
|
|
178
|
+
| ((qos: QoS) => { successful: boolean; reason?: string })
|
|
179
|
+
| null;
|
|
180
|
+
|
|
181
|
+
/** Optional entity disambiguation suffix. */
|
|
182
|
+
readonly entityId: string | null;
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Create options that override history, depth, and reliability.
|
|
186
|
+
*/
|
|
187
|
+
static withDefaultPolicies(opts?: {
|
|
188
|
+
callback?: (qos: QoS) => { successful: boolean; reason?: string };
|
|
189
|
+
entityId?: string;
|
|
190
|
+
}): QoSOverridingOptions;
|
|
191
|
+
}
|
|
137
192
|
}
|
package/types/subscription.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
declare module 'rclnodejs' {
|
|
2
2
|
/**
|
|
3
3
|
* A callback for receiving published messages.
|
|
4
|
+
* If the callback accepts two parameters, the second will be a MessageInfo
|
|
5
|
+
* containing metadata about the received message.
|
|
4
6
|
*
|
|
5
7
|
* @param message - The published message.
|
|
8
|
+
* @param messageInfo - Optional metadata about the message (timestamps, publisher GID, etc).
|
|
6
9
|
*
|
|
7
10
|
* @remarks
|
|
8
11
|
* See {@link Node#createSubscription | Node.createSubscription}
|
|
@@ -13,12 +16,15 @@ declare module 'rclnodejs' {
|
|
|
13
16
|
*/
|
|
14
17
|
type SubscriptionCallback<T extends TypeClass<MessageTypeClassName>> =
|
|
15
18
|
// * @param message - The published message
|
|
16
|
-
(message: MessageType<T
|
|
19
|
+
(message: MessageType<T>, messageInfo?: MessageInfo) => void;
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* A callback for receiving published raw messages.
|
|
23
|
+
* If the callback accepts a second parameter, it will receive a MessageInfo
|
|
24
|
+
* containing metadata about the received message.
|
|
20
25
|
*
|
|
21
26
|
* @param message - The published message.
|
|
27
|
+
* @param messageInfo - Optional metadata about the message.
|
|
22
28
|
*
|
|
23
29
|
* @remarks
|
|
24
30
|
* See {@link Node#createSubscription | Node.createSubscription}
|
|
@@ -29,7 +35,7 @@ declare module 'rclnodejs' {
|
|
|
29
35
|
*/
|
|
30
36
|
type SubscriptionWithRawMessageCallback =
|
|
31
37
|
// * @param message - The published raw message
|
|
32
|
-
(message: Buffer) => void;
|
|
38
|
+
(message: Buffer, messageInfo?: MessageInfo) => void;
|
|
33
39
|
|
|
34
40
|
/**
|
|
35
41
|
* A ROS Subscription for published messages on a topic.
|
|
@@ -45,6 +51,12 @@ declare module 'rclnodejs' {
|
|
|
45
51
|
*/
|
|
46
52
|
readonly isRaw: boolean;
|
|
47
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Check if content filtering is supported for this subscription.
|
|
56
|
+
* @returns True if the subscription instance supports content filtering; otherwise false.
|
|
57
|
+
*/
|
|
58
|
+
isContentFilterSupported(): boolean;
|
|
59
|
+
|
|
48
60
|
/**
|
|
49
61
|
* Test if the RMW supports content-filtered topics and that this subscription
|
|
50
62
|
* is configured with a well formed content-filter.
|
package/types/timer.d.ts
CHANGED
|
@@ -78,8 +78,9 @@ declare module 'rclnodejs' {
|
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
80
|
* Call a timer and starts counting again, retrieves actual and expected call time.
|
|
81
|
-
*
|
|
81
|
+
*
|
|
82
|
+
* @return The timer information with expected and actual call timestamps.
|
|
82
83
|
*/
|
|
83
|
-
callTimerWithInfo():
|
|
84
|
+
callTimerWithInfo(): TimerInfo;
|
|
84
85
|
}
|
|
85
86
|
}
|
package/test_data_integrity.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
// Data integrity + throughput test for subscription
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const rclnodejs = require('./index.js');
|
|
5
|
-
|
|
6
|
-
const PUBLISH_HZ = 50;
|
|
7
|
-
const TEST_DURATION_SEC = 10;
|
|
8
|
-
|
|
9
|
-
async function main() {
|
|
10
|
-
await rclnodejs.init();
|
|
11
|
-
|
|
12
|
-
const pubNode = new rclnodejs.Node('data_pub_node');
|
|
13
|
-
const subNode = new rclnodejs.Node('data_sub_node');
|
|
14
|
-
|
|
15
|
-
const publisher = pubNode.createPublisher(
|
|
16
|
-
'std_msgs/msg/Float64MultiArray',
|
|
17
|
-
'/data_integrity_topic'
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
let msgCount = 0;
|
|
21
|
-
let errCount = 0;
|
|
22
|
-
let lastTs = null;
|
|
23
|
-
const hzSamples = [];
|
|
24
|
-
const errors = [];
|
|
25
|
-
|
|
26
|
-
subNode.createSubscription(
|
|
27
|
-
'std_msgs/msg/Float64MultiArray',
|
|
28
|
-
'/data_integrity_topic',
|
|
29
|
-
(msg) => {
|
|
30
|
-
const now = Date.now();
|
|
31
|
-
msgCount++;
|
|
32
|
-
|
|
33
|
-
// --- Data validation ---
|
|
34
|
-
// Each published message has data = [seqNo, seqNo*1.5, seqNo*2.5]
|
|
35
|
-
// Verify structure and values
|
|
36
|
-
if (!msg || !msg.data) {
|
|
37
|
-
errCount++;
|
|
38
|
-
errors.push(`msg#${msgCount}: missing data field, got: ${JSON.stringify(msg)}`);
|
|
39
|
-
} else if (!Array.isArray(msg.data) && !(msg.data instanceof Float64Array)) {
|
|
40
|
-
errCount++;
|
|
41
|
-
errors.push(`msg#${msgCount}: data is not array-like, type=${typeof msg.data}`);
|
|
42
|
-
} else if (msg.data.length !== 3) {
|
|
43
|
-
errCount++;
|
|
44
|
-
errors.push(`msg#${msgCount}: expected 3 elements, got ${msg.data.length}`);
|
|
45
|
-
} else {
|
|
46
|
-
const seqNo = msg.data[0];
|
|
47
|
-
const expectedB = seqNo * 1.5;
|
|
48
|
-
const expectedC = seqNo * 2.5;
|
|
49
|
-
|
|
50
|
-
if (Math.abs(msg.data[1] - expectedB) > 1e-9) {
|
|
51
|
-
errCount++;
|
|
52
|
-
errors.push(
|
|
53
|
-
`msg#${msgCount}: data[1] expected ${expectedB}, got ${msg.data[1]}`
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
if (Math.abs(msg.data[2] - expectedC) > 1e-9) {
|
|
57
|
-
errCount++;
|
|
58
|
-
errors.push(
|
|
59
|
-
`msg#${msgCount}: data[2] expected ${expectedC}, got ${msg.data[2]}`
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (lastTs) {
|
|
65
|
-
hzSamples.push(1000 / (now - lastTs));
|
|
66
|
-
}
|
|
67
|
-
lastTs = now;
|
|
68
|
-
}
|
|
69
|
-
);
|
|
70
|
-
|
|
71
|
-
pubNode.spin();
|
|
72
|
-
subNode.spin();
|
|
73
|
-
|
|
74
|
-
let pubSeq = 0;
|
|
75
|
-
const pubInterval = setInterval(() => {
|
|
76
|
-
pubSeq++;
|
|
77
|
-
publisher.publish({ data: [pubSeq, pubSeq * 1.5, pubSeq * 2.5] });
|
|
78
|
-
}, 1000 / PUBLISH_HZ);
|
|
79
|
-
|
|
80
|
-
setTimeout(() => {
|
|
81
|
-
clearInterval(pubInterval);
|
|
82
|
-
|
|
83
|
-
console.log(`\n=== Data Integrity Test Results ===`);
|
|
84
|
-
console.log(`Published: ${pubSeq} messages at ${PUBLISH_HZ} Hz`);
|
|
85
|
-
console.log(`Received: ${msgCount} messages`);
|
|
86
|
-
console.log(`Data errors: ${errCount}`);
|
|
87
|
-
|
|
88
|
-
if (errors.length > 0) {
|
|
89
|
-
console.log(`\nFirst 10 errors:`);
|
|
90
|
-
errors.slice(0, 10).forEach((e) => console.log(` ${e}`));
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (hzSamples.length > 0) {
|
|
94
|
-
const avgHz = hzSamples.reduce((a, b) => a + b, 0) / hzSamples.length;
|
|
95
|
-
console.log(`\nAvg Hz: ${avgHz.toFixed(2)}`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const pass = errCount === 0 && msgCount > 0;
|
|
99
|
-
console.log(`\nResult: ${pass ? 'PASS - all data correct' : 'FAIL'}`);
|
|
100
|
-
|
|
101
|
-
pubNode.stop();
|
|
102
|
-
subNode.stop();
|
|
103
|
-
rclnodejs.shutdown();
|
|
104
|
-
process.exit(pass ? 0 : 1);
|
|
105
|
-
}, TEST_DURATION_SEC * 1000);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
main().catch(console.error);
|