Skip to content

Commit bf41b27

Browse files
committed
Add QoS overriding options for publishers and subscriptions (#1468)
Allow QoS policies to be overridden at deployment time via ROS parameters, without changing source code. When `qosOverridingOptions` is passed to `createPublisher()` or `createSubscription()`, the node declares read-only parameters (e.g. `qos_overrides./chatter.subscription.depth`) whose values can be set at startup. Ported from rclpy's `QoSOverridingOptions` (rclpy/qos_overriding_options.py). Usage with rclnodejs: ```bash node my_app.js --ros-args -p "qos_overrides./chatter.subscription.depth:=1" node my_app.js --ros-args --params-file qos.yaml ``` The `--ros-args` are received via `process.argv`, processed by `rclnodejs.init()`, and applied when `declareParameter()` finds matching overrides in `_parameterOverrides`. **New: `lib/qos_overriding_options.js`** — `QoSPolicyKind` enum (HISTORY, DEPTH, RELIABILITY, DURABILITY, LIVELINESS, AVOID_ROS_NAMESPACE_CONVENTIONS), `QoSOverridingOptions` class with `withDefaultPolicies()` factory, `declareQosParameters()` engine that declares parameters per whitelisted policy and applies overrides to the QoS profile in-place, and enum↔string conversion helpers. Includes `_resolveQoS()` to convert string profile names to mutable QoS objects. **Modified: `lib/node.js`** — `_createPublisher()` and `createSubscription()` check for `options.qosOverridingOptions`, resolve QoS profile strings, and call `declareQosParameters()` before creating the entity. **Modified: `index.js`** — Exports `QoSPolicyKind` and `QoSOverridingOptions`. **New: `test/test-qos-overriding-options.js`** — 11 tests: enum values, factory method, custom policies with entityId, publisher/subscription parameter declaration and value verification, entity ID suffix in parameter names, validation callback accept/reject, string QoS resolution, no-override baseline, and end-to-end parameter override proving the QoS object is mutated in-place. Fix: #1467
1 parent be0483f commit bf41b27

7 files changed

Lines changed: 794 additions & 0 deletions

File tree

index.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ const {
3939
} = require('./lib/parameter.js');
4040
const path = require('path');
4141
const QoS = require('./lib/qos.js');
42+
const {
43+
QoSPolicyKind,
44+
QoSOverridingOptions,
45+
} = require('./lib/qos_overriding_options.js');
4246
const rclnodejs = require('./lib/native_loader.js');
4347
const tsdGenerator = require('./rostsd_gen/index.js');
4448
const validator = require('./lib/validator.js');
@@ -258,6 +262,12 @@ let rcl = {
258262
/** {@link QoS} class */
259263
QoS: QoS,
260264

265+
/** {@link QoSPolicyKind} enum */
266+
QoSPolicyKind: QoSPolicyKind,
267+
268+
/** {@link QoSOverridingOptions} class */
269+
QoSOverridingOptions: QoSOverridingOptions,
270+
261271
/** {@link RMWUtils} */
262272
RMWUtils: RMWUtils,
263273

lib/node.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ const Service = require('./service.js');
4848
const Subscription = require('./subscription.js');
4949
const ObservableSubscription = require('./observable_subscription.js');
5050
const MessageInfo = require('./message_info.js');
51+
const {
52+
declareQosParameters,
53+
_resolveQoS,
54+
} = require('./qos_overriding_options.js');
5155
const TimeSource = require('./time_source.js');
5256
const Timer = require('./timer.js');
5357
const TypeDescriptionService = require('./type_description_service.js');
@@ -705,6 +709,10 @@ class Node extends rclnodejs.ShadowNode {
705709
* @param {object} options - The options argument used to parameterize the publisher.
706710
* @param {boolean} options.enableTypedArray - The topic will use TypedArray if necessary, default: true.
707711
* @param {QoS} options.qos - ROS Middleware "quality of service" settings for the publisher, default: QoS.profileDefault.
712+
* @param {QoSOverridingOptions} [options.qosOverridingOptions] - If provided, declares read-only ROS parameters
713+
* for the specified QoS policies (e.g. `qos_overrides./topic.publisher.depth`). These can be overridden at
714+
* startup via `--ros-args -p` or `--params-file`. If qos is a profile string, it will be resolved to a
715+
* mutable QoS object before overrides are applied.
708716
* @param {PublisherEventCallbacks} eventCallbacks - The event callbacks for the publisher.
709717
* @return {Publisher} - An instance of Publisher.
710718
*/
@@ -752,6 +760,21 @@ class Node extends rclnodejs.ShadowNode {
752760
);
753761
}
754762

763+
// Apply QoS overriding options if provided
764+
if (options.qosOverridingOptions) {
765+
const resolvedTopic = this.resolveTopicName(topic);
766+
if (typeof options.qos === 'string' || !(options.qos instanceof QoS)) {
767+
options.qos = _resolveQoS(options.qos);
768+
}
769+
declareQosParameters(
770+
'publisher',
771+
this,
772+
resolvedTopic,
773+
options.qos,
774+
options.qosOverridingOptions
775+
);
776+
}
777+
755778
let publisher = publisherClass.createPublisher(
756779
this,
757780
typeClass,
@@ -795,6 +818,10 @@ class Node extends rclnodejs.ShadowNode {
795818
* @param {string[]} [options.contentFilter.parameters=undefined] - Array of strings that give values to
796819
* the ‘parameters’ (i.e., "%n" tokens) in the filter_expression. The number of supplied parameters must
797820
* fit with the requested values in the filter_expression (i.e., the number of %n tokens). default: undefined.
821+
* @param {QoSOverridingOptions} [options.qosOverridingOptions] - If provided, declares read-only ROS parameters
822+
* for the specified QoS policies (e.g. `qos_overrides./topic.subscription.depth`). These can be overridden at
823+
* startup via `--ros-args -p` or `--params-file`. If qos is a profile string, it will be resolved to a
824+
* mutable QoS object before overrides are applied.
798825
* @param {SubscriptionCallback} callback - The callback to be call when receiving the topic subscribed. The topic will be an instance of null-terminated Buffer when options.isRaw is true.
799826
* @param {SubscriptionEventCallbacks} eventCallbacks - The event callbacks for the subscription.
800827
* @return {Subscription} - An instance of Subscription.
@@ -848,6 +875,21 @@ class Node extends rclnodejs.ShadowNode {
848875
);
849876
}
850877

878+
// Apply QoS overriding options if provided
879+
if (options.qosOverridingOptions) {
880+
const resolvedTopic = this.resolveTopicName(topic);
881+
if (typeof options.qos === 'string' || !(options.qos instanceof QoS)) {
882+
options.qos = _resolveQoS(options.qos);
883+
}
884+
declareQosParameters(
885+
'subscription',
886+
this,
887+
resolvedTopic,
888+
options.qos,
889+
options.qosOverridingOptions
890+
);
891+
}
892+
851893
let subscription = Subscription.createSubscription(
852894
this,
853895
typeClass,

0 commit comments

Comments
 (0)