Skip to content

Commit 6057475

Browse files
committed
feat(turtlebot3): add anomaly_detector for direct fault reporting
- Add anomaly_detector.py that monitors navigation metrics and reports faults directly to FaultManager via /fault_manager/report_fault service - Monitors: navigation goal status (ABORTED/CANCELED), AMCL covariance, and robot progress - Remove inject-collision.sh and inject-controller-failure.sh as they produced redundant/unreliable faults - Simplify remaining inject scripts to rely on anomaly_detector - Update restore-normal.sh to remove lifecycle node reactivation - Add anomaly-detector to manifest (app + fault-management function) - Update README with new fault reporting architecture Fault codes: - NAVIGATION_GOAL_ABORTED: Navigation goal failed - NAVIGATION_GOAL_CANCELED: Navigation goal was canceled - LOCALIZATION_UNCERTAINTY: High AMCL covariance - NAVIGATION_NO_PROGRESS: Robot stuck during active goal
1 parent e231a5f commit 6057475

13 files changed

Lines changed: 437 additions & 156 deletions

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# selfpatch_demos
22

33
[![CI](https://github.com/selfpatch/selfpatch_demos/actions/workflows/ci.yml/badge.svg)](https://github.com/selfpatch/selfpatch_demos/actions/workflows/ci.yml)
4+
[![Docs](https://img.shields.io/badge/docs-GitHub%20Pages-blue)](https://selfpatch.github.io/ros2_medkit/)
5+
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
6+
[![Discord](https://img.shields.io/badge/Discord-Join%20Us-7289DA?logo=discord&logoColor=white)](https://discord.gg/fEbWKTah)
47

58
Demonstration projects showcasing [ros2_medkit](https://github.com/selfpatch/ros2_medkit) integration
69
with real ROS 2 systems.

demos/turtlebot3_integration/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,10 @@ install(DIRECTORY config/
1313
DESTINATION share/${PROJECT_NAME}/config
1414
)
1515

16+
# Install scripts
17+
install(PROGRAMS
18+
scripts/anomaly_detector.py
19+
DESTINATION lib/${PROJECT_NAME}
20+
)
21+
1622
ament_package()

demos/turtlebot3_integration/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ RUN git clone --depth 1 --recurse-submodules https://github.com/selfpatch/ros2_m
5959
COPY package.xml CMakeLists.txt ${COLCON_WS}/src/turtlebot3_medkit_demo/
6060
COPY config/ ${COLCON_WS}/src/turtlebot3_medkit_demo/config/
6161
COPY launch/ ${COLCON_WS}/src/turtlebot3_medkit_demo/launch/
62+
COPY scripts/ ${COLCON_WS}/src/turtlebot3_medkit_demo/scripts/
6263

6364
# Build ros2_medkit and demo package
6465
WORKDIR ${COLCON_WS}

demos/turtlebot3_integration/README.md

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -271,45 +271,67 @@ TurtleBot3 Demo (manifest-based discovery)
271271
│ ├── planner-server → component: nav2-stack
272272
│ ├── medkit-gateway → component: gateway
273273
│ ├── medkit-fault-manager → component: fault-manager
274-
│ └── diagnostic-bridge → component: diagnostic-bridge-unit
274+
│ ├── diagnostic-bridge → component: diagnostic-bridge-unit
275+
│ └── anomaly-detector → component: diagnostic-bridge-unit
275276
└── Functions (high-level capabilities)
276277
├── autonomous-navigation → hosted by: amcl, bt-navigator, ...
277278
├── robot-control → hosted by: turtlebot3-node, velocity-smoother
278-
└── fault-management → hosted by: gateway, fault-manager, bridge
279+
└── fault-management → hosted by: gateway, fault-manager, bridge, anomaly-detector
279280
```
280281

281282
### Fault Reporting
282283

283-
This demo uses the **legacy fault reporting path** via diagnostic_bridge:
284+
This demo uses two fault reporting paths:
285+
286+
1. **Direct Fault Reporting** via `anomaly_detector`:
287+
- Monitors navigation goal status, AMCL covariance, and robot progress
288+
- Reports faults directly to FaultManager via `/fault_manager/report_fault` service
289+
290+
2. **Legacy Path** via `diagnostic_bridge`:
291+
- Subscribes to `/diagnostics` topic (DiagnosticArray)
292+
- Converts diagnostics to fault reports
284293

285294
```
286-
Nav2/TurtleBot3 nodes → /diagnostics topic (DiagnosticArray)
287-
288-
diagnostic_bridge subscribes and converts
289-
290-
FaultManager receives via ReportFault service
291-
292-
Gateway exposes via GET /api/v1/faults
295+
┌─────────────────────────────────────────────────────────────────────┐
296+
│ Fault Reporting Paths │
297+
├─────────────────────────────────────────────────────────────────────┤
298+
│ │
299+
│ anomaly_detector ─────┬──── /fault_manager/report_fault ──────┐ │
300+
│ (monitors: │ (direct service call) │ │
301+
│ - nav goal status) │ │ │
302+
│ - AMCL covariance) │ ▼ │
303+
│ - robot progress) │ ┌──────────────┐
304+
│ │ │ FaultManager │
305+
│ │ └──────┬───────┘
306+
│ Nav2/TurtleBot3 ──────┼──── /diagnostics topic ──────┐ │ │
307+
│ (DiagnosticArray) │ ▼ │ │
308+
│ │ diagnostic_bridge │ │
309+
│ └───────────────────────────────┘ │ │
310+
│ ▼ │
311+
│ GET /api/v1/faults │
312+
└─────────────────────────────────────────────────────────────────────┘
293313
```
294314

295315
| Source | Fault Reporter | Example Faults |
296316
|--------|----------------|----------------|
317+
| Navigation Goals | anomaly_detector | `NAVIGATION_GOAL_ABORTED`, `NAVIGATION_GOAL_CANCELED` |
318+
| Localization | anomaly_detector | `LOCALIZATION_UNCERTAINTY` |
319+
| Robot Progress | anomaly_detector | `NAVIGATION_NO_PROGRESS` |
297320
| AMCL | diagnostic_bridge | Localization degraded |
298321
| Nav2 Controller | diagnostic_bridge | Path following errors |
299322
| TurtleBot3 | diagnostic_bridge | Motor/sensor issues |
300323

301324
## Fault Injection Scenarios
302325

303-
This demo includes scripts to inject various fault conditions for testing fault management:
326+
This demo includes scripts to inject various fault conditions for testing fault management.
327+
Faults are detected by `anomaly_detector` and reported directly to FaultManager.
304328

305329
### Available Fault Scenarios
306330

307331
| Script | Fault Type | Description | Expected Faults |
308332
|--------|-----------|-------------|-----------------|
309-
| `inject-nav-failure.sh` | Navigation | Send goal to unreachable location | BT_NAVIGATOR, PLANNER_SERVER |
310-
| `inject-localization-failure.sh` | Localization | Reset AMCL with high uncertainty | AMCL |
311-
| `inject-controller-failure.sh` | Controller | Set very restrictive velocity limits | VELOCITY_SMOOTHER, CONTROLLER_SERVER |
312-
| `inject-collision.sh` | Collision | Navigate toward obstacles | COLLISION_MONITOR |
333+
| `inject-nav-failure.sh` | Navigation | Send goal to unreachable location | `NAVIGATION_GOAL_ABORTED` |
334+
| `inject-localization-failure.sh` | Localization | Reset AMCL with high uncertainty | `LOCALIZATION_UNCERTAINTY` |
313335
| `restore-normal.sh` | Recovery | Restore defaults and clear faults | - |
314336

315337
### Fault Injection Examples
@@ -321,7 +343,7 @@ This demo includes scripts to inject various fault conditions for testing fault
321343
./inject-nav-failure.sh
322344

323345
# Check resulting faults
324-
curl http://localhost:8080/api/v1/faults | jq '.items[] | {code, severity, message}'
346+
curl http://localhost:8080/api/v1/faults | jq '.items[] | {fault_code, severity_label, description}'
325347
```
326348

327349
#### 2. Localization Failure
@@ -330,27 +352,7 @@ curl http://localhost:8080/api/v1/faults | jq '.items[] | {code, severity, messa
330352
# Reinitialize AMCL global localization (causes high uncertainty)
331353
./inject-localization-failure.sh
332354

333-
# Watch localization recover
334-
curl http://localhost:8080/api/v1/apps/amcl/data/particlecloud | jq '.poses | length'
335-
```
336-
337-
#### 3. Controller Restriction
338-
339-
```bash
340-
# Set very low velocity limits (robot moves extremely slowly)
341-
./inject-controller-failure.sh
342-
343-
# Try sending a navigation goal - robot will struggle to follow path
344-
./send-nav-goal.sh 2.0 0.5
345-
```
346-
347-
#### 4. Collision Scenario
348-
349-
```bash
350-
# Trigger collision avoidance
351-
./inject-collision.sh
352-
353-
# Monitor collision warnings
355+
# Watch for LOCALIZATION_UNCERTAINTY fault
354356
curl http://localhost:8080/api/v1/faults | jq
355357
```
356358

@@ -429,16 +431,16 @@ demos/turtlebot3_integration/
429431
├── check-faults.sh # View active faults
430432
├── inject-nav-failure.sh # Inject navigation failure scenario
431433
├── inject-localization-failure.sh # Inject AMCL localization issues
432-
├── inject-controller-failure.sh # Inject controller velocity limits
433-
├── inject-collision.sh # Inject collision warning scenario
434434
├── restore-normal.sh # Restore normal operation
435435
├── config/
436436
│ ├── medkit_params.yaml # ros2_medkit gateway config
437437
│ ├── turtlebot3_manifest.yaml # SOVD manifest (entity hierarchy)
438438
│ ├── nav2_params.yaml # Nav2 navigation parameters
439439
│ └── turtlebot3_world.yaml # Map configuration
440-
└── launch/
441-
└── demo.launch.py # ROS 2 launch file
440+
├── launch/
441+
│ └── demo.launch.py # ROS 2 launch file
442+
└── scripts/
443+
└── anomaly_detector.py # Navigation anomaly detector node
442444
```
443445

444446
## Scripts
@@ -452,8 +454,6 @@ demos/turtlebot3_integration/
452454
| `check-faults.sh` | View active faults from gateway |
453455
| `inject-nav-failure.sh` | Inject navigation failure (unreachable goal) |
454456
| `inject-localization-failure.sh` | Inject localization failure (AMCL reset) |
455-
| `inject-controller-failure.sh` | Inject controller failure (velocity limits) |
456-
| `inject-collision.sh` | Inject collision warning scenario |
457457
| `restore-normal.sh` | Restore normal operation and clear faults |
458458

459459
## Manual Setup (Alternative)

demos/turtlebot3_integration/config/turtlebot3_manifest.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,18 @@ apps:
183183
node_name: diagnostic_bridge
184184
namespace: /bridge
185185

186+
- id: anomaly-detector
187+
name: "Anomaly Detector"
188+
category: "diagnostics"
189+
is_located_on: diagnostic-bridge-unit
190+
description: "Monitors navigation metrics and reports faults directly to FaultManager"
191+
depends_on:
192+
- amcl
193+
- bt-navigator
194+
ros_binding:
195+
node_name: anomaly_detector
196+
namespace: /bridge
197+
186198
# =============================================================================
187199
# FUNCTIONS - High-level capabilities
188200
# =============================================================================
@@ -213,3 +225,4 @@ functions:
213225
- medkit-gateway
214226
- medkit-fault-manager
215227
- diagnostic-bridge
228+
- anomaly-detector

demos/turtlebot3_integration/inject-collision.sh

Lines changed: 0 additions & 52 deletions
This file was deleted.

demos/turtlebot3_integration/inject-controller-failure.sh

Lines changed: 0 additions & 41 deletions
This file was deleted.

demos/turtlebot3_integration/inject-localization-failure.sh

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,30 @@ curl -s -X POST "${API_BASE}/apps/amcl/operations/reinitialize_global_localizati
2222
-d '{}'
2323

2424
echo ""
25-
echo "✓ Localization failure injected!"
25+
echo "Waiting for particles to scatter..."
26+
sleep 2
27+
28+
# Now try to navigate - with scattered particles, localization uncertainty is high
29+
echo "Sending navigation goal (with high localization uncertainty)..."
30+
curl -s -X POST "${API_BASE}/apps/bt-navigator/operations/navigate_to_pose/executions" \
31+
-H "Content-Type: application/json" \
32+
-d '{
33+
"goal": {
34+
"pose": {
35+
"header": {"frame_id": "map"},
36+
"pose": {
37+
"position": {"x": 2.0, "y": 0.0, "z": 0.0},
38+
"orientation": {"w": 1.0}
39+
}
40+
}
41+
}
42+
}' | jq '.' 2>/dev/null || true
43+
2644
echo ""
27-
echo "AMCL will now have high uncertainty until it re-localizes."
28-
echo "Expected faults (via diagnostic_bridge):"
29-
echo " - AMCL: Localization confidence low"
30-
echo " - BT_NAVIGATOR: Goal may fail due to uncertain pose"
45+
echo "✓ Localization failure injected!"
3146
echo ""
32-
echo "Watch localization recover with:"
33-
echo " curl ${API_BASE}/apps/amcl/data/particlecloud | jq '.poses | length'"
47+
echo "AMCL has been reinitialized - localization uncertainty is high."
48+
echo "The anomaly_detector monitors AMCL covariance and will report:"
49+
echo " - LOCALIZATION_UNCERTAINTY: High AMCL covariance (uncertainty)"
3450
echo ""
3551
echo "Check faults with: curl ${API_BASE}/faults | jq"

demos/turtlebot3_integration/inject-nav-failure.sh

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ echo "Sending navigation goal to (100.0, 100.0) - far outside map..."
2727
RESPONSE=$(curl -s -X POST "${API_BASE}/apps/bt-navigator/operations/navigate_to_pose/executions" \
2828
-H "Content-Type: application/json" \
2929
-d '{
30-
"request": {
30+
"goal": {
3131
"pose": {
3232
"header": {"frame_id": "map"},
3333
"pose": {
@@ -40,11 +40,26 @@ RESPONSE=$(curl -s -X POST "${API_BASE}/apps/bt-navigator/operations/navigate_to
4040

4141
echo "$RESPONSE" | jq '.' 2>/dev/null || echo "$RESPONSE"
4242

43+
# Extract execution ID
44+
EXEC_ID=$(echo "$RESPONSE" | jq -r '.id' 2>/dev/null)
45+
46+
if [ -n "$EXEC_ID" ] && [ "$EXEC_ID" != "null" ]; then
47+
echo ""
48+
echo "Waiting for navigation to fail (checking status)..."
49+
for i in {1..10}; do
50+
sleep 2
51+
STATUS=$(curl -s "${API_BASE}/apps/bt-navigator/operations/navigate_to_pose/executions/${EXEC_ID}" | jq -r '.status' 2>/dev/null)
52+
echo " Status: $STATUS"
53+
if [ "$STATUS" = "failed" ] || [ "$STATUS" = "completed" ]; then
54+
break
55+
fi
56+
done
57+
fi
58+
4359
echo ""
4460
echo "✓ Navigation failure injected!"
4561
echo ""
46-
echo "Expected faults (via diagnostic_bridge):"
47-
echo " - BT_NAVIGATOR: Goal rejected or path planning failed"
48-
echo " - PLANNER_SERVER: No valid path to goal"
62+
echo "Expected faults (via anomaly_detector → FaultManager):"
63+
echo " - NAVIGATION_GOAL_ABORTED: Navigation goal ABORTED"
4964
echo ""
5065
echo "Check faults with: curl ${API_BASE}/faults | jq"

demos/turtlebot3_integration/launch/demo.launch.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,5 +165,19 @@ def generate_launch_description():
165165
},
166166
],
167167
),
168+
# Launch anomaly detector to monitor navigation and publish diagnostics
169+
Node(
170+
package="turtlebot3_medkit_demo",
171+
executable="anomaly_detector.py",
172+
name="anomaly_detector",
173+
namespace="bridge",
174+
output="screen",
175+
parameters=[
176+
{"use_sim_time": use_sim_time},
177+
{"covariance_warn_threshold": 0.3},
178+
{"covariance_error_threshold": 1.0},
179+
{"no_progress_timeout_sec": 20.0},
180+
],
181+
),
168182
]
169183
)

0 commit comments

Comments
 (0)