@@ -51,6 +51,12 @@ class ActionClient extends Entity {
5151 * @param {QoS } options.qos.feedbackSubQosProfile - Quality of service option for the feedback subscription,
5252 * default: new QoS(QoS.HistoryPolicy.RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT, 10).
5353 * @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.
5460 */
5561 constructor ( node , typeClass , actionName , options ) {
5662 super ( null , null , options ) ;
@@ -87,6 +93,14 @@ class ActionClient extends Entity {
8793 checkTypes : true ,
8894 } ;
8995
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.
99+ this . _enableFeedbackMsgOptimization =
100+ this . _options . enableFeedbackMsgOptimization === true &&
101+ DistroUtils . getDistroId ( ) >= DistroUtils . DistroId . ROLLING &&
102+ typeof rclnodejs . actionConfigureFeedbackSubFilterAddGoalId === 'function' ;
103+
90104 let type = this . typeClass . type ( ) ;
91105
92106 this . _handle = rclnodejs . actionCreateClient (
@@ -126,6 +140,7 @@ class ActionClient extends Entity {
126140 }
127141
128142 this . _goalHandles . set ( uuid , goalHandle ) ;
143+ this . _feedbackSubFilterAddGoalId ( goalHandle . goalId ) ;
129144 } else {
130145 // Clean up feedback callback for rejected goals
131146 let uuid = ActionUuid . fromMessage (
@@ -205,6 +220,9 @@ class ActionClient extends Entity {
205220 status === ActionInterfaces . GoalStatus . STATUS_ABORTED
206221 ) {
207222 this . _goalHandles . delete ( uuid ) ;
223+ this . _feedbackSubFilterRemoveGoalId (
224+ statusMessage . goal_info . goal_id
225+ ) ;
208226 }
209227 }
210228 } else {
@@ -393,6 +411,8 @@ class ActionClient extends Entity {
393411 this . _removePendingCancelRequest ( sequenceNumber )
394412 ) ;
395413
414+ this . _feedbackSubFilterRemoveGoalId ( goalHandle . goalId ) ;
415+
396416 return deferred . promise ;
397417 }
398418
@@ -442,9 +462,10 @@ class ActionClient extends Entity {
442462 goalHandle . status = result . status ;
443463 return result . result ;
444464 } ) ;
445- deferred . setDoneCallback ( ( ) =>
446- this . _removePendingResultRequest ( sequenceNumber )
447- ) ;
465+ deferred . setDoneCallback ( ( ) => {
466+ this . _removePendingResultRequest ( sequenceNumber ) ;
467+ this . _feedbackSubFilterRemoveGoalId ( goalHandle . goalId ) ;
468+ } ) ;
448469
449470 this . _pendingResultRequests . set ( sequenceNumber , deferred ) ;
450471
@@ -464,6 +485,50 @@ class ActionClient extends Entity {
464485 this . _pendingCancelRequests . delete ( sequenceNumber ) ;
465486 }
466487
488+ /**
489+ * Add a goal ID to the feedback subscription content filter.
490+ * @ignore
491+ * @param {object } goalId - The goal UUID message.
492+ */
493+ _feedbackSubFilterAddGoalId ( goalId ) {
494+ if ( ! this . _enableFeedbackMsgOptimization ) return ;
495+ try {
496+ rclnodejs . actionConfigureFeedbackSubFilterAddGoalId (
497+ this . handle ,
498+ Buffer . from ( goalId . uuid )
499+ ) ;
500+ } catch ( e ) {
501+ this . _enableFeedbackMsgOptimization = false ;
502+ this . _node
503+ . getLogger ( )
504+ . warn (
505+ `${ e . message } \nFeedback message optimization is automatically disabled.`
506+ ) ;
507+ }
508+ }
509+
510+ /**
511+ * Remove a goal ID from the feedback subscription content filter.
512+ * @ignore
513+ * @param {object } goalId - The goal UUID message.
514+ */
515+ _feedbackSubFilterRemoveGoalId ( goalId ) {
516+ if ( ! this . _enableFeedbackMsgOptimization ) return ;
517+ try {
518+ rclnodejs . actionConfigureFeedbackSubFilterRemoveGoalId (
519+ this . handle ,
520+ Buffer . from ( goalId . uuid )
521+ ) ;
522+ } catch ( e ) {
523+ this . _enableFeedbackMsgOptimization = false ;
524+ this . _node
525+ . getLogger ( )
526+ . warn (
527+ `${ e . message } \nFeedback message optimization is automatically disabled.`
528+ ) ;
529+ }
530+ }
531+
467532 /**
468533 * Destroy the underlying action client handle.
469534 * @return {undefined }
0 commit comments