diff --git a/.github/workflows/debian-packages.yml b/.github/workflows/debian-packages.yml index 1f793ed..ab1dd57 100644 --- a/.github/workflows/debian-packages.yml +++ b/.github/workflows/debian-packages.yml @@ -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: diff --git a/.github/workflows/ros-tests.yml b/.github/workflows/ros-tests.yml index e985367..fd84112 100644 --- a/.github/workflows/ros-tests.yml +++ b/.github/workflows/ros-tests.yml @@ -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: diff --git a/README.md b/README.md index 7ba0e91..0532d71 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/greenwave_monitor/CMakeLists.txt b/greenwave_monitor/CMakeLists.txt index dd4eab9..026d208 100644 --- a/greenwave_monitor/CMakeLists.txt +++ b/greenwave_monitor/CMakeLists.txt @@ -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 diff --git a/greenwave_monitor/include/message_diagnostics.hpp b/greenwave_monitor/include/message_diagnostics.hpp index 8108c5a..d3c5bce 100644 --- a/greenwave_monitor/include/message_diagnostics.hpp +++ b/greenwave_monitor/include/message_diagnostics.hpp @@ -487,7 +487,6 @@ class MessageDiagnostics } return error_found; } - }; } // namespace message_diagnostics diff --git a/greenwave_monitor/include/minimal_publisher_node.hpp b/greenwave_monitor/include/minimal_publisher_node.hpp index 3c7e086..fb3a38c 100644 --- a/greenwave_monitor/include/minimal_publisher_node.hpp +++ b/greenwave_monitor/include/minimal_publisher_node.hpp @@ -17,6 +17,10 @@ #pragma once +#include +#include +#include + #include "rclcpp/rclcpp.hpp" #include "sensor_msgs/msg/image.hpp" #include "sensor_msgs/msg/imu.hpp" @@ -24,7 +28,7 @@ #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 { diff --git a/greenwave_monitor/src/greenwave_monitor.cpp b/greenwave_monitor/src/greenwave_monitor.cpp index 4204a49..c7679c2 100644 --- a/greenwave_monitor/src/greenwave_monitor.cpp +++ b/greenwave_monitor/src/greenwave_monitor.cpp @@ -18,11 +18,12 @@ #include "greenwave_monitor.hpp" #include -#include "rosidl_typesupport_introspection_cpp/message_introspection.hpp" #include #include #include +#include "rosidl_typesupport_introspection_cpp/message_introspection.hpp" + using namespace std::chrono_literals; GreenwaveMonitor::GreenwaveMonitor(const rclcpp::NodeOptions & options) @@ -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}, @@ -326,7 +327,7 @@ GreenwaveMonitor::GetTimestampFromSerializedMessage( const std::string & type) { if (!has_header_from_type(type)) { - return std::chrono::time_point(); // timestamp 0 as fallback + return std::chrono::time_point(); // timestamp 0 as fallback } int32_t timestamp_sec; diff --git a/greenwave_monitor/test/test_message_diagnostics.cpp b/greenwave_monitor/test/test_message_diagnostics.cpp index 56b1258..df3e0dc 100644 --- a/greenwave_monitor/test/test_message_diagnostics.cpp +++ b/greenwave_monitor/test/test_message_diagnostics.cpp @@ -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) @@ -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); @@ -98,7 +99,8 @@ TEST_F(MessageDiagnosticsTest, FrameRateNodeTest) const double expected_frame_rate = static_cast(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) @@ -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( - ::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); @@ -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(::message_diagnostics::constants::kMillisecondsToMicroseconds) * - static_cast(::message_diagnostics::constants::kMicrosecondsToNanoseconds); // 50 ms delay - auto msg_timestamp = test_constants::kStartTimestampNs; // Starting message timestamp in nanoseconds + static_cast(::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(); @@ -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; } diff --git a/greenwave_monitor_interfaces/CMakeLists.txt b/greenwave_monitor_interfaces/CMakeLists.txt index 315b95f..a3c2b46 100644 --- a/greenwave_monitor_interfaces/CMakeLists.txt +++ b/greenwave_monitor_interfaces/CMakeLists.txt @@ -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) diff --git a/greenwave_monitor_interfaces/package.xml b/greenwave_monitor_interfaces/package.xml index ed9bcaa..99fe344 100644 --- a/greenwave_monitor_interfaces/package.xml +++ b/greenwave_monitor_interfaces/package.xml @@ -2,9 +2,9 @@ greenwave_monitor_interfaces - 0.0.0 + 0.1.0 Interfaces for the greenwave_monitor package - user + Sean Gillen Apache-2.0 ament_cmake diff --git a/greenwave_monitor_interfaces/srv/ManageTopic.srv b/greenwave_monitor_interfaces/srv/ManageTopic.srv index 2fb4ff1..ae8abb1 100644 --- a/greenwave_monitor_interfaces/srv/ManageTopic.srv +++ b/greenwave_monitor_interfaces/srv/ManageTopic.srv @@ -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 diff --git a/greenwave_monitor_interfaces/srv/SetExpectedFrequency.srv b/greenwave_monitor_interfaces/srv/SetExpectedFrequency.srv index e362638..cf61ff4 100644 --- a/greenwave_monitor_interfaces/srv/SetExpectedFrequency.srv +++ b/greenwave_monitor_interfaces/srv/SetExpectedFrequency.srv @@ -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 diff --git a/r2s_gw/README.md b/r2s_gw/README.md index b9866ae..43b2948 100644 --- a/r2s_gw/README.md +++ b/r2s_gw/README.md @@ -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 ``` diff --git a/scripts/build_debian_packages.sh b/scripts/build_debian_packages.sh index 763af39..aa90873 100755 --- a/scripts/build_debian_packages.sh +++ b/scripts/build_debian_packages.sh @@ -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 diff --git a/scripts/docker-test.sh b/scripts/docker-test.sh index 8006c13..f59137d 100755 --- a/scripts/docker-test.sh +++ b/scripts/docker-test.sh @@ -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