#!/usr/bin/env bash # Сквозная проверка внутри контейнера: нода + проигрывание бэга + разбор вывода. # # docker run --rm --network host -v <бэги>:/data -v <репо>/docker:/smoke:ro flyguard \ # bash /smoke/demo_test.sh /data/doubleT_obstacle set -u # Управление заданиями: без него фоновые процессы неинтерактивного bash глухи к # SIGINT, и узел не гас по `kill -INT` — его добивал `kill -9`, без итога. set -m BAG="${1:?укажите путь к бэгу}" shift || true LAUNCH_ARGS=("$@") # NODE=external — узел уже запущен снаружи (другим контейнером, см. # jury_cpu_test.sh): здесь только проигрывание и подсчёт. LAUNCH_PID="" if [ "${NODE:-}" != "external" ]; then echo "=== запуск ноды ===" ros2 launch flyguard detect.launch.py "${LAUNCH_ARGS[@]}" > /tmp/node.log 2>&1 & LAUNCH_PID=$! echo "параметры: ${LAUNCH_ARGS[*]:-по умолчанию}" else : > /tmp/node.log fi for i in $(seq 1 30); do if ros2 topic list 2>/dev/null | grep -q '^/flyguard/obstacle$'; then echo "топик /flyguard/obstacle появился за ${i} с" break fi sleep 1 done # Видеокарта поднимается в фоне, и узел принимает кадры, не дожидаясь её. Для # замера скорости ждём её здесь, иначе первые кадры посчитает процессор: # решения те же, а время кадра смешается. WAIT_GPU=0 — не ждать, как на стенде. if [ "${WAIT_GPU:-1}" = 1 ] && grep -q "вычисления: пока процессор" /tmp/node.log 2>/dev/null; then for i in $(seq 1 90); do grep -qE "вычисления: (видеокарта|процессор \()|не поднялась" /tmp/node.log && break sleep 1 done GPU_STATE=$(grep -oE 'готова через [0-9.]+ с|не поднялась|CUDA недоступна' /tmp/node.log | head -1) echo "видеокарта: ${GPU_STATE:-нет ответа за 90 с}" fi # Счётчик на rclpy: `ros2 topic echo` сам не успевает за потоком и теряет # сообщения, из-за чего занижает оценку частоты. python3 - > /tmp/count.txt 2>/dev/null <<'PY' & import rclpy from rclpy.node import Node from flyguard_msgs.msg import ObstacleStatus from diagnostic_msgs.msg import DiagnosticArray class Counter(Node): def __init__(self): super().__init__("counter") self.n = self.hits = 0 self.dist, self.ms, self.diag = [], [], {} self.create_subscription(ObstacleStatus, "/flyguard/obstacle", self.on_obs, 50) self.create_subscription(DiagnosticArray, "/flyguard/diagnostics", self.on_diag, 50) def on_obs(self, m): self.n += 1 self.ms.append(m.processing_ms) if m.detected: self.hits += 1 self.dist.append(m.distance) def on_diag(self, m): for st in m.status: for kv in st.values: if kv.key in ("dropped_frames", "frames_processed", "frames_received", "frames_calibration", "cycle_ms"): self.diag[kv.key] = kv.value rclpy.init() c = Counter() try: rclpy.spin(c) except KeyboardInterrupt: pass finally: import statistics ms = sorted(c.ms) print(f"сообщений: {c.n}") if c.n: print(f"кадров с обнаружением: {c.hits} ({c.hits / c.n:.1%})") if c.dist: print(f"дистанция: медиана {statistics.median(c.dist):.1f} м, " f"мин {min(c.dist):.1f} м, макс {max(c.dist):.1f} м") if ms: print(f"обработка кадра: медиана {statistics.median(ms):.1f} мс, " f"p95 {ms[int(0.95 * (len(ms) - 1))]:.1f} мс, макс {max(ms):.1f} мс") print("по данным самой ноды: " + ", ".join(f"{k}={v}" for k, v in sorted(c.diag.items()))) PY COUNTER_PID=$! sleep 2 echo "=== проигрывание бэга ===" # read-ahead-queue-size: проигрыватель по умолчанию набивает очередь на 1000 # сообщений ДО старта. При кадре в 24 МБ это 24 ГБ, чтение занимает секунды, # а часы записи уже идут — всё, что за это время «просрочилось», не публикуется. PLAY_ARGS="${PLAY_ARGS:---read-ahead-queue-size 10}" echo "аргументы проигрывания: $PLAY_ARGS" T0=$(date +%s.%N) ros2 bag play $PLAY_ARGS "$BAG" 2>&1 | grep -Ei "duration|Opened database" | head -3 T1=$(date +%s.%N) awk -v a="$T0" -v b="$T1" 'BEGIN{printf "проиграно за %.1f с" ORS, b-a}' sleep 3 kill -INT $COUNTER_PID 2>/dev/null || true wait $COUNTER_PID 2>/dev/null || true # SIGINT, а не SIGTERM: так launch гасит и узел, а узел печатает итог. От # SIGTERM детектор переживал launch, и в check_all.sh узлы копились от записи # к записи, считая кадры соседей и отбирая у них процессор. `kill -9` ниже — # только страховка: с `set -m` узел гаснет за полсекунды. if [ -n "$LAUNCH_PID" ]; then kill -INT $LAUNCH_PID 2>/dev/null || true for i in $(seq 1 10); do pgrep -f "lib/flyguard/detector" >/dev/null || break; sleep 1; done pkill -9 -f "lib/flyguard/detector" 2>/dev/null || true wait $LAUNCH_PID 2>/dev/null || true fi echo echo "=== результат ===" cat /tmp/count.txt echo echo "=== журнал ноды ===" grep -Ei "вычисления|видеокарт|память|считывание|решётк|кадр лидара|подписка|итог|ошибк|error|traceback" /tmp/node.log | head -20 echo echo "=== что узел сказал в консоль ===" grep -E "ПРЕПЯТСТВИЕ|препятствие|ЭКСТРЕННОЕ|экстренное|путь свободен" /tmp/node.log | head -30