Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .github/workflows/debian-packages.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

name: Generate Debian Packages

on:
Expand Down
17 changes: 17 additions & 0 deletions .github/workflows/ros-tests.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

name: ROS2 Tests

on:
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ Greenwave monitor is a tool for runtime monitoring of ROS 2 topics.

It provides the following features:

1. A node similar to a C++ based ros2 topic hz. I.E. subscribes to topics to determine the frame rate and latency. compared to ros2 topic hz the greenwave node is more performant, publishes Diagnostics, and offers services to manage topics and expected frequencies.
1. A node similar to a C++ based ros2 topic hz. i.e. subscribes to topics to determine the frame rate and latency. Compared to ros2 topic hz the greenwave node is more performant, publishes Diagnostics, and offers services to manage topics and expected frequencies.

2. A terminal based dashboard that displays the topic rates, latency, and status, and allows you to add/remove topics and set expected frequencies.

3. A header only C++ library so you can calculate and publish compatible diagnostics directly from your own nodes for reduced overhead.

This diagram shows an overview of the ![architecture](docs/images/greenwave_diagram.png)
This diagram shows an overview of the architecture:

![architecture](docs/images/greenwave_diagram.png)

## Diagnostic messages

Expand Down
7 changes: 0 additions & 7 deletions greenwave_monitor/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,6 @@ if(BUILD_TESTING)
find_package(ament_cmake_pytest REQUIRED)
find_package(ament_cmake_gtest REQUIRED)

# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()

# Add launch tests for greenwave_monitor
Expand Down
1 change: 0 additions & 1 deletion greenwave_monitor/include/message_diagnostics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,6 @@ class MessageDiagnostics
}
return error_found;
}

};

} // namespace message_diagnostics
6 changes: 5 additions & 1 deletion greenwave_monitor/include/minimal_publisher_node.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,18 @@

#pragma once

#include <memory>
#include <string>
#include <vector>

#include "rclcpp/rclcpp.hpp"
#include "sensor_msgs/msg/image.hpp"
#include "sensor_msgs/msg/imu.hpp"
#include "std_msgs/msg/string.hpp"
#include "message_diagnostics.hpp"
#include "rclcpp/subscription_options.hpp"

using namespace std::chrono_literals;
using std::chrono_literals::operator""ms;

class MinimalPublisher : public rclcpp::Node
{
Expand Down
7 changes: 4 additions & 3 deletions greenwave_monitor/src/greenwave_monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
#include "greenwave_monitor.hpp"

#include <algorithm>
#include "rosidl_typesupport_introspection_cpp/message_introspection.hpp"
#include <cstring>
#include <mutex>
#include <unordered_map>

#include "rosidl_typesupport_introspection_cpp/message_introspection.hpp"

using namespace std::chrono_literals;

GreenwaveMonitor::GreenwaveMonitor(const rclcpp::NodeOptions & options)
Expand Down Expand Up @@ -227,7 +228,7 @@ bool GreenwaveMonitor::has_header_from_type(const std::string & type_name)
{"std_msgs/msg/Float64", false},
{"std_msgs/msg/Bool", false},
{"std_msgs/msg/Empty", false},
{"std_msgs/msg/Header", false}, // Header itself doesn't have a header
{"std_msgs/msg/Header", false}, // Header itself doesn't have a header

// Common message types without headers
{"geometry_msgs/msg/Twist", false},
Expand Down Expand Up @@ -326,7 +327,7 @@ GreenwaveMonitor::GetTimestampFromSerializedMessage(
const std::string & type)
{
if (!has_header_from_type(type)) {
return std::chrono::time_point<std::chrono::system_clock>(); // timestamp 0 as fallback
return std::chrono::time_point<std::chrono::system_clock>(); // timestamp 0 as fallback
}

int32_t timestamp_sec;
Expand Down
32 changes: 19 additions & 13 deletions greenwave_monitor/test/test_message_diagnostics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ TEST_F(MessageDiagnosticsTest, FrameRateMsgTest)
message_diagnostics::MessageDiagnostics message_diagnostics(
*node_, "test_topic", message_diagnostics::MessageDiagnosticsConfig());

uint64_t timestamp = test_constants::kStartTimestampNs; // in nanoseconds
uint64_t timestamp = test_constants::kStartTimestampNs; // in nanoseconds
for (int i = 0; i < 1000; i++) {
message_diagnostics.updateDiagnostics(timestamp);
timestamp += 10000000; // 10 ms in nanoseconds
timestamp += 10000000; // 10 ms in nanoseconds
}
EXPECT_EQ(message_diagnostics.getFrameRateMsg(), 100); // 100 Hz
EXPECT_EQ(message_diagnostics.getFrameRateMsg(), 100); // 100 Hz
}

TEST_F(MessageDiagnosticsTest, FrameRateNodeTest)
Expand All @@ -82,11 +82,12 @@ TEST_F(MessageDiagnosticsTest, FrameRateNodeTest)
message_diagnostics::MessageDiagnostics message_diagnostics(
*node_, "test_topic", message_diagnostics::MessageDiagnosticsConfig());

constexpr auto timestamp = test_constants::kStartTimestampNs; // dummy timestamp, not used for node time calculation
// dummy timestamp, not used for node time calculation
constexpr auto timestamp = test_constants::kStartTimestampNs;
const auto start_time = std::chrono::high_resolution_clock::now();

constexpr int num_messages = 1000;
constexpr int interarrival_time_ms = 10; // 100 hz
constexpr int interarrival_time_ms = 10; // 100 hz

for (int i = 0; i < num_messages; i++) {
message_diagnostics.updateDiagnostics(timestamp);
Expand All @@ -98,7 +99,8 @@ TEST_F(MessageDiagnosticsTest, FrameRateNodeTest)

const double expected_frame_rate = static_cast<double>(num_messages) / total_duration.count();

EXPECT_NEAR(message_diagnostics.getFrameRateNode(), expected_frame_rate, 2.0); // allow 2.0 Hz error
// allow 2.0 Hz error
EXPECT_NEAR(message_diagnostics.getFrameRateNode(), expected_frame_rate, 2.0);
}

TEST_F(MessageDiagnosticsTest, MessageLatencyTest)
Expand All @@ -116,22 +118,24 @@ TEST_F(MessageDiagnosticsTest, MessageLatencyTest)

message_diagnostics.updateDiagnostics(msg_timestamp.nanoseconds());

EXPECT_NEAR(message_diagnostics.getLatency(), expected_latency_ms, 1.0); // allow 1 ms tolerance
EXPECT_NEAR(message_diagnostics.getLatency(), expected_latency_ms, 1.0); // allow 1 ms tolerance
}

TEST_F(MessageDiagnosticsTest, DiagnosticPublishSubscribeTest)
{
constexpr int input_frequency = 50; // 50 Hz
constexpr int input_frequency = 50; // 50 Hz
// 20 ms in nanoseconds
const int64_t interarrival_time_ns = static_cast<int64_t>(
::message_diagnostics::constants::kSecondsToNanoseconds / input_frequency); // 20 ms in nanoseconds
::message_diagnostics::constants::kSecondsToNanoseconds / input_frequency);

// Initialize MessageDiagnostics with diagnostics enabled
message_diagnostics::MessageDiagnosticsConfig config;
config.enable_msg_time_diagnostics = true;
config.enable_node_time_diagnostics = true;
config.enable_increasing_msg_time_diagnostics = true;
// in us
config.expected_dt_us = interarrival_time_ns /
::message_diagnostics::constants::kMicrosecondsToNanoseconds; // in us
::message_diagnostics::constants::kMicrosecondsToNanoseconds;

message_diagnostics::MessageDiagnostics message_diagnostics(*node_, "test_topic", config);

Expand All @@ -144,10 +148,12 @@ TEST_F(MessageDiagnosticsTest, DiagnosticPublishSubscribeTest)
received_diagnostics.push_back(msg);
});

// 50 ms delay
constexpr int64_t delay_time_ns = 50 *
static_cast<int64_t>(::message_diagnostics::constants::kMillisecondsToMicroseconds) *
static_cast<int64_t>(::message_diagnostics::constants::kMicrosecondsToNanoseconds); // 50 ms delay
auto msg_timestamp = test_constants::kStartTimestampNs; // Starting message timestamp in nanoseconds
static_cast<int64_t>(::message_diagnostics::constants::kMicrosecondsToNanoseconds);
// Starting message timestamp in nanoseconds
auto msg_timestamp = test_constants::kStartTimestampNs;

int sent_count = 0;
const auto start_time = std::chrono::high_resolution_clock::now();
Expand All @@ -170,7 +176,7 @@ TEST_F(MessageDiagnosticsTest, DiagnosticPublishSubscribeTest)
}
// Add a jitter by delaying at count 10
if (sent_count == 10) {
std::this_thread::sleep_for(std::chrono::nanoseconds(delay_time_ns)); // 50 ms delay
std::this_thread::sleep_for(std::chrono::nanoseconds(delay_time_ns)); // 50 ms delay
msg_timestamp += delay_time_ns;
}

Expand Down
17 changes: 17 additions & 0 deletions greenwave_monitor_interfaces/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.8)
project(greenwave_monitor_interfaces)

Expand Down
4 changes: 2 additions & 2 deletions greenwave_monitor_interfaces/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
<name>greenwave_monitor_interfaces</name>
<version>0.0.0</version>
<version>0.1.0</version>
<description>Interfaces for the greenwave_monitor package</description>
<maintainer email="[email protected]">user</maintainer>
<maintainer email="[email protected]">Sean Gillen</maintainer>
<license>Apache-2.0</license>

<buildtool_depend>ament_cmake</buildtool_depend>
Expand Down
17 changes: 17 additions & 0 deletions greenwave_monitor_interfaces/srv/ManageTopic.srv
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

# Request
string topic_name
bool add_topic # true to add, false to remove
Expand Down
17 changes: 17 additions & 0 deletions greenwave_monitor_interfaces/srv/SetExpectedFrequency.srv
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
# SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

# Request
string topic_name
float64 expected_hz
Expand Down
7 changes: 4 additions & 3 deletions r2s_gw/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ r2s_gw is written in Python and utilizes [Textual](https://github.com/textualize

## Installing

To run:
This package is bundled with the Greenwave Monitor repository. See the main [Greenwave Monitor README](../README.md) for installation instructions.

For standalone development:

```
git clone https://github.com/mjcarroll/r2s.git
cd r2s
cd r2s_gw
poetry install
poetry run r2s_gw
```
Expand Down
17 changes: 17 additions & 0 deletions scripts/build_debian_packages.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
#!/bin/bash

# SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

# Build Debian packages for greenwave_monitor
#
# This script builds .deb packages for greenwave_monitor_interfaces, greenwave_monitor, and r2s_gw
Expand Down
17 changes: 17 additions & 0 deletions scripts/docker-test.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
#!/bin/bash

# SPDX-FileCopyrightText: NVIDIA CORPORATION & AFFILIATES
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

# Docker test environment for Greenwave Monitor
# Quick way to test in different ROS 2 distributions

Expand Down