Skip to content

Commit a808ce4

Browse files
committed
feat(sensor-demo): add snapshot and rosbag recording support
Add fault_manager configuration to sensor_diagnostics demo with: - SQLite storage for fault persistence - Freeze-frame snapshot capture on fault confirmation - MCAP rosbag recording with ring buffer (10s pre + 2s post fault) - Sensor topics included: /sensors/scan, imu, fix, image_raw Infrastructure changes: - Pass medkit_params to fault_manager node in launch file - Create /var/lib/ros2_medkit/rosbags dir in Dockerfile - Add sqlite3 package to Dockerfile - Add persistent medkit_data volume to docker-compose - Add bulk-data/snapshot demo steps to check-demo.sh
1 parent c843ded commit a808ce4

5 files changed

Lines changed: 108 additions & 5 deletions

File tree

demos/sensor_diagnostics/Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y \
1616
python3-requests \
1717
nlohmann-json3-dev \
1818
libcpp-httplib-dev \
19+
sqlite3 \
1920
libsqlite3-dev \
2021
git \
2122
curl \
@@ -48,6 +49,9 @@ RUN bash -c "source /opt/ros/jazzy/setup.bash && \
4849
--skip-keys='ament_cmake_clang_format ament_cmake_clang_tidy test_msgs example_interfaces sqlite3' && \
4950
colcon build --symlink-install --cmake-args -DBUILD_TESTING=OFF"
5051

52+
# Create storage directories for faults and rosbags
53+
RUN mkdir -p /var/lib/ros2_medkit/rosbags
54+
5155
# Setup environment
5256
RUN echo "source /opt/ros/jazzy/setup.bash" >> ~/.bashrc && \
5357
echo "source ${COLCON_WS}/install/setup.bash" >> ~/.bashrc

demos/sensor_diagnostics/check-demo.sh

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,42 @@ curl -s "${API_BASE}/apps/lidar-sim/configurations" | jq '.items[] | {name: .nam
9090
echo_step "9. Checking Current Faults"
9191
curl -s "${API_BASE}/faults" | jq '.'
9292

93+
# If there are faults, demonstrate snapshot / bulk-data endpoints
94+
FAULT_COUNT=$(curl -s "${API_BASE}/faults" | jq '.items | length')
95+
if [ "$FAULT_COUNT" -gt 0 ]; then
96+
FIRST_FAULT=$(curl -s "${API_BASE}/faults" | jq -r '.items[0].code')
97+
FIRST_ENTITY=$(curl -s "${API_BASE}/faults" | jq -r '.items[0].entity_id')
98+
99+
echo_step "10. Fault Detail with Environment Data (Snapshots)"
100+
echo "Fetching fault ${FIRST_FAULT} on entity ${FIRST_ENTITY}..."
101+
curl -s "${API_BASE}/${FIRST_ENTITY}/faults/${FIRST_FAULT}" | jq '{
102+
code: .item.code,
103+
status: .item.status,
104+
environment_data: {
105+
extended_data_records: .environment_data.extended_data_records,
106+
snapshot_count: (.environment_data.snapshots | length)
107+
}
108+
}'
109+
110+
echo_step "11. Bulk-Data Categories (Rosbag Recordings)"
111+
echo "Checking available bulk-data categories..."
112+
curl -s "${API_BASE}/${FIRST_ENTITY}/bulk-data" | jq '.'
113+
114+
echo_step "12. Bulk-Data Descriptors (Rosbag Files)"
115+
echo "Listing available rosbag recordings..."
116+
curl -s "${API_BASE}/${FIRST_ENTITY}/bulk-data/rosbags" | jq '.items[] | {
117+
id: .id,
118+
name: .name,
119+
size: .size,
120+
mimetype: .mimetype,
121+
"x-medkit": ."x-medkit"
122+
}'
123+
else
124+
echo ""
125+
echo " No active faults. Inject a fault first to see snapshot/bulk-data features:"
126+
echo " ./inject-noise.sh && sleep 5 && bash $0"
127+
fi
128+
93129
echo ""
94130
echo_success "API demonstration complete!"
95131
echo ""
@@ -100,9 +136,10 @@ echo " ./inject-nan.sh # Inject NaN values"
100136
echo " ./inject-drift.sh # Inject sensor drift"
101137
echo " ./restore-normal.sh # Restore normal operation"
102138
echo ""
139+
echo "📸 After injecting a fault, check snapshots and rosbags:"
140+
echo " curl ${API_BASE}/faults | jq # List faults"
141+
echo " curl ${API_BASE}/components/lidar-unit/faults/<CODE> | jq # Fault detail + snapshots"
142+
echo " curl ${API_BASE}/components/lidar-unit/bulk-data/rosbags | jq # List rosbag recordings"
143+
echo ""
103144
echo "🌐 Web UI: http://localhost:3000"
104145
echo "🌐 REST API: http://localhost:8080/api/v1/"
105-
echo ""
106-
echo "📖 More examples:"
107-
echo " curl ${API_BASE}/apps/imu-sim/configurations | jq # IMU parameters"
108-
echo " curl ${API_BASE}/apps/gps-sim/data/fix | jq # GPS data"

demos/sensor_diagnostics/config/medkit_params.yaml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,55 @@ diagnostics:
2626
discovery:
2727
runtime:
2828
create_synthetic_components: false # Manifest defines components
29+
30+
# Fault Manager configuration (runs in root namespace)
31+
fault_manager:
32+
ros__parameters:
33+
# Storage configuration
34+
storage_type: "sqlite"
35+
database_path: "/var/lib/ros2_medkit/faults.db"
36+
37+
# Debounce configuration
38+
confirmation_threshold: 0 # Immediate confirmation
39+
healing_enabled: false
40+
healing_threshold: 3
41+
auto_confirm_after_sec: 0.0
42+
43+
# Snapshot configuration (freeze frames)
44+
snapshots:
45+
enabled: true
46+
background_capture: true # Non-blocking capture
47+
timeout_sec: 2.0
48+
max_message_size: 131072 # 128KB max per message
49+
50+
# Topics to capture for all faults
51+
default_topics:
52+
- /sensors/scan
53+
- /sensors/imu
54+
- /sensors/fix
55+
- /sensors/image_raw
56+
- /diagnostics
57+
58+
# Rosbag recording configuration
59+
rosbag:
60+
enabled: true
61+
duration_sec: 10.0 # Record 10 seconds before fault confirmation
62+
duration_after_sec: 2.0 # Record 2 seconds after confirmation
63+
lazy_start: false # Always recording (ring buffer)
64+
format: "mcap" # MCAP format (recommended for cross-platform)
65+
storage_path: "/var/lib/ros2_medkit/rosbags"
66+
max_bag_size_mb: 100 # Max size per rosbag file
67+
max_total_storage_mb: 1000 # 1GB total storage limit
68+
auto_cleanup: true # Cleanup rosbags on fault clear
69+
70+
# Topics to record (use 'config' or 'all')
71+
topics: "config" # Use include/exclude lists below
72+
include_topics:
73+
- /sensors/scan
74+
- /sensors/imu
75+
- /sensors/fix
76+
- /sensors/image_raw
77+
- /diagnostics
78+
exclude_topics:
79+
- /rosout
80+
- /parameter_events

demos/sensor_diagnostics/docker-compose.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ services:
77
container_name: sensor_diagnostics_demo
88
environment:
99
- ROS_DOMAIN_ID=40
10+
volumes:
11+
- medkit_data:/var/lib/ros2_medkit # Persistent storage for faults and rosbags
1012
ports:
1113
- "8080:8080"
1214
stdin_open: true
@@ -46,3 +48,7 @@ services:
4648
curl -sf http://localhost:8080/api/v1/health &&
4749
curl -sf http://localhost:8080/api/v1/apps | jq '.items[] | .id' &&
4850
echo 'CI validation passed!'"
51+
52+
volumes:
53+
medkit_data:
54+
name: sensor_diagnostics_medkit_data

demos/sensor_diagnostics/launch/demo.launch.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,13 +125,17 @@ def generate_launch_description():
125125
# ===== Fault Manager (at root namespace) =====
126126
# Services at /fault_manager/* (e.g., /fault_manager/report_fault)
127127
# Both paths report here: diagnostic_bridge (legacy) and anomaly_detector (modern)
128+
# Also handles snapshot and rosbag capture when faults are confirmed
128129
Node(
129130
package="ros2_medkit_fault_manager",
130131
executable="fault_manager_node",
131132
name="fault_manager",
132133
namespace="", # Root namespace so services are at /fault_manager/*
133134
output="screen",
134-
parameters=[{"use_sim_time": use_sim_time}],
135+
parameters=[
136+
medkit_params_file,
137+
{"use_sim_time": use_sim_time},
138+
],
135139
),
136140
]
137141
)

0 commit comments

Comments
 (0)