diff --git a/Dockerfile b/Dockerfile
index 52c6cfd..e999dac 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -89,6 +89,9 @@ RUN apt-get install -y python3-babeltrace python3-lttng python3-pytest python3-p
# So we install it using pip
RUN python3 -m pip install --upgrade bokeh
+# Install additional Python packages
+RUN python3 -m pip install --upgrade numexpr
+
# Add user to the "tracing" group
RUN usermod -aG tracing $USERNAME
diff --git a/src/simple_topology/CMakeLists.txt b/src/simple_topology/CMakeLists.txt
new file mode 100644
index 0000000..548d51b
--- /dev/null
+++ b/src/simple_topology/CMakeLists.txt
@@ -0,0 +1,42 @@
+cmake_minimum_required(VERSION 3.5)
+project(simple_topology)
+
+# Default to C99
+if(NOT CMAKE_C_STANDARD)
+ set(CMAKE_C_STANDARD 99)
+endif()
+
+# Default to C++14
+if(NOT CMAKE_CXX_STANDARD)
+ set(CMAKE_CXX_STANDARD 14)
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ add_compile_options(-Wall -Wextra -Wpedantic)
+endif()
+
+# find dependencies
+find_package(ament_cmake REQUIRED)
+find_package(rclcpp REQUIRED)
+find_package(std_msgs REQUIRED)
+
+add_executable(simple_topology src/simple_topology.cpp)
+ament_target_dependencies(simple_topology rclcpp std_msgs)
+install(TARGETS simple_topology DESTINATION lib/${PROJECT_NAME})
+install(
+ DIRECTORY launch
+ DESTINATION share/${PROJECT_NAME}
+)
+
+if(BUILD_TESTING)
+ find_package(ament_lint_auto REQUIRED)
+ # the following line skips the linter which checks for copyrights
+ # uncomment the line when a copyright and license is not present in all source files
+ #set(ament_cmake_copyright_FOUND TRUE)
+ # the following line skips cpplint (only works in a git repo)
+ # uncomment the line when this package is not in a git repo
+ #set(ament_cmake_cpplint_FOUND TRUE)
+ ament_lint_auto_find_test_dependencies()
+endif()
+
+ament_package()
diff --git a/src/simple_topology/launch/trace_simple_topology.launch.py b/src/simple_topology/launch/trace_simple_topology.launch.py
new file mode 100644
index 0000000..e4c7bad
--- /dev/null
+++ b/src/simple_topology/launch/trace_simple_topology.launch.py
@@ -0,0 +1,24 @@
+from launch import LaunchDescription
+from launch_ros.actions import Node
+from tracetools_launch.action import Trace
+
+def generate_launch_description():
+ return LaunchDescription([
+ # Start tracing automatically
+ Trace(
+ session_name='ros2_tracing_session',
+ events_ust=[
+ 'rclcpp:*', 'rcl:*', 'rmw:*', 'ros2:*', 'rclcpp:*callback*', 'rclcpp:*executor*'
+ ],
+ events_kernel=[
+ 'sched_switch', 'sched_wakeup'
+ ],
+ ),
+
+ # Your executable as a Node
+ Node(
+ package='simple_topology',
+ executable='simple_topology',
+ output='screen',
+ ),
+ ])
diff --git a/src/simple_topology/package.xml b/src/simple_topology/package.xml
new file mode 100644
index 0000000..6fc7362
--- /dev/null
+++ b/src/simple_topology/package.xml
@@ -0,0 +1,34 @@
+
+
+
+ simple_topology
+ 0.0.0
+ TODO: Package description
+ dev
+ TODO: License declaration
+
+ ament_cmake
+
+ launch
+ launch_ros
+ tracetools_trace
+ tracetools_launch
+
+ rclcpp
+ std_msgs
+
+ ament_copyright
+ ament_flake8
+ ament_mypy
+ ament_pep257
+ ament_xmllint
+ python3-pytest
+
+ ament_lint_auto
+ ament_lint_common
+
+
+ ament_cmake
+ ament_python
+
+
diff --git a/src/simple_topology/src/simple_topology.cpp b/src/simple_topology/src/simple_topology.cpp
new file mode 100644
index 0000000..e8e2489
--- /dev/null
+++ b/src/simple_topology/src/simple_topology.cpp
@@ -0,0 +1,110 @@
+// --- includes ---
+#include
+#include
+#include
+#include
+
+#include "rclcpp/rclcpp.hpp"
+#include "std_msgs/msg/string.hpp"
+
+using namespace std::chrono_literals;
+
+constexpr int RUN_DURATION_SECONDS = 5;
+
+// --- Sensor Node ---
+class SensorNode : public rclcpp::Node
+{
+public:
+ SensorNode() : Node("sensor_node")
+ {
+ publisher_ = this->create_publisher("sensor_topic", 10);
+ timer_ = this->create_wall_timer(
+ 100ms, [this]() { publish_message(); });
+ }
+
+private:
+ void publish_message()
+ {
+ auto message = std_msgs::msg::String();
+ message.data = "Sensor reading";
+ RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
+ publisher_->publish(message);
+ }
+
+ rclcpp::Publisher::SharedPtr publisher_;
+ rclcpp::TimerBase::SharedPtr timer_;
+};
+
+// --- Processing Node ---
+class ProcessingNode : public rclcpp::Node
+{
+public:
+ ProcessingNode() : Node("processing_node")
+ {
+ subscription_ = this->create_subscription(
+ "sensor_topic", 10,
+ [this](std_msgs::msg::String::SharedPtr msg) { process_message(msg); });
+ publisher_ = this->create_publisher("processed_topic", 10);
+ }
+
+private:
+ void process_message(const std_msgs::msg::String::SharedPtr msg)
+ {
+ RCLCPP_INFO(this->get_logger(), "Processing: '%s'", msg->data.c_str());
+ // Simulate processing delay
+ std::this_thread::sleep_for(10ms);
+ auto new_msg = std_msgs::msg::String();
+ new_msg.data = msg->data + " -> processed";
+ publisher_->publish(new_msg);
+ }
+
+ rclcpp::Subscription::SharedPtr subscription_;
+ rclcpp::Publisher::SharedPtr publisher_;
+};
+
+// --- Decision Node ---
+class DecisionNode : public rclcpp::Node
+{
+public:
+ DecisionNode() : Node("decision_node")
+ {
+ subscription_ = this->create_subscription(
+ "processed_topic", 10,
+ [this](std_msgs::msg::String::SharedPtr msg) { decide(msg); });
+ }
+
+private:
+ void decide(const std_msgs::msg::String::SharedPtr msg)
+ {
+ RCLCPP_INFO(this->get_logger(), "Deciding based on: '%s'", msg->data.c_str());
+ // Future place for semantic detection (e.g., "if smoke detected, boost priority!")
+ }
+
+ rclcpp::Subscription::SharedPtr subscription_;
+};
+
+// --- Main ---
+int main(int argc, char * argv[])
+{
+ rclcpp::init(argc, argv);
+
+ auto sensor_node = std::make_shared();
+ auto processing_node = std::make_shared();
+ auto decision_node = std::make_shared();
+
+ rclcpp::executors::MultiThreadedExecutor executor;
+ executor.add_node(sensor_node);
+ executor.add_node(processing_node);
+ executor.add_node(decision_node);
+
+ auto start_time = std::chrono::steady_clock::now();
+
+ while (rclcpp::ok() && (std::chrono::steady_clock::now() - start_time) < std::chrono::seconds(RUN_DURATION_SECONDS))
+ {
+ executor.spin_some();
+ std::this_thread::sleep_for(1ms);
+ }
+
+ rclcpp::shutdown();
+ return 0;
+}
diff --git a/src/tools/tracetools_analysis b/src/tools/tracetools_analysis
index e3591d1..00a3e8c 160000
--- a/src/tools/tracetools_analysis
+++ b/src/tools/tracetools_analysis
@@ -1 +1 @@
-Subproject commit e3591d1664af8159dde023f93751d4fbb7619542
+Subproject commit 00a3e8c3a6b67ce0dab01ef69e6abc42bb48bf10