Skip to content

Conversation

@bmchalenv
Copy link
Contributor

@bmchalenv bmchalenv commented Jan 2, 2026

Resolves #19 and gives the capability to specify expected frequencies and tolerance through ROS 2 parameters. The topics parameter can now be specified with subfields topics.<topic_name>.(expected_frequency|tolerance).

The original topics parameter with a list still exists and can be used during initialization, but now parameters specified with the new subfields will also add those topics to the monitor node with the expected frequency and tolerance already set. They can be set in a ROS 2 parameter file like:

/monitor_node
    ros__parameters:
        topics:
            /imu:
                expected_frequency: 100
                tolerance: 5

or

/monitor_node:
    ros__parameters:
         topics: ["/image", "/string"]
         "topics./imu.expected_frequency": 100
         "topics./imu.tolerance": 5

ncurses_dashboard also works with the parameters. It reads all parameters at the beginning and sets up the dashboard with expected frequencies already set. If parameters are updated it also updates at the same time.

@greptile-apps
Copy link

greptile-apps bot commented Jan 2, 2026

Greptile Summary

This PR implements ROS 2 parameter-based configuration for topic monitoring, allowing users to specify expected frequencies and tolerances through parameter files or dynamic parameter commands instead of only through service calls.

Key Changes

  • Parameter Structure: Topics can now be configured using topics.<topic_name>.expected_frequency and topics.<topic_name>.tolerance parameters, supporting both flat dotted notation and nested dictionary format in YAML files
  • Bidirectional Synchronization: Service calls update parameters, and parameter changes trigger monitoring updates, keeping both representations in sync
  • Dynamic Parameter Handling: Full support for runtime parameter modification with validation (frequency must be positive, tolerance non-negative, only numeric types accepted)
  • Parameter Lifecycle: Proper handling of parameter deletion to clear expected frequency checking, with tolerance resetting to default (5%) when deleted
  • UI Integration: ncurses_dashboard fetches initial parameters on startup and subscribes to parameter events to reflect changes in real-time
  • Deadlock Prevention: Uses updating_params_internally_ flag to prevent recursive callbacks when the node updates its own parameters
  • Comprehensive Testing: 7 new test files covering startup configuration, YAML loading, dynamic updates, validation, edge cases, and parameter deletion

Implementation Quality

The implementation demonstrates careful attention to edge cases and proper ROS 2 parameter lifecycle management. Parameter validation prevents invalid states, and the separation of internal state updates from parameter updates (via the update_parameters flag) provides flexibility for different code paths.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation is production-ready with comprehensive error handling, extensive test coverage (7 new test files covering all scenarios), proper parameter validation, deadlock prevention mechanisms, and careful attention to edge cases. The code follows ROS 2 best practices for parameter handling and maintains backward compatibility with existing service-based configuration.
  • No files require special attention

Important Files Changed

Filename Overview
greenwave_monitor/src/greenwave_monitor.cpp Comprehensive implementation of ROS 2 parameter-based topic configuration with proper validation, error handling, and bidirectional sync between parameters and internal state
greenwave_monitor/include/greenwave_monitor.hpp Added necessary data structures and method declarations for parameter handling, including callbacks and internal state management flag
greenwave_monitor/greenwave_monitor/ui_adaptor.py Extended UI adaptor to fetch initial parameters on startup and react to parameter change events, maintaining synchronization with monitor node state
greenwave_monitor/test/parameters/test_param_yaml.py Tests both flat dotted key format and nested dictionary format for parameter specification in YAML files
greenwave_monitor/test/parameters/test_param_dynamic.py Comprehensive dynamic parameter testing covering setting, updating, deleting parameters, validation of invalid values, and edge cases

Sequence Diagram

sequenceDiagram
    participant User
    participant LaunchFile
    participant MonitorNode as GreenwaveMonitor
    participant ParamServer as Parameter Server
    participant UIAdaptor
    participant Diagnostics as Message Diagnostics

    Note over User,Diagnostics: Startup Flow with Parameter Configuration

    User->>LaunchFile: Launch with parameter file
    LaunchFile->>MonitorNode: Start with topics.<topic>.expected_frequency<br/>and topics.<topic>.tolerance
    MonitorNode->>MonitorNode: Constructor initializes with<br/>allow_undeclared_parameters=true
    MonitorNode->>ParamServer: Automatically declare parameters from overrides
    MonitorNode->>MonitorNode: Register on_parameter_change callback
    MonitorNode->>ParamServer: Subscribe to /parameter_events
    MonitorNode->>MonitorNode: load_topic_parameters_from_overrides()
    MonitorNode->>ParamServer: list_parameters() and get values
    loop For each topic with frequency parameter
        MonitorNode->>Diagnostics: add_topic(topic)
        MonitorNode->>Diagnostics: setExpectedDt(freq, tolerance)
    end

    User->>UIAdaptor: Launch ncurses dashboard
    UIAdaptor->>ParamServer: create_timer for initial params fetch
    UIAdaptor->>ParamServer: list_parameters() when services ready
    ParamServer-->>UIAdaptor: Parameter names
    UIAdaptor->>ParamServer: get_parameters(topic param names)
    ParamServer-->>UIAdaptor: Parameter values
    UIAdaptor->>UIAdaptor: Parse and store expected_frequencies
    UIAdaptor->>ParamServer: Subscribe to /parameter_events

    Note over User,Diagnostics: Dynamic Parameter Update Flow

    User->>ParamServer: ros2 param set topics./imu.expected_frequency 100
    ParamServer->>MonitorNode: on_parameter_change callback
    MonitorNode->>MonitorNode: Check updating_params_internally_ flag
    MonitorNode->>MonitorNode: Validate parameter value (>0 for freq, >=0 for tol)
    alt Valid parameter
        MonitorNode->>MonitorNode: parse_topic_param_name()
        MonitorNode->>MonitorNode: set_topic_expected_frequency()
        MonitorNode->>Diagnostics: setExpectedDt(freq, tolerance)
        MonitorNode-->>ParamServer: Return success
    else Invalid parameter
        MonitorNode-->>ParamServer: Return error with reason
    end
    
    ParamServer->>UIAdaptor: ParameterEvent message on /parameter_events
    UIAdaptor->>UIAdaptor: Parse parameter name and value
    UIAdaptor->>UIAdaptor: Update expected_frequencies map

    Note over User,Diagnostics: Parameter Deletion Flow

    User->>ParamServer: ros2 param delete topics./imu.expected_frequency
    ParamServer->>MonitorNode: ParameterEvent with deleted_parameters
    MonitorNode->>MonitorNode: on_parameter_event callback
    MonitorNode->>Diagnostics: clearExpectedDt()
    ParamServer->>UIAdaptor: ParameterEvent on /parameter_events
    UIAdaptor->>UIAdaptor: Remove from expected_frequencies map

    Note over User,Diagnostics: Service Call with Parameter Sync

    User->>MonitorNode: set_expected_frequency service call
    MonitorNode->>MonitorNode: handle_set_expected_frequency()
    MonitorNode->>MonitorNode: set_topic_expected_frequency(update_parameters=true)
    MonitorNode->>MonitorNode: Set updating_params_internally_ = true
    MonitorNode->>Diagnostics: setExpectedDt(freq, tolerance)
    MonitorNode->>ParamServer: declare_or_set_parameter() for freq and tol
    MonitorNode->>MonitorNode: Set updating_params_internally_ = false
    ParamServer->>UIAdaptor: ParameterEvent on /parameter_events
    UIAdaptor->>UIAdaptor: Update expected_frequencies map
Loading

@bmchalenv bmchalenv marked this pull request as draft January 2, 2026 18:16
… 2 parameters

Signed-off-by: Blake McHale <bmchale@nvidia.com>
…y time

Signed-off-by: Blake McHale <bmchale@nvidia.com>
…cing with parameters

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Signed-off-by: Blake McHale <bmchale@nvidia.com>
Signed-off-by: Blake McHale <bmchale@nvidia.com>
Signed-off-by: Blake McHale <bmchale@nvidia.com>
Signed-off-by: Blake McHale <bmchale@nvidia.com>
Signed-off-by: Blake McHale <bmchale@nvidia.com>
Signed-off-by: Blake McHale <bmchale@nvidia.com>
Signed-off-by: Blake McHale <bmchale@nvidia.com>
Signed-off-by: Blake McHale <bmchale@nvidia.com>
@bmchalenv bmchalenv marked this pull request as ready for review January 3, 2026 01:12
Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (1)

  1. greenwave_monitor/src/greenwave_monitor.cpp, line 282-286 (link)

    logic: If declare_or_set_parameter() throws an exception, updating_params_internally_ remains true, potentially blocking future parameter updates.

14 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (5)

  1. greenwave_monitor/CMakeLists.txt, line 121 (link)

    style: using file(GLOB ...) can cause build issues if test files are added/removed without re-running CMake configure step

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  2. greenwave_monitor/src/greenwave_monitor.cpp, line 282-291 (link)

    logic: Exception safety issue: if parameter operations throw after setting updating_params_internally_ = true, the flag remains true permanently, blocking future parameter updates

  3. greenwave_monitor/greenwave_monitor/test_utils.py, line 153-154 (link)

    logic: Setting empty string as topic when topics list is empty could cause issues. Is this intended behavior when an empty topics list is provided - should it default to an empty string topic or skip the topics parameter entirely?

  4. greenwave_monitor/greenwave_monitor/test_utils.py, line 76-78 (link)

    style: Service availability timeout is hardcoded to 5.0s while function parameter allows configuring timeout_sec for the overall operation

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

  5. greenwave_monitor/include/greenwave_monitor.hpp, line 83 (link)

    syntax: Typo in comment: 'on_paramter_change' should be 'on_parameter_change'

14 files reviewed, 5 comments

Edit Code Review Agent Settings | Greptile

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (1)

  1. greenwave_monitor/greenwave_monitor/ui_adaptor.py, line 326-327 (link)

    logic: substring match could incorrectly process events from unrelated nodes

14 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (1)

  1. greenwave_monitor/src/greenwave_monitor.cpp, line 283-292 (link)

    style: The updating_params_internally_ flag lacks thread-safety mechanisms (atomic or mutex). If this node runs with a multi-threaded executor, race conditions could occur:

    • Thread A sets flag to true (line 283)
    • Thread B checks flag (line 308) before Thread A completes
    • Both threads could process parameters simultaneously

    ROS 2 uses single-threaded executors by default, so this is safe for typical usage. However, consider using std::atomic<bool> for robustness if multi-threaded executors might be used.

14 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Comments (1)

  1. greenwave_monitor/test/parameters/test_param_tol_only.py, line 82 (link)

    style: requesting expected_count=1 when expecting 0 results - this parameter should be 0 for clearer intent

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

14 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link
Collaborator

@sgillen sgillen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a cursory review, but as we discussed offline, the plan will be to

  1. remove the services entirely and use params for everything
  2. move all the parameter logic to message_diagnostics.hpp (which we should rename greenwave_diagnostics.hpp btw)
    (edited)

#
# SPDX-License-Identifier: Apache-2.0

"""Test: only expected_frequency specified, tolerance defaults to 5%."""
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's label the test files + label strings more clearly since params are dynamic now, maybe startup_params when that is what you are testing.

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR successfully migrates from a service-based approach to a ROS 2 parameter-based approach for configuring topic monitoring frequencies and tolerances. The implementation is comprehensive and well-tested.

Key Changes

  • Removed SetExpectedFrequency service interface in favor of ROS 2 parameters
  • Parameters use greenwave_diagnostics.<topic_name>.expected_frequency and greenwave_diagnostics.<topic_name>.tolerance naming convention
  • Added event-driven parameter callbacks in GreenwaveDiagnostics class for dynamic updates
  • Enhanced GreenwaveUiAdaptor to query and track parameters from all nodes at startup
  • Added get_topics_from_parameters() to discover topics from parameter namespace
  • Comprehensive test coverage with 8 new parameter test files covering YAML config, dynamic updates, validation, and edge cases

Critical Issue Found

Documentation contains incorrect parameter names - docs/images/SERVICES.md documents the parameter prefix as topics. but the actual implementation uses greenwave_diagnostics. - this will cause all user commands in the documentation to fail. This must be fixed before merge.

Architecture Benefits

  • More idiomatic ROS 2 approach using standard parameter system
  • Parameters can be set via YAML files, launch files, or ros2 param set commands
  • Parameters persist across node restarts when configured via launch/YAML
  • Dynamic reconfiguration without service calls
  • Integration with existing publisher nodes that have built-in GreenwaveDiagnostics

Confidence Score: 3/5

  • This PR has significant documentation errors that will break user workflows, but the code implementation itself is solid
  • Score reflects critical documentation issues that must be fixed: all parameter examples use wrong prefix (topics. instead of greenwave_diagnostics.). The C++ and Python implementations are well-architected with proper thread safety, comprehensive test coverage (8 new test files), and clean integration. A minor typo exists in a log message. Once documentation is corrected, this would be a 4/5.
  • docs/images/SERVICES.md requires immediate correction - all parameter names are wrong and will cause user commands to fail

Important Files Changed

File Analysis

Filename Score Overview
docs/images/SERVICES.md 2/5 Critical documentation errors: parameter prefix is greenwave_diagnostics. not topics. - all examples will fail if users follow them
greenwave_monitor/include/greenwave_diagnostics.hpp 4/5 Major refactor adding parameter-based frequency configuration with event-driven updates; minor typo in log message
greenwave_monitor/src/greenwave_monitor.cpp 4/5 Implements parameter discovery at startup and integrates with GreenwaveDiagnostics parameter system; clean implementation
greenwave_monitor/greenwave_monitor/ui_adaptor.py 4/5 Adds comprehensive parameter event handling and initial parameter fetching from all nodes; well-structured async queries
greenwave_monitor/test/parameters/test_param_dynamic.py 5/5 Comprehensive test coverage for dynamic parameter changes including edge cases and validation

Sequence Diagram

sequenceDiagram
    participant User
    participant LaunchFile
    participant MonitorNode
    participant GreenwaveDiagnostics
    participant PublisherNode
    participant ParameterServer

    Note over User,ParameterServer: Scenario 1: Configuration via YAML at Launch

    User->>LaunchFile: Launch with YAML config
    LaunchFile->>MonitorNode: Start with parameters file
    MonitorNode->>ParameterServer: declare_parameters_from_overrides()
    ParameterServer-->>MonitorNode: Parameters declared
    MonitorNode->>MonitorNode: get_topics_from_parameters()
    MonitorNode->>ParameterServer: list_parameters("greenwave_diagnostics")
    ParameterServer-->>MonitorNode: [greenwave_diagnostics./topic.expected_frequency, ...]
    MonitorNode->>MonitorNode: add_topic() for each discovered topic
    MonitorNode->>GreenwaveDiagnostics: new GreenwaveDiagnostics(topic_name, config)
    GreenwaveDiagnostics->>ParameterServer: declare_parameter(freq_param_name)
    GreenwaveDiagnostics->>ParameterServer: set_parameter(freq) [triggers callback]
    GreenwaveDiagnostics->>GreenwaveDiagnostics: onParameterEvent() -> setExpectedDt()
    Note over GreenwaveDiagnostics: Diagnostics now active with expected frequency

    Note over User,ParameterServer: Scenario 2: Dynamic Parameter Update

    User->>ParameterServer: ros2 param set greenwave_diagnostics./topic.expected_frequency 30.0
    ParameterServer->>GreenwaveDiagnostics: onParameterChange() [validation]
    GreenwaveDiagnostics-->>ParameterServer: SetParametersResult{successful=true}
    ParameterServer->>GreenwaveDiagnostics: /parameter_events [ParameterEvent msg]
    GreenwaveDiagnostics->>GreenwaveDiagnostics: onParameterEvent() -> setExpectedDt()
    Note over GreenwaveDiagnostics: Expected frequency updated, diagnostics reconfigured

    Note over User,ParameterServer: Scenario 3: Publisher Node with Built-in Diagnostics

    User->>LaunchFile: Launch publisher with greenwave_diagnostics params
    LaunchFile->>PublisherNode: Start with greenwave_diagnostics./topic.* params
    PublisherNode->>GreenwaveDiagnostics: new GreenwaveDiagnostics(topic_name)
    GreenwaveDiagnostics->>ParameterServer: declare parameters & subscribe to events
    User->>MonitorNode: Call manage_topic service to add topic
    MonitorNode->>MonitorNode: get_publishers_info_by_topic()
    MonitorNode->>PublisherNode: Check for greenwave_diagnostics./topic.enabled param
    MonitorNode->>ParameterServer: set_parameter(enabled=true) on PublisherNode
    ParameterServer->>PublisherNode: Parameter update event
    PublisherNode->>GreenwaveDiagnostics: onParameterEvent() -> enabled=true
    Note over PublisherNode: Publisher now publishes diagnostics to /diagnostics

Loading

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

Overview

This PR refactors the greenwave_monitor from a service-based API to a parameter-based API for controlling topic monitoring and expected frequencies. The changes replace ManageTopic and SetExpectedFrequency services with ROS 2 parameters following the pattern greenwave_diagnostics.<topic>.(enabled|expected_frequency|tolerance).

Key Changes

Architecture Shift: Moved from service calls to parameter-based configuration, aligning with ROS 2 best practices and enabling declarative configuration via YAML files.

New Components:

  • greenwave_diagnostics.hpp: New header-only library for per-topic diagnostics with parameter callbacks
  • Parameter naming: greenwave_diagnostics.<topic>.enabled|expected_frequency|tolerance
  • External node tracking to prevent duplicate monitoring across nodes

API Changes:

  • Removed: Service interfaces ManageTopic.srv and SetExpectedFrequency.srv
  • Added: Parameter-based control with validation callbacks
  • Enhanced: YAML configuration support with nested parameter syntax

Issues Found

Critical (Must Fix Before Merge)

  1. Missing include: greenwave_diagnostics.hpp uses rcpputils::join() without including the header - will cause compilation failure
  2. Missing dependency: package.xml doesn't declare rcpputils dependency - will cause build failure

Non-Critical Issues

  1. Typo: "Iniital" should be "Initial" in log message (line 743 of greenwave_diagnostics.hpp)
  2. Logic inconsistency: ui_adaptor.py comment says NaN frequencies are "cleared" but they're actually stored in the dictionary (lines 489-492)
  3. Style improvement: Parameter validation could use continue statements for cleaner logic flow (lines 624-636 of greenwave_diagnostics.hpp)

Testing

The PR includes comprehensive test coverage:

  • test_parameters.py: 9 test classes covering startup, YAML config, dynamic parameters, and multi-topic scenarios
  • test_greenwave_diagnostics.cpp: Unit tests for C++ diagnostics functionality
  • Integration tests validate parameter synchronization across nodes

Positive Aspects

  • Well-structured refactoring with clear separation of concerns
  • Excellent test coverage demonstrating various configuration scenarios
  • Documentation updated to reflect new API
  • Backwards compatibility maintained via existing topics parameter list
  • Proper mutex protection for thread-safe parameter updates

Confidence Score: 3/5

  • This PR has critical build issues that must be fixed before merging, but the core logic is sound
  • Score of 3 reflects that while the refactoring is well-designed with good test coverage, there are two critical issues (missing include and dependency) that will cause immediate build failures. Once these are fixed, the PR should be safe to merge. The non-critical issues are style/consistency concerns that don't affect functionality.
  • Pay close attention to greenwave_monitor/include/greenwave_diagnostics.hpp and greenwave_monitor/package.xml - both need updates to fix critical build issues

Important Files Changed

File Analysis

Filename Score Overview
greenwave_monitor/include/greenwave_diagnostics.hpp 3/5 New header-only diagnostics class with parameter-based configuration. Contains critical missing include for rcpputils::join and typo in log message. Parameter validation logic works but could be cleaner.
greenwave_monitor/package.xml 2/5 Missing rcpputils dependency required by greenwave_diagnostics.hpp. This will cause build failures.
greenwave_monitor/src/greenwave_monitor.cpp 4/5 Refactored from service-based to parameter-based topic management. Replaces ManageTopic and SetExpectedFrequency services with parameter events. Logic appears sound with proper validation and external node tracking.
greenwave_monitor/greenwave_monitor/ui_adaptor.py 3/5 Python UI adapter for parameter-based diagnostics. Contains logic inconsistency where NaN frequency values are stored rather than cleared despite comment suggesting otherwise.
greenwave_monitor/test/test_parameters.py 5/5 Comprehensive test suite for parameter-based configuration covering startup behavior, multiple topics, YAML config, and dynamic parameter changes. Well-structured tests.

Sequence Diagram

sequenceDiagram
    participant User
    participant ROS2_Param_System as ROS 2 Parameter System
    participant GreenwaveMonitor
    participant GreenwaveDiagnostics
    participant Publisher_Node as Publisher Node

    Note over User,Publisher_Node: Startup: Topic Configuration from YAML/Launch

    User->>GreenwaveMonitor: Launch with parameters<br/>(greenwave_diagnostics./topic.enabled: true)
    GreenwaveMonitor->>GreenwaveMonitor: fetch_external_topic_map()
    GreenwaveMonitor->>Publisher_Node: Query parameters via SyncParametersClient
    Publisher_Node-->>GreenwaveMonitor: Return topic parameters
    GreenwaveMonitor->>GreenwaveMonitor: get_topics_from_parameters()
    GreenwaveMonitor->>GreenwaveMonitor: add_topic() for each configured topic
    GreenwaveMonitor->>GreenwaveDiagnostics: Create diagnostics object
    GreenwaveDiagnostics->>ROS2_Param_System: Declare/set freq, tol, enabled parameters
    GreenwaveDiagnostics->>ROS2_Param_System: Subscribe to /parameter_events

    Note over User,Publisher_Node: Runtime: Enable Monitoring for New Topic

    User->>ROS2_Param_System: Set greenwave_diagnostics./new_topic.enabled = true
    ROS2_Param_System->>GreenwaveMonitor: on_parameter_change() (validation)
    GreenwaveMonitor->>GreenwaveMonitor: validate_add_topic()<br/>(check publishers, external nodes)
    GreenwaveMonitor-->>ROS2_Param_System: Return validation result
    ROS2_Param_System->>GreenwaveMonitor: ParameterEvent (new_parameters)
    GreenwaveMonitor->>GreenwaveMonitor: internal_on_parameter_event()
    GreenwaveMonitor->>GreenwaveMonitor: execute_add_topic()
    GreenwaveMonitor->>GreenwaveDiagnostics: Create diagnostics object

    Note over User,Publisher_Node: Runtime: Set Expected Frequency

    User->>ROS2_Param_System: Set greenwave_diagnostics./topic.expected_frequency = 30.0
    ROS2_Param_System->>GreenwaveDiagnostics: onParameterChange() (validation)
    GreenwaveDiagnostics->>GreenwaveDiagnostics: Validate freq > 0 or NaN
    GreenwaveDiagnostics-->>ROS2_Param_System: Return validation result
    ROS2_Param_System->>GreenwaveDiagnostics: ParameterEvent (changed_parameters)
    GreenwaveDiagnostics->>GreenwaveDiagnostics: onParameterEvent()<br/>setExpectedDt()
    GreenwaveDiagnostics->>GreenwaveDiagnostics: Enable time diagnostics

    Note over User,Publisher_Node: Runtime: Message Flow & Diagnostics

    Publisher_Node->>GreenwaveMonitor: Publish message on /topic
    GreenwaveMonitor->>GreenwaveDiagnostics: updateDiagnostics(timestamp)
    GreenwaveDiagnostics->>GreenwaveDiagnostics: Check frame rate vs expected
    GreenwaveMonitor->>GreenwaveDiagnostics: publishDiagnostics() (timer callback)
    GreenwaveDiagnostics->>ROS2_Param_System: Publish to /diagnostics topic
Loading

@greptile-apps
Copy link

greptile-apps bot commented Jan 9, 2026

Additional Comments (1)

greenwave_monitor/package.xml
The code uses rcpputils::join in greenwave_diagnostics.hpp but rcpputils is not listed as a dependency in package.xml. This will cause build failures.

  <depend>rclcpp</depend>
  <depend>rcpputils</depend>
  <depend>std_msgs</depend>
  <depend>diagnostic_msgs</depend>
  <depend>sensor_msgs</depend>
  <depend>rclpy</depend>

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

Adds ROS 2 parameter-based configuration for topic monitoring, enabling users to specify expected frequencies and tolerances via parameters instead of only service calls. The implementation supports both flat (topics./my_topic.expected_frequency) and nested YAML (topics: { /my_topic: { expected_frequency: 100 } }) parameter formats. The ncurses dashboard integrates with the new parameter system, reading initial configurations and responding to dynamic updates. Most of the implementation is solid with comprehensive test coverage.

Confidence Score: 1/5

  • High risk due to logic bug that stores invalid NaN frequency values
  • The PR contains a critical logic error in ui_adaptor.py line 491 where the condition if value > 0 or math.isnan(value) will store NaN frequencies in the cache instead of clearing them as intended by the comment. This bug causes the expected_frequencies dictionary to contain invalid (NaN, tolerance) entries, leading to incorrect behavior in UI display logic. While the C++ implementation appears correct, this Python bug affects the ncurses frontend's ability to properly track cleared frequency parameters.
  • greenwave_monitor/greenwave_monitor/ui_adaptor.py requires immediate fix to line 491 logic bug

Important Files Changed

File Analysis

Filename Score Overview
greenwave_monitor/greenwave_monitor/ui_adaptor.py 1/5 Critical logic bug at line 491: NaN frequency values incorrectly stored in cache instead of being cleared
greenwave_monitor/src/greenwave_monitor.cpp 3/5 Adds parameter-based topic configuration; implements validation and external topic tracking correctly
greenwave_monitor/include/greenwave_diagnostics.hpp 3/5 Adds ROS 2 parameter support for frequency, tolerance, and enabled flags with validation

Sequence Diagram

sequenceDiagram
    participant User
    participant YAML/Launch
    participant MonitorNode
    participant ParamServer
    participant GreenwaveDiag
    participant PublisherNode

    Note over User,PublisherNode: Startup: Parameter Initialization
    YAML/Launch->>MonitorNode: Load parameters (topics./imu.expected_frequency: 100)
    MonitorNode->>MonitorNode: get_topics_from_parameters()
    MonitorNode->>MonitorNode: validate_add_topic(/imu)
    MonitorNode->>GreenwaveDiag: Create diagnostics instance
    GreenwaveDiag->>ParamServer: Declare enabled/freq/tol parameters
    GreenwaveDiag->>GreenwaveDiag: setExpectedDt(100, 5)

    Note over User,PublisherNode: Runtime: Dynamic Parameter Update
    User->>ParamServer: Set topics./camera.expected_frequency=30
    ParamServer->>MonitorNode: on_parameter_change()
    MonitorNode->>MonitorNode: validate_add_topic(/camera)
    MonitorNode->>MonitorNode: Store in pending_validations_
    ParamServer-->>MonitorNode: SetParametersResult (success)
    ParamServer->>MonitorNode: ParameterEvent (new_parameters)
    MonitorNode->>MonitorNode: execute_add_topic()
    MonitorNode->>GreenwaveDiag: Create diagnostics for /camera
    GreenwaveDiag->>GreenwaveDiag: setExpectedDt(30, 5)

    Note over User,PublisherNode: External Node Conflict Prevention
    PublisherNode->>ParamServer: Set topics./imu.enabled=true
    ParamServer->>MonitorNode: ParameterEvent (external node)
    MonitorNode->>MonitorNode: external_on_parameter_event()
    MonitorNode->>MonitorNode: Store in external_topic_to_node_
    User->>MonitorNode: Try to monitor /imu
    MonitorNode->>MonitorNode: validate_add_topic(): Check external_topic_to_node_
    MonitorNode-->>User: Error: Already monitored by PublisherNode
Loading

Comment on lines +491 to +492
if value > 0 or math.isnan(value):
self.expected_frequencies[topic_name] = (value, current[1])
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition if value > 0 or math.isnan(value) will store NaN values in expected_frequencies, causing invalid cache entries. The comment states "Treat NaN or non-positive as 'cleared'", but NaN values are stored rather than cleared.

Issue: When a frequency parameter is set to NaN (which signals clearing), line 492 executes and stores (NaN, current[1]) in the cache. This causes incorrect behavior in get_expected_frequency_str() (line 577) which checks if freq <= 0.0 or math.isnan(freq) and returns '-'.

Expected behavior: NaN should remove the entry from the cache, not store it.

Suggested change
if value > 0 or math.isnan(value):
self.expected_frequencies[topic_name] = (value, current[1])
if field == 'freq':
# Treat NaN or non-positive as "cleared"
if value > 0 and not math.isnan(value):
self.expected_frequencies[topic_name] = (value, current[1])
elif math.isnan(value):
self.expected_frequencies.pop(topic_name, None)

Comment on lines +405 to +407
tol = config.get('tol', DEFAULT_TOLERANCE_PERCENT)
if freq > 0 and not math.isnan(freq):
self.expected_frequencies[topic_name] = (freq, tol)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition if freq > 0 and not math.isnan(freq) correctly validates frequency values before storing them. However, this logic should match the handling in _on_parameter_event() at line 491 where NaN values are incorrectly stored. Consider extracting this validation into a helper method to ensure consistency.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +289 to +293
self._pending_node_queries: Dict[str, dict] = {}

self.manage_topic_client = self.node.create_client(
ManageTopic,
manage_service_name
)
# Query initial parameters after a short delay to let nodes come up
self._initial_params_timer = self.node.create_timer(
2.0, self._fetch_initial_parameters_callback)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verify that _pending_node_queries cleanup occurs even if async callbacks fail. Currently _cleanup_node_query() is called in exception handlers, but ensure all error paths are covered to prevent memory leaks from orphaned client references.

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

Overview

This PR implements a significant architectural change to the Greenwave Monitor by replacing service-based topic management with a ROS 2 parameter-based approach. This makes the system more idiomatic to ROS 2 and enables easier configuration through YAML files and launch parameters.

Key Changes

1. Parameter-Based Topic Configuration

  • Replaces ManageTopic and SetExpectedFrequency services with ROS 2 parameters
  • Topics are now configured via parameters with naming convention: greenwave_diagnostics.<topic_name>.(expected_frequency|tolerance|enabled)
  • Supports both flat parameter syntax ("greenwave_diagnostics./topic.expected_frequency": 100) and nested YAML syntax
  • Parameters can be set at launch time, via YAML files, or dynamically at runtime

2. Core Component Refactoring

  • greenwave_diagnostics.hpp: Renamed from message_diagnostics.hpp, added comprehensive parameter handling with validation callbacks
  • greenwave_monitor.cpp: Refactored to use parameters instead of services, added external topic tracking to prevent conflicts
  • ui_adaptor.py: New Python module providing clean API for UI frontends to interact with parameter-based monitoring

3. Test Coverage

  • Added extensive test suite (test_parameters.py) covering startup behavior, dynamic changes, YAML config, validation, and multi-topic scenarios
  • Enhanced C++ unit tests (test_greenwave_diagnostics.cpp) for parameter validation and edge cases
  • Tests verify parameter rejection for invalid values (negative frequency, non-numeric types, etc.)

Critical Issue Found

Bug in external_on_parameter_event: The function does not process changed_parameters, only new_parameters and deleted_parameters. This means when an external node changes an enabled parameter from true to false, the external_topic_to_node_ map is not updated, potentially blocking other nodes from monitoring that topic.

Architecture Benefits

  1. More ROS 2 Idiomatic: Parameters are the standard ROS 2 way to configure node behavior
  2. Better Tooling Support: Can use standard ros2 param CLI and rqt_reconfigure
  3. Declarative Configuration: YAML files provide clear, version-controlled configuration
  4. Dynamic Reconfiguration: Parameters can be changed at runtime without service calls
  5. Better Integration: UI tools can subscribe to parameter events for automatic updates

Backwards Compatibility

The PR removes the service-based API entirely. The old topics parameter (list of strings) still works for basic topic monitoring, but advanced features (frequency/tolerance) require the new parameter structure.

Confidence Score: 3/5

  • This PR has significant architectural improvements but contains a logic bug that could cause operational issues in multi-node scenarios
  • Score of 3/5 reflects: (1) A confirmed logic bug in external_on_parameter_event that fails to handle changed_parameters, which could block topic monitoring in production; (2) Otherwise well-designed parameter system with comprehensive validation and extensive test coverage; (3) Breaking API change that removes service-based interface entirely; (4) Good test coverage but the existing tests don't catch the external parameter event bug
  • Pay close attention to greenwave_monitor/src/greenwave_monitor.cpp (lines 214-236) - the external_on_parameter_event function needs to be fixed to handle changed_parameters

Important Files Changed

File Analysis

Filename Score Overview
greenwave_monitor/src/greenwave_monitor.cpp 3/5 Major refactoring to use ROS parameters instead of services for topic management. Contains a logic bug in external parameter event handling that fails to process changed_parameters properly.
greenwave_monitor/include/greenwave_diagnostics.hpp 4/5 Renamed from message_diagnostics.hpp. Added comprehensive parameter handling for frequency, tolerance, and enabled state. Parameter validation and callbacks are well-implemented with proper mutex protection.
greenwave_monitor/greenwave_monitor/ui_adaptor.py 4/5 New UI adapter for parameter-based topic monitoring. Handles parameter events comprehensively, maintains topic-to-node mapping, and provides clean API for frontends. Well-structured threading and locking.
greenwave_monitor/test/test_parameters.py 5/5 Comprehensive test suite for parameter functionality covering startup behavior, multiple topics, YAML configuration, dynamic parameter changes, validation, and enable/disable functionality.
greenwave_monitor/test/test_greenwave_diagnostics.cpp 5/5 Extensive unit tests for greenwave_diagnostics including frame rate calculation, parameter validation, frequency/tolerance handling, and config impacts. Tests cover edge cases and boundary values thoroughly.

Sequence Diagram

sequenceDiagram
    participant User
    participant GreenwaveMonitor
    participant GreenwaveDiagnostics
    participant PublisherNode
    participant ParameterServer
    
    Note over User,ParameterServer: Topic Monitoring Setup (Startup)
    User->>GreenwaveMonitor: Launch with YAML config
    GreenwaveMonitor->>GreenwaveMonitor: fetch_external_topic_map()
    GreenwaveMonitor->>GreenwaveMonitor: get_topics_from_parameters()
    loop For each configured topic
        GreenwaveMonitor->>GreenwaveMonitor: validate_add_topic()
        GreenwaveMonitor->>GreenwaveDiagnostics: Create instance
        GreenwaveDiagnostics->>ParameterServer: Declare parameters (freq, tol, enabled)
        GreenwaveDiagnostics->>ParameterServer: Subscribe to parameter events
        GreenwaveMonitor->>GreenwaveMonitor: create_generic_subscription()
    end
    
    Note over User,ParameterServer: Runtime Parameter Change
    User->>ParameterServer: Set greenwave_diagnostics./topic.expected_frequency
    ParameterServer->>GreenwaveDiagnostics: Parameter change callback (validation)
    GreenwaveDiagnostics-->>ParameterServer: Validation result
    ParameterServer->>GreenwaveDiagnostics: Parameter event (if successful)
    GreenwaveDiagnostics->>GreenwaveDiagnostics: setExpectedDt(freq, tolerance)
    
    Note over User,ParameterServer: Enable/Disable Monitoring
    User->>ParameterServer: Set greenwave_diagnostics./topic.enabled = true
    ParameterServer->>GreenwaveMonitor: on_parameter_change (validation)
    GreenwaveMonitor->>GreenwaveMonitor: validate_add_topic()
    GreenwaveMonitor-->>ParameterServer: Validation result
    ParameterServer->>GreenwaveMonitor: on_parameter_event (if successful)
    GreenwaveMonitor->>GreenwaveMonitor: execute_add_topic()
    GreenwaveMonitor->>GreenwaveDiagnostics: Create diagnostics instance
    
    Note over User,ParameterServer: Message Flow
    PublisherNode->>GreenwaveMonitor: Publish message on topic
    GreenwaveMonitor->>GreenwaveDiagnostics: updateDiagnostics(timestamp)
    GreenwaveDiagnostics->>GreenwaveDiagnostics: Check frequency/jitter/timestamps
    GreenwaveMonitor->>GreenwaveDiagnostics: publishDiagnostics()
    GreenwaveDiagnostics->>User: Publish to /diagnostics topic
Loading

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR implements ROS 2 parameter-based configuration for topic monitoring, replacing the previous service-based approach. Topics can now be configured using greenwave_diagnostics.<topic_name>.expected_frequency, greenwave_diagnostics.<topic_name>.tolerance, and greenwave_diagnostics.<topic_name>.enabled parameters.

Key architectural changes:

  1. New GreenwaveDiagnostics class: Extracted diagnostics logic into a standalone header-only class (greenwave_diagnostics.hpp) that handles per-topic parameter management, validation, and diagnostics computation. Each instance manages parameters for a single topic.

  2. Parameter-based topic control: The enabled parameter controls whether a topic is actively monitored. Setting it to true triggers topic validation and subscription creation; false removes the topic from monitoring.

  3. Bidirectional parameter synchronization: Service calls previously used for configuration have been removed. All configuration now flows through ROS 2 parameters with proper validation callbacks.

  4. External node coordination: The monitor node tracks which topics are being monitored by other nodes to prevent duplicate monitoring, using a startup discovery phase and runtime parameter event monitoring.

  5. Dynamic parameter updates: Frequency and tolerance can be updated at runtime. Invalid values (negative tolerance, non-positive frequency, non-numeric types) are rejected with clear error messages.

The implementation includes comprehensive test coverage with both Python integration tests (test_parameters.py) and C++ unit tests (test_greenwave_diagnostics.cpp). The UI adaptor has been updated to work with the new parameter-based API.

Confidence Score: 4/5

  • Safe to merge after fixing the missing rcpputils dependency
  • The PR has one blocking issue: missing rcpputils dependency in package.xml. The code uses rcpputils::join but doesn't declare the dependency, which will cause build failures. Otherwise, the implementation is well-tested with comprehensive test coverage, proper parameter validation, and clean architecture. The previous review comments about documentation have been addressed.
  • greenwave_monitor/package.xml - missing rcpputils dependency

Important Files Changed

File Analysis

Filename Score Overview
greenwave_monitor/include/greenwave_diagnostics.hpp 4/5 New header-only diagnostics class with parameter handling; uses rcpputils::join but dependency not in package.xml
greenwave_monitor/src/greenwave_monitor.cpp 5/5 Monitor node refactored to use parameter-based topic management; replaces service-based approach
greenwave_monitor/greenwave_monitor/ui_adaptor.py 5/5 Python UI adaptor updated to work with parameter-based configuration
greenwave_monitor/test/test_parameters.py 5/5 Comprehensive test suite for parameter-based topic configuration
greenwave_monitor/test/test_greenwave_diagnostics.cpp 5/5 New C++ unit tests for GreenwaveDiagnostics class parameter handling
greenwave_monitor/config/greenwave_monitor.yaml 5/5 Example config file demonstrating nested parameter syntax
docs/images/SERVICES.md 5/5 Documentation updated to reflect parameter-based API; no issues found
greenwave_monitor/CMakeLists.txt 5/5 Build configuration updated with new test targets
greenwave_monitor/package.xml 4/5 Package manifest; missing rcpputils dependency used in greenwave_diagnostics.hpp

Sequence Diagram

sequenceDiagram
    participant User
    participant MonitorNode as GreenwaveMonitor
    participant DiagObj as GreenwaveDiagnostics
    participant ParamSvc as Parameter Service
    participant Publisher as Topic Publisher
    
    Note over User,Publisher: Startup Phase
    User->>MonitorNode: Launch with YAML config
    MonitorNode->>MonitorNode: fetch_external_topic_map()
    MonitorNode->>MonitorNode: get_topics_from_parameters()
    MonitorNode->>MonitorNode: Merge topics from params
    loop For each topic
        MonitorNode->>MonitorNode: validate_add_topic()
        MonitorNode->>MonitorNode: execute_add_topic()
        MonitorNode->>DiagObj: new GreenwaveDiagnostics()
        DiagObj->>ParamSvc: declare_parameter(freq, tol, enabled)
        DiagObj->>DiagObj: Register parameter callbacks
        MonitorNode->>Publisher: create_generic_subscription()
    end
    
    Note over User,Publisher: Runtime Operation
    Publisher->>MonitorNode: Publish message
    MonitorNode->>DiagObj: updateDiagnostics(timestamp)
    DiagObj->>DiagObj: Calculate frame rate & jitter
    
    User->>ParamSvc: ros2 param set .../topic.expected_frequency 100.0
    ParamSvc->>DiagObj: onParameterChange() [validation]
    alt Valid parameter
        DiagObj-->>ParamSvc: success=true
        ParamSvc->>DiagObj: onParameterEvent() [execution]
        DiagObj->>DiagObj: setExpectedDt(freq, tol)
    else Invalid parameter
        DiagObj-->>ParamSvc: success=false, reason
    end
    
    User->>ParamSvc: ros2 param set .../topic2.enabled true
    ParamSvc->>MonitorNode: on_parameter_change() [validation]
    MonitorNode->>MonitorNode: validate_add_topic()
    alt Topic valid
        MonitorNode-->>ParamSvc: success=true
        ParamSvc->>MonitorNode: internal_on_parameter_event()
        MonitorNode->>MonitorNode: execute_add_topic()
        MonitorNode->>DiagObj: new GreenwaveDiagnostics()
    else Topic not found
        MonitorNode-->>ParamSvc: success=false
    end
    
    Note over MonitorNode,DiagObj: Timer callback (1 Hz)
    MonitorNode->>DiagObj: publishDiagnostics()
    DiagObj->>DiagObj: Publish to /diagnostics topic
Loading

@greptile-apps
Copy link

greptile-apps bot commented Jan 9, 2026

Additional Comments (1)

greenwave_monitor/package.xml
[P0] Missing rcpputils dependency. The code uses rcpputils::join in greenwave_diagnostics.hpp:648 but rcpputils is not declared as a dependency. This will cause build failures when the package is built in isolation or when dependencies are not transitively available.

Add <depend>rcpputils</depend> to the dependencies list.

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

Adds ROS 2 parameter-based configuration for topic monitoring, allowing users to specify expected frequencies and tolerances through parameter files or dynamic commands instead of only through service calls. Parameters use the greenwave_diagnostics.<topic_name>.(expected_frequency|tolerance|enabled) naming convention with bidirectional synchronization between service calls and parameter changes. The ncurses dashboard reads parameters at startup and updates dynamically when parameters change.

Confidence Score: 3/5

  • Safe to merge after adding missing rcpputils dependency
  • The implementation is well-structured with comprehensive test coverage. The main issue is a missing build dependency (rcpputils) that will cause compilation failures in certain build configurations. The parameter validation logic correctly rejects invalid inputs, and the synchronization between parameters and diagnostics is properly implemented with mutex protection. Once the dependency is added, the code should function correctly.
  • greenwave_monitor/package.xml requires rcpputils dependency addition

Important Files Changed

File Analysis

Filename Score Overview
greenwave_monitor/include/greenwave_diagnostics.hpp 3/5 Adds parameter-based configuration for topic monitoring with expected frequency and tolerance
greenwave_monitor/src/greenwave_monitor.cpp 4/5 Implements parameter event handling and external node monitoring coordination
greenwave_monitor/package.xml 2/5 Package manifest missing rcpputils dependency used in greenwave_diagnostics.hpp

Sequence Diagram

sequenceDiagram
    participant User
    participant ParamFile as Parameter File/CLI
    participant Monitor as GreenwaveMonitor
    participant Diag as GreenwaveDiagnostics
    participant ParamEvents as /parameter_events

    User->>ParamFile: Set greenwave_diagnostics./topic.expected_frequency
    ParamFile->>Monitor: Parameter override at startup
    Monitor->>Diag: Create GreenwaveDiagnostics(config)
    Diag->>Diag: Register parameter callbacks
    Diag->>Diag: setParameterOrDefault() triggers callbacks
    Diag->>ParamEvents: Publish parameter event
    Diag->>Diag: onParameterEvent() updates expected_dt

    User->>Monitor: ros2 param set expected_frequency
    Monitor->>Diag: Parameter change validation
    Diag-->>Monitor: Validation result
    Monitor->>ParamEvents: Publish parameter event (if successful)
    Diag->>Diag: onParameterEvent() updates expected_dt
    
    User->>Monitor: ros2 param set enabled false
    Monitor->>Monitor: on_parameter_change() validation
    Monitor->>ParamEvents: Publish parameter event
    Monitor->>Monitor: internal_on_parameter_event() removes topic
Loading

@greptile-apps
Copy link

greptile-apps bot commented Jan 9, 2026

Additional Comments (1)

greenwave_monitor/package.xml
Missing rcpputils dependency. The code uses rcpputils::join in greenwave_diagnostics.hpp:642 but rcpputils is not declared as a dependency. This will cause build failures when the package is built in isolation or when dependencies are not transitively available.

  <depend>rclcpp</depend>
  <depend>rcpputils</depend>
  <depend>std_msgs</depend>
  <depend>diagnostic_msgs</depend>
  <depend>sensor_msgs</depend>
  <depend>rclpy</depend>

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR adds ROS 2 parameter-based configuration for topic monitoring, allowing users to specify expected frequencies and tolerances through parameter files or dynamic parameter commands instead of only through service calls. The implementation provides bidirectional synchronization between parameters and monitoring state.

Key Changes

  • Parameter Structure: Topics configured via greenwave_diagnostics.<topic_name>.expected_frequency and greenwave_diagnostics.<topic_name>.tolerance parameters
  • Dynamic Parameter Handling: Full runtime parameter modification with validation (frequency must be positive, tolerance non-negative, only numeric types accepted)
  • Topic Enable/Disable: New greenwave_diagnostics.<topic_name>.enabled parameter controls monitoring on/off
  • UI Integration: ncurses dashboard reads and displays expected frequencies from parameters
  • Comprehensive Tests: Extensive test coverage for YAML config, dynamic changes, validation, and multi-topic scenarios

Issues Found

  • Critical: Missing rcpputils include in greenwave_diagnostics.hpp will cause compilation failure (line 642 uses rcpputils::join without include)
  • Critical: Missing rcpputils dependency in package.xml will cause build failures in isolation
  • Logic Error: Python ui_adaptor.py stores NaN values instead of clearing frequency entries (line 491)
  • Minor: Typo "Iniital" in log message (line 739)
  • Style: Inconsistent idempotency in enabled parameter handling

Confidence Score: 3/5

  • This PR has compilation and logic issues that must be fixed before merging
  • Score reflects critical build-breaking issues (missing rcpputils include and dependency) and a logic error in Python NaN handling that could cause incorrect behavior. The core implementation is sound with good test coverage, but these issues prevent safe merging.
  • Pay close attention to greenwave_monitor/include/greenwave_diagnostics.hpp (missing include), greenwave_monitor/package.xml (missing dependency), and greenwave_monitor/greenwave_monitor/ui_adaptor.py (NaN logic error)

Important Files Changed

File Analysis

Filename Score Overview
greenwave_monitor/include/greenwave_diagnostics.hpp 3/5 Adds ROS 2 parameter support for topic frequency/tolerance configuration. Issues: missing rcpputils include (compilation failure), typo in log message, parameter deletion explicitly rejected but should align with clearing behavior.
greenwave_monitor/src/greenwave_monitor.cpp 4/5 Implements enabled parameter handling for topic monitoring control. Minor style issue with idempotency - enabling already-enabled topic succeeds silently but disabling non-monitored topic fails.
greenwave_monitor/greenwave_monitor/ui_adaptor.py 3/5 Adds parameter-based topic control for UI. Critical logic error in NaN handling - stores NaN values instead of clearing them from expected_frequencies dict.
greenwave_monitor/test/test_parameters.py 5/5 Comprehensive test coverage for parameter-based configuration including YAML, dynamic changes, validation, and multi-topic scenarios. Well-structured tests.
greenwave_monitor/package.xml 2/5 Missing rcpputils dependency - code uses rcpputils::join but dependency not declared, will cause build failures in isolation.
docs/images/SERVICES.md 5/5 Updated documentation for parameter-based configuration. Clear examples and usage patterns documented.

Sequence Diagram

sequenceDiagram
    participant User
    participant GreenwaveMonitor
    participant GreenwaveDiagnostics
    participant ParameterService
    participant ParameterEvents
    participant UiAdaptor

    Note over User,UiAdaptor: Setting Expected Frequency via Parameter

    User->>ParameterService: ros2 param set greenwave_diagnostics./topic.expected_frequency 100.0
    ParameterService->>GreenwaveDiagnostics: onParameterChange(freq=100.0)
    GreenwaveDiagnostics->>GreenwaveDiagnostics: Validate: freq > 0 or isNaN
    alt validation fails
        GreenwaveDiagnostics-->>ParameterService: SetParametersResult(successful=false)
        ParameterService-->>User: Error message
    else validation succeeds
        GreenwaveDiagnostics-->>ParameterService: SetParametersResult(successful=true)
        ParameterService->>ParameterEvents: Publish ParameterEvent(changed_parameters)
        ParameterEvents->>GreenwaveDiagnostics: onParameterEvent(changed)
        GreenwaveDiagnostics->>GreenwaveDiagnostics: setExpectedDt(100.0, tolerance)
        ParameterEvents->>UiAdaptor: onParameterEvent(changed)
        UiAdaptor->>UiAdaptor: Update expected_frequencies dict
        ParameterService-->>User: Success
    end

    Note over User,UiAdaptor: Enabling/Disabling Topic Monitoring

    User->>ParameterService: ros2 param set greenwave_diagnostics./topic.enabled true
    ParameterService->>GreenwaveMonitor: on_parameter_change(enabled=true)
    GreenwaveMonitor->>GreenwaveMonitor: validate_add_topic()
    alt topic validation fails
        GreenwaveMonitor-->>ParameterService: SetParametersResult(successful=false)
        ParameterService-->>User: Error message
    else validation succeeds
        GreenwaveMonitor->>GreenwaveMonitor: Store in pending_validations_
        GreenwaveMonitor-->>ParameterService: SetParametersResult(successful=true)
        ParameterService->>ParameterEvents: Publish ParameterEvent(new_parameters)
        ParameterEvents->>GreenwaveMonitor: internal_on_parameter_event()
        GreenwaveMonitor->>GreenwaveMonitor: execute_add_topic()
        GreenwaveMonitor->>GreenwaveMonitor: Create subscription
        GreenwaveMonitor->>GreenwaveDiagnostics: new GreenwaveDiagnostics()
        GreenwaveDiagnostics->>GreenwaveDiagnostics: Declare frequency/tolerance params
        ParameterEvents->>UiAdaptor: onParameterEvent(new)
        UiAdaptor->>UiAdaptor: Update topic_to_node map
        ParameterService-->>User: Success
    end

    Note over User,UiAdaptor: UI Adaptor Reading Parameters at Startup

    UiAdaptor->>UiAdaptor: _fetch_initial_parameters_callback()
    loop For each node
        UiAdaptor->>ParameterService: ListParameters(prefix="greenwave_diagnostics")
        ParameterService-->>UiAdaptor: Parameter names
        UiAdaptor->>ParameterService: GetParameters(names)
        ParameterService-->>UiAdaptor: Parameter values
        UiAdaptor->>UiAdaptor: Parse and store in expected_frequencies
    end
Loading

Comment on lines +159 to +163
if (greenwave_diagnostics_.find(topic) == greenwave_diagnostics_.end()) {
result.successful = false;
result.reason = "Topic not being monitored: " + topic;
return result;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inconsistent idempotency - disabling non-monitored topic fails, but enabling already-monitored topic succeeds silently

Lines 145-148 allow enabling an already-enabled topic (silently continues), but lines 159-163 reject disabling a non-monitored topic with an error. Consider making both operations idempotent for consistency:

Suggested change
if (greenwave_diagnostics_.find(topic) == greenwave_diagnostics_.end()) {
result.successful = false;
result.reason = "Topic not being monitored: " + topic;
return result;
}
if (greenwave_diagnostics_.find(topic) == greenwave_diagnostics_.end()) {
// Topic not monitored, disabling is idempotent - silently succeed
continue;
}

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR successfully migrates the Greenwave Monitor from a service-based architecture to a parameter-based configuration system, enabling more flexible and ROS-native topic monitoring control.

Key Architectural Changes

Service Removal: Completely removes the greenwave_monitor_interfaces package with its ManageTopic and SetExpectedFrequency services, replacing them with ROS 2 parameters following the naming convention greenwave_diagnostics.<topic_name>.(expected_frequency|tolerance|enabled).

Bidirectional Synchronization: Implements a two-way sync mechanism where:

  • Parameter changes trigger monitoring updates via onParameterEvent
  • Service-like operations (add/remove topics, set frequencies) now update parameters
  • Both the monitor node and publisher nodes can manage their own topic parameters

External Node Tracking: The monitor node discovers and tracks topics being monitored by other nodes through the external_topic_to_node_ map, preventing duplicate monitoring and respecting ownership boundaries.

Implementation Quality

The implementation includes comprehensive validation (positive frequencies, non-negative tolerances, type checking) and extensive test coverage. The Python UI adaptor demonstrates good async patterns for parameter discovery across multiple nodes.

Critical Issues Found

  1. Build Failure: Missing rcpputils include and dependency for rcpputils::join() used in error message formatting (line 650 of greenwave_diagnostics.hpp)
  2. Potential KeyError: Python code attempts to delete dictionary keys without checking existence in parameter deletion handler (ui_adaptor.py:511)

Non-Critical Issues

  • Typo in warning message: "Iniital" → "Initial"
  • Parameter deletion is rejected entirely rather than treated as "clear" operation
  • Synchronous validation in parameter callback can block up to 0.5 seconds during publisher discovery

The feature is well-designed and thoroughly tested, but the missing dependency will cause immediate build failures that must be resolved before merge.

Confidence Score: 2/5

  • This PR has a critical build failure due to missing rcpputils dependency and a potential runtime crash in Python code
  • Score of 2 reflects that while the feature is well-designed with excellent test coverage, there is a guaranteed compilation failure (missing rcpputils include/dependency) and a potential runtime crash (KeyError in Python). The missing dependency alone would prevent the code from building. Once these issues are fixed, the PR would be much safer (4-5 range) as the core logic is sound.
  • Critical attention needed for greenwave_monitor/package.xml (add rcpputils dependency), greenwave_monitor/include/greenwave_diagnostics.hpp (add include), and greenwave_monitor/greenwave_monitor/ui_adaptor.py (fix KeyError in line 511)

Important Files Changed

File Analysis

Filename Score Overview
greenwave_monitor/include/greenwave_diagnostics.hpp 3/5 Added parameter-based configuration system with validation and synchronization. Missing rcpputils include/dependency. Contains typo in warning message.
greenwave_monitor/src/greenwave_monitor.cpp 4/5 Replaced service-based topic management with parameter-based system. Implements validation, external node tracking, and deferred topic addition via pending_validations.
greenwave_monitor/greenwave_monitor/ui_adaptor.py 4/5 Enhanced UI adaptor with async parameter querying, topic-to-node mapping, and bidirectional parameter synchronization. Well-structured implementation.
greenwave_monitor/test/test_parameters.py 5/5 Comprehensive test suite covering parameter validation, dynamic updates, YAML config, and edge cases. Well-organized.
greenwave_monitor/package.xml 2/5 Removed greenwave_monitor_interfaces dependency but missing rcpputils dependency needed by code.

Sequence Diagram

sequenceDiagram
    participant User
    participant MonitorNode as GreenwaveMonitor
    participant PublisherNode as Publisher Node
    participant Diagnostics as GreenwaveDiagnostics
    participant ParamEvents as /parameter_events

    Note over User,ParamEvents: Startup: Topic Discovery & Parameter Loading
    
    MonitorNode->>MonitorNode: fetch_external_topic_map()
    MonitorNode->>PublisherNode: Query parameters via SyncParametersClient
    PublisherNode-->>MonitorNode: Return greenwave_diagnostics.* params
    MonitorNode->>MonitorNode: Build external_topic_to_node_ map
    
    MonitorNode->>MonitorNode: get_topics_from_parameters()
    MonitorNode->>MonitorNode: Merge with 'topics' list parameter
    
    loop For each topic
        MonitorNode->>MonitorNode: validate_add_topic(topic)
        MonitorNode->>MonitorNode: execute_add_topic(topic)
        MonitorNode->>Diagnostics: Create GreenwaveDiagnostics
        Diagnostics->>Diagnostics: Register onParameterChange callback
        Diagnostics->>ParamEvents: Subscribe to /parameter_events
        Diagnostics->>Diagnostics: setParameterOrDefault() for freq/tol/enabled
    end

    Note over User,ParamEvents: Runtime: Parameter-Based Configuration

    User->>MonitorNode: ros2 param set enabled=true
    MonitorNode->>MonitorNode: on_parameter_change()
    MonitorNode->>MonitorNode: validate_add_topic() (with retries)
    alt Validation succeeds
        MonitorNode->>MonitorNode: Store in pending_validations_
        MonitorNode-->>User: Success
        ParamEvents->>MonitorNode: ParameterEvent (new/changed)
        MonitorNode->>MonitorNode: internal_on_parameter_event()
        MonitorNode->>MonitorNode: execute_add_topic() from pending
        MonitorNode->>Diagnostics: Create GreenwaveDiagnostics
    else Validation fails
        MonitorNode-->>User: Error (no publisher found)
    end

    User->>Diagnostics: ros2 param set expected_frequency=30.0
    Diagnostics->>Diagnostics: onParameterChange() validation
    alt Frequency valid (positive or NaN)
        Diagnostics-->>User: Success
        ParamEvents->>Diagnostics: ParameterEvent
        Diagnostics->>Diagnostics: onParameterEvent()
        Diagnostics->>Diagnostics: setExpectedDt(freq, tolerance)
        Diagnostics->>Diagnostics: Enable time diagnostics
    else Frequency invalid (≤0)
        Diagnostics-->>User: Error: must be positive or NaN
    end

    Note over User,ParamEvents: Runtime: Message Monitoring

    PublisherNode->>Diagnostics: updateDiagnostics(timestamp)
    Diagnostics->>Diagnostics: Check enabled flag
    alt Enabled
        Diagnostics->>Diagnostics: Calculate frame rates & jitter
        Diagnostics->>Diagnostics: Check vs expected_dt if set
        Diagnostics->>Diagnostics: Update status (OK/WARN/ERROR)
    else Disabled
        Diagnostics->>Diagnostics: Skip update
    end

    loop Every 1 second
        MonitorNode->>Diagnostics: publishDiagnostics()
        Diagnostics->>ParamEvents: Publish to /diagnostics topic
    end

    Note over User,ParamEvents: Runtime: Disabling Monitoring

    User->>MonitorNode: ros2 param set enabled=false
    MonitorNode->>MonitorNode: on_parameter_change()
    MonitorNode->>MonitorNode: Check not external topic
    MonitorNode-->>User: Success
    ParamEvents->>MonitorNode: ParameterEvent (changed)
    MonitorNode->>MonitorNode: internal_on_parameter_event()
    MonitorNode->>MonitorNode: remove_topic()
    MonitorNode->>Diagnostics: Destroy GreenwaveDiagnostics
    Note right of Diagnostics: Parameters persist for re-enable
Loading

@greptile-apps
Copy link

greptile-apps bot commented Jan 9, 2026

Additional Comments (1)

greenwave_monitor/package.xml
Missing rcpputils dependency. The code in greenwave_diagnostics.hpp:650 uses rcpputils::join() but this dependency is not declared. This will cause build failures when the package is built in isolation or when transitive dependencies are not available.

  <depend>rclcpp</depend>
  <depend>rcpputils</depend>
  <depend>std_msgs</depend>
  <depend>diagnostic_msgs</depend>
  <depend>sensor_msgs</depend>
  <depend>rclpy</depend>

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR implements ROS 2 parameter-based configuration for topic monitoring in the Greenwave Monitor system. It replaces the previous service-based approach with a more idiomatic ROS 2 parameter system.

Key Changes

Parameter Structure: Topics can now be configured using greenwave_diagnostics.<topic_name>.(expected_frequency|tolerance|enabled) parameters, supporting both flat dotted notation and nested dictionary format in YAML files.

Architecture Shift: The entire greenwave_monitor_interfaces package has been removed, eliminating custom service definitions (ManageTopic.srv, SetExpectedFrequency.srv) in favor of standard ROS 2 parameter services.

Bidirectional Synchronization: Parameter changes trigger monitoring updates, and the system maintains consistency between parameter state and runtime behavior.

New Components:

  • GreenwaveDiagnostics class now manages its own parameters with validation and callbacks
  • GreenwaveUiAdaptor provides thread-safe parameter-based UI integration
  • Comprehensive test coverage in test_parameters.py and test_greenwave_diagnostics.cpp

Critical Issues Found

Compilation Failure: The code uses rcpputils::join() but neither includes the header nor declares the dependency in package.xml. This will prevent the package from building.

Runtime Crashes: Two instances of unsafe dictionary deletion in ui_adaptor.py will cause KeyError exceptions when parameters are modified before diagnostics messages arrive.

Implementation Quality

The parameter validation logic is well-designed with proper type checking, range validation, and atomic updates. The synchronization between onParameterChange() (validation) and onParameterEvent() (execution) correctly prevents partial parameter updates. The external node tracking mechanism properly handles multi-node monitoring scenarios.

Confidence Score: 2/5

  • Not safe to merge - contains compilation-blocking issues (missing rcpputils dependency) and runtime crashes (KeyError exceptions)
  • The PR has two P0 blocking issues: (1) missing rcpputils include and dependency causes compilation failure, and (2) potential KeyError exceptions in Python code will cause runtime crashes. Additionally, there are two P1 issues with the same KeyError pattern that need fixing.
  • greenwave_monitor/include/greenwave_diagnostics.hpp (missing include), greenwave_monitor/package.xml (missing dependency), greenwave_monitor/greenwave_monitor/ui_adaptor.py (KeyError bugs on lines 484 and 511)

Important Files Changed

File Analysis

Filename Score Overview
greenwave_monitor/include/greenwave_diagnostics.hpp 3/5 New header-only diagnostics class with parameter management. Uses rcpputils::join without including header or dependency.
greenwave_monitor/package.xml 3/5 Removed greenwave_monitor_interfaces dependency. Missing rcpputils dependency needed by greenwave_diagnostics.hpp.
greenwave_monitor/src/greenwave_monitor.cpp 4/5 Refactored to use parameter-based topic management. Proper validation and synchronization logic for parameter events.
greenwave_monitor/greenwave_monitor/ui_adaptor.py 3/5 UI adaptor for parameter-based monitoring. Potential KeyError on line 484 and 511 when deleting non-existent keys.
greenwave_monitor/CMakeLists.txt 5/5 Build configuration updated to use header-only greenwave_diagnostics library. No issues found.
greenwave_monitor/test/test_parameters.py 5/5 Comprehensive parameter testing added. Covers various scenarios including dynamic parameter changes.
docs/images/SERVICES.md 5/5 Documentation updated to reflect parameter-based configuration. Clear examples provided.
greenwave_monitor/include/greenwave_monitor.hpp 5/5 Monitor node header updated with parameter-based topic management interfaces. Clean implementation.

Sequence Diagram

sequenceDiagram
    participant User
    participant ROS2_Param as ROS2 Parameter Service
    participant Monitor as GreenwaveMonitor
    participant Diag as GreenwaveDiagnostics
    participant UI as ncurses/UI Adaptor
    
    Note over User,UI: Topic Monitoring Setup
    User->>ROS2_Param: ros2 param set greenwave_diagnostics./topic.enabled true
    ROS2_Param->>Monitor: on_parameter_change(enabled=true)
    Monitor->>Monitor: validate_add_topic()
    Monitor-->>ROS2_Param: SetParametersResult(success=true)
    ROS2_Param->>Monitor: ParameterEvent(new_parameters)
    Monitor->>Monitor: execute_add_topic()
    Monitor->>Diag: create GreenwaveDiagnostics
    Diag->>Diag: declare parameters
    Diag->>ROS2_Param: set default parameters
    
    Note over User,UI: Frequency Configuration
    User->>ROS2_Param: ros2 param set greenwave_diagnostics./topic.expected_frequency 30.0
    ROS2_Param->>Diag: onParameterChange()
    Diag->>Diag: validate frequency > 0
    Diag-->>ROS2_Param: SetParametersResult(success=true)
    ROS2_Param->>Diag: ParameterEvent(changed_parameters)
    Diag->>Diag: setExpectedDt(30.0, tolerance)
    
    Note over User,UI: Runtime Monitoring
    Monitor->>Monitor: topic_callback(msg)
    Monitor->>Diag: updateDiagnostics(timestamp)
    Diag->>Diag: check frequency/jitter
    Monitor->>Diag: publishDiagnostics()
    Diag->>UI: DiagnosticArray on /diagnostics
    UI->>UI: update UI display
    
    Note over User,UI: Topic Removal
    User->>ROS2_Param: ros2 param set greenwave_diagnostics./topic.enabled false
    ROS2_Param->>Monitor: on_parameter_change(enabled=false)
    Monitor->>Monitor: validate removal
    Monitor-->>ROS2_Param: SetParametersResult(success=true)
    ROS2_Param->>Monitor: ParameterEvent(changed_parameters)
    Monitor->>Monitor: remove_topic()
    Monitor->>Monitor: destroy subscription
    Note over Diag: Parameters persist for future use
Loading

@greptile-apps
Copy link

greptile-apps bot commented Jan 9, 2026

Additional Comments (1)

greenwave_monitor/package.xml
[P0] Missing <depend>rcpputils</depend> dependency. The code uses rcpputils::join in greenwave_diagnostics.hpp:650 but this dependency is not declared. This will cause build failures when the package is built in isolation or when transitive dependencies are not available.

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

Overview

This PR implements parameter-based configuration for topic monitoring frequencies and tolerances. Instead of only service calls, users can now configure topics through ROS 2 parameters (both flat dotted notation and nested YAML format), with full bidirectional synchronization between parameters and service calls.

Key Changes

  • Parameter Structure: Topics are configured using greenwave_diagnostics.<topic_name>.expected_frequency, greenwave_diagnostics.<topic_name>.tolerance, and greenwave_diagnostics.<topic_name>.enabled parameters
  • Bidirectional Synchronization: Parameter changes trigger monitoring updates; both representations stay in sync
  • Dynamic Parameter Handling: Full support for runtime parameter modification with validation (positive frequency, non-negative tolerance, numeric types only)
  • Interface Changes: Removed custom service interfaces (ManageTopic.srv, SetExpectedFrequency.srv) in favor of standard parameter-based control
  • Python Frontend: ncurses dashboard now reads parameters and supports dynamic reconfiguration

Critical Issues Found

  1. Missing rcpputils dependency - Code uses rcpputils::join() but the dependency is not declared in package.xml and the header is not included in greenwave_diagnostics.hpp. This will cause compilation failures.

Code Quality

  • Comprehensive test coverage with 16+ test cases covering startup behavior, multiple topics, YAML configuration, dynamic parameters, and edge cases
  • Proper parameter validation (non-positive frequencies rejected, negative tolerances rejected, non-numeric types rejected, parameter deletion rejected)
  • Thread-safe implementation with mutex locks for shared state
  • Good error handling and logging throughout

Confidence Score: 2/5

  • This PR has critical build issues that must be resolved before merging. Missing rcpputils dependency in both package.xml and header includes will prevent compilation.
  • Score of 2 reflects a single but critical blocker: the missing rcpputils dependency. The underlying functionality appears well-designed with comprehensive tests and proper parameter validation, but the code cannot compile in its current state. The rcpputils::join() function is used in the parameter validation error handling path (line 650 of greenwave_diagnostics.hpp), and both the C++ header include and package.xml dependency are missing. This is a compile-time error that prevents the code from building.
  • greenwave_monitor/include/greenwave_diagnostics.hpp (add missing #include), greenwave_monitor/package.xml (add missing rcpputils dependency)

Important Files Changed

File Analysis

Filename Score Overview
greenwave_monitor/include/greenwave_diagnostics.hpp 2/5 Header-only library for diagnostics configuration with parameter callbacks. Critical issue: missing #include <rcpputils/join.hpp> which will cause compilation failure when rcpputils::join() is called on line 650.
greenwave_monitor/package.xml 2/5 Package manifest missing critical rcpputils dependency. The code uses rcpputils::join() in greenwave_diagnostics.hpp but the dependency is not declared, causing build failures.
greenwave_monitor/src/greenwave_monitor.cpp 4/5 Main monitor node implementation with parameter handling, topic validation, and subscription management. Implementation is solid with proper mutex locking, error handling, and lifecycle management.
greenwave_monitor/test/test_parameters.py 5/5 Comprehensive test suite covering parameter-based configuration with multiple test scenarios including YAML loading, dynamic parameter changes, and edge cases. Tests are well-organized and thorough.

Sequence Diagram

sequenceDiagram
    actor User
    participant Launch as ROS Launch
    participant Monitor as greenwave_monitor
    participant Diag as GreenwaveDiagnostics
    participant Param as Parameter Events
    
    User->>Launch: Launch with parameters
    Launch->>Monitor: Load greenwave_diagnostics.* parameters
    Monitor->>Monitor: get_topics_from_parameters()
    Monitor->>Diag: Create GreenwaveDiagnostics per topic
    Diag->>Diag: declare_parameter(freq, tol, enabled)
    Diag->>Param: Subscribe to parameter events
    
    User->>Monitor: ros2 param set greenwave_diagnostics./topic.expected_frequency 50.0
    Monitor->>Param: Parameter change event
    Diag->>Diag: onParameterChange() validation
    Diag->>Param: Subscribe for parameter event
    Diag->>Diag: onParameterEvent() applies change
    Diag->>Diag: setExpectedDt() or clearExpectedDt()
    
    Monitor->>Diag: Message arrives on topic
    Monitor->>Diag: updateDiagnostics(msg_timestamp)
    Diag->>Diag: Check against expected frequency
    Monitor->>Diag: publishDiagnostics()

Loading

@greptile-apps
Copy link

greptile-apps bot commented Jan 9, 2026

Additional Comments (2)

greenwave_monitor/include/greenwave_diagnostics.hpp
Missing #include <rcpputils/join.hpp> header. The code uses rcpputils::join() on line 650 but this header is not included. This will cause a compilation error.

#include <algorithm>
#include <cstring>
#include <limits>
#include <cinttypes>
#include <cmath>
#include <mutex>
#include <optional>
#include <queue>
#include <string>
#include <vector>

#include "diagnostic_msgs/msg/diagnostic_array.hpp"
#include "diagnostic_msgs/msg/diagnostic_status.hpp"
#include "diagnostic_msgs/msg/key_value.hpp"
#include "std_msgs/msg/header.hpp"
#include "builtin_interfaces/msg/time.hpp"
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
#include "rcl_interfaces/msg/parameter_event.hpp"
#include "rcl_interfaces/msg/set_parameters_result.hpp"
#include "rclcpp/rclcpp.hpp"
#include <rcpputils/join.hpp>

greenwave_monitor/package.xml
Missing rcpputils dependency. The code uses rcpputils::join in greenwave_diagnostics.hpp but this dependency is not declared. This will cause build failures when the package is built in isolation or when transitive dependencies are not available.

  <buildtool_depend>ament_cmake</buildtool_depend>
  <buildtool_depend>ament_cmake_auto</buildtool_depend>
  <buildtool_depend>ament_cmake_python</buildtool_depend>

  <depend>rclcpp</depend>
  <depend>rcpputils</depend>
  <depend>std_msgs</depend>
  <depend>diagnostic_msgs</depend>
  <depend>sensor_msgs</depend>
  <depend>rclpy</depend>

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR implements ROS 2 parameter-based configuration for topic monitoring, replacing service-based configuration with a more idiomatic ROS 2 approach. The implementation allows users to specify expected frequencies and tolerances through parameter files or dynamic parameter commands.

Key Changes:

  • Parameter Structure: Topics configured using greenwave_diagnostics.<topic>.expected_frequency, greenwave_diagnostics.<topic>.tolerance, and greenwave_diagnostics.<topic>.enabled parameters
  • Bidirectional Sync: Service-like behavior maintained through parameter callbacks that validate and apply changes
  • Dynamic Parameters: Full runtime modification support with validation (frequency must be positive, tolerance non-negative)
  • Multi-Node Support: External node tracking prevents duplicate monitoring across multiple monitor instances
  • Backward Compatibility: Original topics list parameter still supported for initialization

Critical Issues Found:

  1. Missing rcpputils dependency in package.xml will cause build failures
  2. Inconsistent NaN handling in ui_adaptor.py stores NaN values instead of clearing them as documented

Confidence Score: 2/5

  • Not safe to merge due to missing dependency that will cause build failures
  • The missing rcpputils dependency is a blocking issue that will cause compilation failures when building the package. The NaN handling inconsistency is a logic bug that could cause unexpected behavior in the UI.
  • greenwave_monitor/package.xml (missing dependency), greenwave_monitor/greenwave_monitor/ui_adaptor.py (NaN handling bug)

Important Files Changed

File Analysis

Filename Score Overview
greenwave_monitor/package.xml 0/5 Missing rcpputils dependency that is required by greenwave_diagnostics.hpp
greenwave_monitor/include/greenwave_diagnostics.hpp 4/5 Uses rcpputils::join for error message formatting in parameter validation
greenwave_monitor/greenwave_monitor/ui_adaptor.py 3/5 Inconsistent NaN handling in parameter event processing stores NaN instead of clearing
greenwave_monitor/src/greenwave_monitor.cpp 5/5 Parameter-based topic monitoring implementation with external node tracking
greenwave_monitor/test/test_parameters.py 5/5 Comprehensive test coverage for parameter-based configuration including dynamic updates

Sequence Diagram

sequenceDiagram
    participant User
    participant ROSParam as ROS Parameter System
    participant Monitor as GreenwaveMonitor
    participant Diag as GreenwaveDiagnostics
    participant UI as GreenwaveUiAdaptor

    Note over User,UI: Initialization Phase
    User->>Monitor: Launch with YAML config
    Monitor->>ROSParam: declare parameters from overrides
    Monitor->>Monitor: fetch_external_topic_map()
    Monitor->>Monitor: get_topics_from_parameters()
    loop For each topic
        Monitor->>Diag: Create GreenwaveDiagnostics
        Diag->>ROSParam: declare/set freq/tol/enabled params
        Diag->>Diag: Register parameter callbacks
    end
    Monitor->>ROSParam: Register parameter callbacks

    Note over User,UI: Dynamic Parameter Changes
    User->>ROSParam: set greenwave_diagnostics./topic.expected_frequency
    ROSParam->>Diag: onParameterChange (validate)
    Diag-->>ROSParam: validation result
    ROSParam->>Diag: onParameterEvent (execute)
    Diag->>Diag: setExpectedDt(freq, tol)
    
    Note over User,UI: Topic Enable/Disable
    User->>ROSParam: set greenwave_diagnostics./topic.enabled=false
    ROSParam->>Monitor: on_parameter_change (validate)
    Monitor-->>ROSParam: validation result
    ROSParam->>Monitor: internal_on_parameter_event
    Monitor->>Monitor: remove_topic()
    Monitor->>Diag: destroy diagnostics object

    Note over User,UI: UI Integration
    UI->>ROSParam: Subscribe to /parameter_events
    ROSParam-->>UI: Parameter changes
    UI->>UI: Update expected_frequencies cache
    UI->>Monitor: Subscribe to /diagnostics
    Monitor-->>UI: Diagnostic messages
    UI->>UI: Update ui_diagnostics
Loading

Comment on lines +494 to +497
if field == 'freq':
# Treat NaN or non-positive as "cleared"
if value > 0 or math.isnan(value):
self.expected_frequencies[topic_name] = (value, current[1])
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Inconsistent NaN handling. The comment says "Treat NaN or non-positive as 'cleared'" but the condition if value > 0 or math.isnan(value): stores NaN values in expected_frequencies. This contradicts the intended behavior. If NaN should clear the frequency, it shouldn't be stored. This causes line 406 (if freq > 0 and not math.isnan(freq):) and line 583 (if freq <= 0.0 or math.isnan(freq):) to treat NaN inconsistently.

@greptile-apps
Copy link

greptile-apps bot commented Jan 9, 2026

Additional Comments (1)

greenwave_monitor/package.xml
[P0] Missing rcpputils dependency. The code uses rcpputils::join in greenwave_diagnostics.hpp:651 but this dependency is not declared. This will cause build failures when the package is built in isolation or when transitive dependencies are not available.

Signed-off-by: Blake McHale <bmchale@nvidia.com>
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

This PR replaces service-based configuration with ROS 2 parameter-based topic monitoring. Topics can now be configured via greenwave_diagnostics.<topic>.(enabled|expected_frequency|tolerance) parameters, supporting both runtime changes and launch-time YAML configuration.

Major Changes

  • Removed service interfaces (ManageTopic, SetExpectedFrequency) and greenwave_monitor_interfaces package entirely
  • Added parameter-based configuration with validation in GreenwaveDiagnostics class
  • Each monitored topic gets its own parameter namespace with enabled, expected_frequency, and tolerance fields
  • Python UI adaptor updated to work with new parameter-based system
  • Comprehensive test coverage added for parameter handling

Issues Found

  • Critical: Buffer overflow risk in GetTimestampFromSerializedMessage - accesses buffer[4-11] without bounds check
  • Critical: Missing rcpputils dependency in package.xml (code uses rcpputils::join)
  • Logic bug: Python ui_adaptor.py inconsistent NaN handling - stores NaN values despite comment saying they represent "cleared"
  • Performance: Each GreenwaveDiagnostics instance creates redundant subscription to /parameter_events (N subscriptions for N topics)

Positive Aspects

  • Well-tested with comprehensive C++ and Python tests
  • Clear parameter validation with helpful error messages
  • Proper mutex protection for shared diagnostics state
  • Good documentation in SERVICES.md explaining new parameter structure

Confidence Score: 2/5

  • Not safe to merge - contains critical buffer overflow vulnerability and missing dependency
  • Score reflects two critical issues that will cause failures: (1) buffer overflow in timestamp extraction can crash the node with malformed messages, (2) missing rcpputils dependency will cause build failures. Additionally, the NaN handling bug in Python could cause UI issues. These must be fixed before merging.
  • greenwave_monitor/src/greenwave_monitor.cpp (buffer overflow), greenwave_monitor/package.xml (missing dependency), greenwave_monitor/greenwave_monitor/ui_adaptor.py (logic bug)

Important Files Changed

File Analysis

Filename Score Overview
greenwave_monitor/include/greenwave_diagnostics.hpp 3/5 Added parameter-based configuration (frequency, tolerance, enabled) with validation and event handling. Each instance registers callbacks and subscribes to parameter events. Missing rcpputils dependency causes build issues.
greenwave_monitor/src/greenwave_monitor.cpp 2/5 Implements parameter-based topic management. Buffer overflow risk in GetTimestampFromSerializedMessage (no bounds check before accessing buffer[4-11]). Multiple subscriptions to /parameter_events per topic may cause performance issues.
greenwave_monitor/greenwave_monitor/ui_adaptor.py 3/5 Python UI adaptor for parameter-based monitoring. Logic inconsistency: line 496 stores NaN frequencies despite comment saying NaN means "cleared". Otherwise handles parameter events and topic toggling correctly.
greenwave_monitor/package.xml 1/5 Missing <depend>rcpputils</depend> dependency. Code uses rcpputils::join in greenwave_diagnostics.hpp:651 but dependency not declared, will cause build failures.

Sequence Diagram

sequenceDiagram
    participant User
    participant YAML/CLI
    participant GreenwaveMonitor
    participant GreenwaveDiagnostics
    participant ParameterEvents
    participant TopicPublisher
    
    Note over User,TopicPublisher: Initialization Phase
    YAML/CLI->>GreenwaveMonitor: Launch with parameters
    GreenwaveMonitor->>GreenwaveMonitor: deferred_init()
    GreenwaveMonitor->>GreenwaveMonitor: get_topics_from_parameters()
    loop For each topic with params
        GreenwaveMonitor->>GreenwaveDiagnostics: Create instance
        GreenwaveDiagnostics->>GreenwaveDiagnostics: Declare/set freq, tol, enabled params
        GreenwaveDiagnostics->>ParameterEvents: Subscribe to /parameter_events
        GreenwaveDiagnostics->>GreenwaveDiagnostics: Register param callback
    end
    
    Note over User,TopicPublisher: Runtime Parameter Changes
    User->>GreenwaveMonitor: ros2 param set greenwave_diagnostics./topic.expected_frequency 30.0
    GreenwaveMonitor->>GreenwaveDiagnostics: onParameterChange() validates
    alt Valid parameter
        GreenwaveMonitor-->>User: Success
        ParameterEvents->>GreenwaveDiagnostics: Parameter event published
        GreenwaveDiagnostics->>GreenwaveDiagnostics: onParameterEvent() applies change
        GreenwaveDiagnostics->>GreenwaveDiagnostics: setExpectedDt(freq, tol)
    else Invalid parameter
        GreenwaveMonitor-->>User: Error reason
    end
    
    Note over User,TopicPublisher: Topic Monitoring via enabled Parameter
    User->>GreenwaveMonitor: ros2 param set greenwave_diagnostics./new_topic.enabled true
    GreenwaveMonitor->>GreenwaveMonitor: on_parameter_change() validates topic
    GreenwaveMonitor->>GreenwaveMonitor: validate_add_topic()
    alt Topic has publishers
        GreenwaveMonitor->>GreenwaveMonitor: Pend validation
        ParameterEvents->>GreenwaveMonitor: Parameter committed
        GreenwaveMonitor->>GreenwaveMonitor: execute_add_topic()
        GreenwaveMonitor->>GreenwaveDiagnostics: Create new instance
        GreenwaveMonitor->>TopicPublisher: Subscribe to topic
    else No publishers
        GreenwaveMonitor-->>User: Error: No publishers found
    end
    
    Note over User,TopicPublisher: Message Flow and Diagnostics
    loop Every message
        TopicPublisher->>GreenwaveMonitor: Publish message
        GreenwaveMonitor->>GreenwaveDiagnostics: updateDiagnostics(timestamp)
        GreenwaveDiagnostics->>GreenwaveDiagnostics: Check freq/tolerance/jitter
    end
    
    loop Every 1 second
        GreenwaveMonitor->>GreenwaveDiagnostics: publishDiagnostics()
        GreenwaveDiagnostics->>ParameterEvents: Publish to /diagnostics
    end
Loading

Comment on lines +494 to +497
if field == 'freq':
# Treat NaN or non-positive as "cleared"
if value > 0 or math.isnan(value):
self.expected_frequencies[topic_name] = (value, current[1])
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

inconsistent NaN handling - comment says "Treat NaN or non-positive as 'cleared'" but if value > 0 or math.isnan(value): stores NaN values

if NaN means "cleared", don't store it:

Suggested change
if field == 'freq':
# Treat NaN or non-positive as "cleared"
if value > 0 or math.isnan(value):
self.expected_frequencies[topic_name] = (value, current[1])
if field == 'freq':
# Store positive frequencies, clear for NaN or non-positive
if value > 0 and not math.isnan(value):
self.expected_frequencies[topic_name] = (value, current[1])
else:
self.expected_frequencies.pop(topic_name, None)

Comment on lines +136 to +139
// Subscribe to parameter events
param_event_subscription_ = node_.create_subscription<rcl_interfaces::msg::ParameterEvent>(
"/parameter_events", 10,
std::bind(&GreenwaveDiagnostics::onParameterEvent, this, std::placeholders::_1));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

each GreenwaveDiagnostics instance creates its own subscription to /parameter_events - with N monitored topics, creates N redundant subscriptions to the same topic

more efficient: single subscription at GreenwaveMonitor level that dispatches to individual diagnostics objects

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps
Copy link

greptile-apps bot commented Jan 9, 2026

Additional Comments (1)

greenwave_monitor/src/greenwave_monitor.cpp
buffer overflow risk - no bounds check before accessing buffer[4] through buffer[11]

if serialized_message_ptr->get_rcl_serialized_message().buffer_length < 12, this causes undefined behavior

add check:

if (serialized_message_ptr->get_rcl_serialized_message().buffer_length < 12) {
  return std::chrono::time_point<std::chrono::system_clock>();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Configuration file for the ncurses dashboard,

2 participants