Skip to content

Commit 3c2d424

Browse files
address comments
1 parent e35eff1 commit 3c2d424

3 files changed

Lines changed: 48 additions & 43 deletions

File tree

example/topics/subscriber/subscription-observable-example.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ async function main() {
3939
});
4040

4141
// Example 2: Filtered messages (only containing "ROS")
42+
// Note: RxJS filter() operates at the application level after messages are received.
43+
// For more efficient filtering at the DDS middleware level (reducing network traffic),
44+
// use the contentFilter option. See: tutorials/content-filtering-subscription.md
4245
obsSub.observable
4346
.pipe(
4447
map((msg) => msg.data),

lib/node.js

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -839,44 +839,9 @@ class Node extends rclnodejs.ShadowNode {
839839
* @return {ObservableSubscription} - An ObservableSubscription with an RxJS Observable.
840840
*/
841841
createObservableSubscription(typeClass, topic, options, eventCallbacks) {
842-
if (typeof typeClass === 'string' || typeof typeClass === 'object') {
843-
typeClass = loader.loadInterface(typeClass);
844-
}
845-
846-
options = this._validateOptions(options);
847-
848-
if (typeof typeClass !== 'function') {
849-
throw new TypeValidationError('typeClass', typeClass, 'function', {
850-
nodeName: this.name(),
851-
entityType: 'subscription',
852-
});
853-
}
854-
if (typeof topic !== 'string') {
855-
throw new TypeValidationError('topic', topic, 'string', {
856-
nodeName: this.name(),
857-
entityType: 'subscription',
858-
});
859-
}
860-
if (
861-
eventCallbacks &&
862-
!(eventCallbacks instanceof SubscriptionEventCallbacks)
863-
) {
864-
throw new TypeValidationError(
865-
'eventCallbacks',
866-
eventCallbacks,
867-
'SubscriptionEventCallbacks',
868-
{
869-
nodeName: this.name(),
870-
entityType: 'subscription',
871-
entityName: topic,
872-
}
873-
);
874-
}
875-
876842
let observableSubscription = null;
877843

878-
const subscription = Subscription.createSubscription(
879-
this,
844+
const subscription = this.createSubscription(
880845
typeClass,
881846
topic,
882847
options,
@@ -888,13 +853,7 @@ class Node extends rclnodejs.ShadowNode {
888853
eventCallbacks
889854
);
890855

891-
observableSubscription = new ObservableSubscription(subscription);
892-
893-
debug('Finish creating observable subscription, topic = %s.', topic);
894-
this._subscriptions.push(subscription);
895-
this.syncHandles();
896-
897-
return observableSubscription;
856+
return new ObservableSubscription(subscription);
898857
}
899858

900859
/**

tutorials/observable-subscriptions.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ rclnodejs provides RxJS Observable support for subscriptions, enabling reactive
2525

2626
Observable subscriptions are ideal for complex message processing pipelines where you need to combine, filter, or transform data from multiple sources.
2727

28+
> **Note:** RxJS `filter()` operates at the application level after messages are received. For simple content-based filtering that reduces network traffic, consider using [DDS Content Filtering](content-filtering-subscription.md) instead, which filters at the middleware level before messages reach your application. See [Example 6](#example-6-combining-dds-content-filtering-with-rxjs) for combined usage.
29+
2830
## Basic Usage
2931

3032
```javascript
@@ -179,6 +181,47 @@ tempSub.observable
179181
});
180182
```
181183

184+
### Example 6: Combining DDS Content Filtering with RxJS
185+
186+
For optimal performance, use DDS content filtering to reduce network traffic at the middleware level, then apply RxJS operators for additional processing:
187+
188+
```javascript
189+
const { throttleTime, map } = require('rxjs');
190+
191+
// DDS filters at middleware level - only temperatures > 30°C are delivered
192+
const tempSub = node.createObservableSubscription(
193+
'sensor_msgs/msg/Temperature',
194+
'/temperature',
195+
{
196+
contentFilter: {
197+
expression: 'temperature > %0',
198+
parameters: ['30.0'],
199+
},
200+
}
201+
);
202+
203+
// RxJS processes the pre-filtered stream
204+
tempSub.observable
205+
.pipe(
206+
throttleTime(1000), // Rate limit to 1 msg/sec
207+
map((msg) => ({
208+
celsius: msg.temperature,
209+
fahrenheit: msg.temperature * 1.8 + 32,
210+
}))
211+
)
212+
.subscribe((temp) => {
213+
console.log(`High temp alert: ${temp.celsius}°C (${temp.fahrenheit}°F)`);
214+
});
215+
```
216+
217+
This approach provides:
218+
219+
- **Network efficiency**: DDS drops messages below 30°C before transmission
220+
- **CPU efficiency**: RxJS only processes relevant messages
221+
- **Flexibility**: RxJS handles rate limiting and transformation
222+
223+
> See [Content Filtering Subscription](content-filtering-subscription.md) for more details on DDS content filtering.
224+
182225
## Cleanup
183226

184227
Always clean up subscriptions when done:

0 commit comments

Comments
 (0)