From ae3f01fbdc4c16f165719c8a9a9b24991db2a499 Mon Sep 17 00:00:00 2001 From: Shiyang-Zhao Date: Sun, 27 Apr 2025 05:14:06 -0500 Subject: [PATCH] Integrate with log_dashboard and add visualization of traffic lights and other vehicles --- .../visualization/sr_viz/threeD/.gitignore | 35 +- .../sr_viz/threeD/legacy/package-lock.json | 5 + .../sr_viz/threeD/legacy/package.json | 1 + ...{traffic_light_1.glb => traffic_light.glb} | Bin .../threeD/public/models/traffic_light_2.glb | Bin 234384 -> 0 bytes .../sr_viz/threeD/src/app/page.tsx | 30 +- .../sr_viz/threeD/src/components/Agent.tsx | 26 +- .../threeD/src/components/CanvasWrapper.tsx | 86 +-- .../threeD/src/components/ControlPanel.tsx | 55 +- .../threeD/src/components/OtherVehicle.tsx | 77 +++ .../threeD/src/components/TrafficLight.tsx | 60 ++ .../sr_viz/threeD/src/components/Vehicle.tsx | 2 +- .../sr_viz/threeD/src/config/cameraConfig.ts | 4 +- .../threeD/src/config/otherVehicleConfig.ts | 14 + .../threeD/src/config/trafficLightConfig.ts | 14 + .../sr_viz/threeD/src/config/vehicleConfig.ts | 24 +- .../threeD/src/hooks/useTimelineStore.ts | 2 + .../threeD/src/hooks/useVehicleControls.ts | 2 +- .../sr_viz/threeD/src/types/TimelineData.ts | 2 + .../sr_viz/threeD/src/utils/buildTimeline.ts | 14 +- .../sr_viz/threeD/src/utils/parseLogFile.ts | 37 +- log_dashboard/README.md | 18 + log_dashboard/app.py | 579 ++++++++++++++++++ log_dashboard/plots/.gitignore | 5 + log_dashboard/plots/sample_plot.png | Bin 0 -> 142686 bytes log_dashboard/requirements.txt | 5 + log_dashboard/templates/index.html | 102 +++ log_dashboard/templates/render.html | 75 +++ log_dashboard/templates/view_log.html | 389 ++++++++++++ 29 files changed, 1539 insertions(+), 124 deletions(-) rename GEMstack/onboard/visualization/sr_viz/threeD/public/models/{traffic_light_1.glb => traffic_light.glb} (100%) delete mode 100644 GEMstack/onboard/visualization/sr_viz/threeD/public/models/traffic_light_2.glb create mode 100644 GEMstack/onboard/visualization/sr_viz/threeD/src/components/OtherVehicle.tsx create mode 100644 GEMstack/onboard/visualization/sr_viz/threeD/src/components/TrafficLight.tsx create mode 100644 GEMstack/onboard/visualization/sr_viz/threeD/src/config/otherVehicleConfig.ts create mode 100644 GEMstack/onboard/visualization/sr_viz/threeD/src/config/trafficLightConfig.ts create mode 100644 log_dashboard/README.md create mode 100644 log_dashboard/app.py create mode 100644 log_dashboard/plots/.gitignore create mode 100644 log_dashboard/plots/sample_plot.png create mode 100644 log_dashboard/requirements.txt create mode 100644 log_dashboard/templates/index.html create mode 100644 log_dashboard/templates/render.html create mode 100644 log_dashboard/templates/view_log.html diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/.gitignore b/GEMstack/onboard/visualization/sr_viz/threeD/.gitignore index 4a7f73a2e..d1a1a9338 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/.gitignore +++ b/GEMstack/onboard/visualization/sr_viz/threeD/.gitignore @@ -1,24 +1,19 @@ -# Nuxt dev/build outputs -.output -.data -.nuxt -.nitro -.cache -dist +# Node.js / Next.js +node_modules/ +.next/ +out/ -# Node dependencies -node_modules +# Python / Flask +__pycache__/ +*.pyc +.venv/ +venv/ -# Logs -logs -*.log - -# Misc -.DS_Store -.fleet -.idea - -# Local env files +# Environment files .env .env.* -!.env.example + +# OS and editor files +.DS_Store +.idea/ +.vscode/ diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/legacy/package-lock.json b/GEMstack/onboard/visualization/sr_viz/threeD/legacy/package-lock.json index 5b16ff0f0..92d191e46 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/legacy/package-lock.json +++ b/GEMstack/onboard/visualization/sr_viz/threeD/legacy/package-lock.json @@ -8,6 +8,7 @@ "hasInstallScript": true, "dependencies": { "nuxt": "^3.16.1", + "nuxt-app": "file:", "three": "^0.174.0", "urdf-loader": "^0.12.4", "vue": "^3.5.13", @@ -7088,6 +7089,10 @@ } } }, + "node_modules/nuxt-app": { + "resolved": "", + "link": true + }, "node_modules/nypm": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.0.tgz", diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/legacy/package.json b/GEMstack/onboard/visualization/sr_viz/threeD/legacy/package.json index 8f0c27838..f0b32f728 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/legacy/package.json +++ b/GEMstack/onboard/visualization/sr_viz/threeD/legacy/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "nuxt": "^3.16.1", + "nuxt-app": "file:", "three": "^0.174.0", "urdf-loader": "^0.12.4", "vue": "^3.5.13", diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/public/models/traffic_light_1.glb b/GEMstack/onboard/visualization/sr_viz/threeD/public/models/traffic_light.glb similarity index 100% rename from GEMstack/onboard/visualization/sr_viz/threeD/public/models/traffic_light_1.glb rename to GEMstack/onboard/visualization/sr_viz/threeD/public/models/traffic_light.glb diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/public/models/traffic_light_2.glb b/GEMstack/onboard/visualization/sr_viz/threeD/public/models/traffic_light_2.glb deleted file mode 100644 index 47161ae232c2050ddfb5539091362bf16d8b98de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 234384 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 diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/app/page.tsx b/GEMstack/onboard/visualization/sr_viz/threeD/src/app/page.tsx index 9cc8d24b5..a680a011b 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/src/app/page.tsx +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/app/page.tsx @@ -1,18 +1,40 @@ "use client"; +import { useSearchParams } from "next/navigation"; import ControlPanel from "@/components/ControlPanel"; import CanvasWrapper from "@/components/CanvasWrapper"; import Scrubber from "@/components/Scrubber"; import { usePlaybackTime } from "@/hooks/usePlaybackTime"; export default function HomePage() { - const { time, reset, restart, play, togglePlay, speed, setPlaybackSpeed, moveToTime, duration, setDuration } = usePlaybackTime(); - + const { + time, + reset, + restart, + play, + togglePlay, + speed, + setPlaybackSpeed, + moveToTime, + duration, + setDuration, + } = usePlaybackTime(); + const searchParams = useSearchParams(); + const folder = searchParams.get("folder") || undefined; + const file = searchParams.get("file") || undefined; return (
- + - +
); } diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/components/Agent.tsx b/GEMstack/onboard/visualization/sr_viz/threeD/src/components/Agent.tsx index 2525cc54c..b4fd99a5a 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/src/components/Agent.tsx +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/components/Agent.tsx @@ -1,6 +1,6 @@ "use client"; -import { useRef, useMemo, useEffect } from "react"; +import { useRef, useMemo, useEffect, useState } from "react"; import { useFrame } from "@react-three/fiber"; import { Mesh, Object3D, MeshStandardMaterial } from "three"; import { useGLTF } from "@react-three/drei"; @@ -14,13 +14,17 @@ interface AgentProps { } export default function Agent({ id, timeline, time }: AgentProps) { - const ref = useRef(null); + const [mounted, setMounted] = useState(false); + const ref = useRef(null); const { modelPath, scale, rotation, offset, bodyColor } = currentAgent; - const { scene } = useGLTF(modelPath); const clonedScene = useMemo(() => scene.clone(true), [scene]); + useEffect(() => { + setMounted(true); + }, []); + useEffect(() => { clonedScene.traverse((child) => { if ( @@ -34,19 +38,21 @@ export default function Agent({ id, timeline, time }: AgentProps) { }, [clonedScene, bodyColor]); useFrame(() => { - const frame = timeline.find((f) => f.time >= time); - if (frame && ref.current) { - ref.current.position.set(frame.x, 0, frame.y); - ref.current.rotation.y = -frame.yaw; - } + if (!ref.current || timeline.length === 0) return; + + const frame = timeline.find((f) => f.time >= time) ?? timeline.at(-1); + if (!frame) return; + + ref.current.position.set(frame.x, 0, frame.y); + ref.current.rotation.y = -frame.yaw; }); const hasSpawned = timeline.length > 0 && timeline[0].time <= time; - if (!hasSpawned) return null; + if (!mounted || !hasSpawned) return null; return ( } + ref={ref as React.RefObject} object={clonedScene} scale={scale} rotation={rotation} diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/components/CanvasWrapper.tsx b/GEMstack/onboard/visualization/sr_viz/threeD/src/components/CanvasWrapper.tsx index 91d8d2803..6a6c920dd 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/src/components/CanvasWrapper.tsx +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/components/CanvasWrapper.tsx @@ -6,47 +6,57 @@ import { Environment } from "@react-three/drei"; import { useTimelineStore } from "@/hooks/useTimelineStore"; import Vehicle from "./Vehicle"; import Agent from "./Agent"; +import TrafficLight from "./TrafficLight"; +import OtherVehicle from "./OtherVehicle"; import Ground from "./Ground"; export default function CanvasWrapper({ - time, - setDuration, + time, + setDuration, }: { - time: number; - setDuration: (duration: number) => void; + time: number; + setDuration: (duration: number) => void; }) { - const { vehicle, agents } = useTimelineStore(); - useEffect(() => { - if (vehicle.length > 0) { - setDuration(vehicle[vehicle.length - 1].time - vehicle[0].time); - } - }, [vehicle]); - const startTime = vehicle.length > 0 ? vehicle[0].time : 0; - const syncedTime = startTime + time; - - return ( - - - - - - {Object.entries(agents).map(([id, timeline]) => ( - - ))} - - - ); + const { vehicle, agents, trafficLights, otherVehicles } = useTimelineStore(); + + useEffect(() => { + if (vehicle.length > 0) { + setDuration(vehicle[vehicle.length - 1].time - vehicle[0].time); + } + }, [vehicle]); + + const startTime = vehicle.length > 0 ? vehicle[0].time : 0; + const syncedTime = startTime + time; + + return ( + + + + + + + {Object.entries(agents).map(([id, timeline]) => ( + + ))} + + {Object.entries(trafficLights).map(([id, timeline]) => ( + + ))} + + {Object.entries(otherVehicles).map(([id, timeline]) => ( + + ))} + + + + ); } diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/components/ControlPanel.tsx b/GEMstack/onboard/visualization/sr_viz/threeD/src/components/ControlPanel.tsx index c2b62df99..e8eeb3450 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/src/components/ControlPanel.tsx +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/components/ControlPanel.tsx @@ -1,6 +1,6 @@ "use client"; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { TiUpload } from "react-icons/ti"; import { RxCross2 } from "react-icons/rx"; import { buildTimeline } from "@/utils/buildTimeline"; @@ -8,7 +8,15 @@ import { parseLogFile } from "@/utils/parseLogFile"; import { useTimelineStore } from "@/hooks/useTimelineStore"; import { TimelineData } from "@/types/TimelineData"; -export default function ControlPanel({ reset }: { reset: () => void }) { +export default function ControlPanel({ + reset, + folder, + file, +}: { + reset: () => void; + folder?: string; + file?: string; +}) { const [isOpen, setIsOpen] = useState(false); const [fileName, setFileName] = useState(null); const setTimeline = useTimelineStore((state) => state.setTimeline); @@ -25,13 +33,48 @@ export default function ControlPanel({ reset }: { reset: () => void }) { const entries = await parseLogFile(file); const timeline: TimelineData = buildTimeline(entries); setTimeline(timeline); - reset(); // ⏪ Restart animation time - console.log("✅ timeline loaded:", timeline); + reset(); + console.log("timeline loaded:", timeline); } catch (err) { - console.error("❌ Failed to parse log file:", err); + console.error("Failed to parse log file:", err); } }; + useEffect(() => { + if (!folder || !file) return; + + const fetchLog = async () => { + const url = `http://localhost:5000/raw_logs/${encodeURIComponent( + folder + )}/${encodeURIComponent(file)}`; + + try { + const res = await fetch(url); + if (!res.ok) { + throw new Error( + `Failed to fetch ${file} from ${url} (status ${res.status})` + ); + } + + const text = await res.text(); + const fakeFile = new File([text], file, { type: "text/plain" }); + + const entries = await parseLogFile(fakeFile); + const timeline = buildTimeline(entries); + + setTimeline(timeline); + reset(); + setFileName(file); + + console.log("[✔] Timeline loaded from Flask API:", timeline); + } catch (err) { + console.error("[✘] Failed to load remote log file:", err); + } + }; + + fetchLog(); + }, [folder, file]); + return ( <>
void }) { />

- {fileName ? `✅ ${fileName}` : "No file loaded"} + {fileName ? `${fileName}` : "No file loaded"}

diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/components/OtherVehicle.tsx b/GEMstack/onboard/visualization/sr_viz/threeD/src/components/OtherVehicle.tsx new file mode 100644 index 000000000..cf9b3658d --- /dev/null +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/components/OtherVehicle.tsx @@ -0,0 +1,77 @@ +"use client"; + +import { useRef, useMemo, useEffect, useState } from "react"; +import { useFrame } from "@react-three/fiber"; +import * as THREE from "three"; +import { FrameData } from "@/types/FrameData"; +import { currentOtherVehicle } from "@/config/otherVehicleConfig"; +import URDFLoader from "urdf-loader"; + +interface OtherVehicleProps { + id: string; + timeline: FrameData[]; + time: number; +} + +export default function OtherVehicle({ id, timeline, time }: OtherVehicleProps) { + const ref = useRef(null); + const vehicleGroup = useRef(new THREE.Group()); + const [isLoaded, setIsLoaded] = useState(false); + + const targetPosition = useMemo(() => new THREE.Vector3(), []); + const targetQuaternion = useMemo(() => new THREE.Quaternion(), []); + + const { modelPath, scale, rotation, offset, bodyColor } = currentOtherVehicle; + + useEffect(() => { + const loader = new URDFLoader(); + + loader.load( + modelPath, + (robot) => { + robot.scale.set(scale[0], scale[1], scale[2]); + robot.rotation.set(rotation[0], rotation[1], rotation[2]); + robot.position.set(offset[0], offset[1], offset[2]); + + robot.traverse((child) => { + if (child instanceof THREE.Mesh && child.material instanceof THREE.MeshStandardMaterial) { + child.material = child.material.clone(); + child.material.color.set(bodyColor); + } + }); + + if (vehicleGroup.current) { + vehicleGroup.current.add(robot); + } + + setIsLoaded(true); + }, + undefined, + (error) => { + console.error("URDF loading failed:", error); + } + ); + }, [modelPath, scale, rotation, offset, bodyColor]); + + useFrame(() => { + if (!ref.current || timeline.length === 0) return; + + const frame = timeline.find((f) => f.time >= time) ?? timeline.at(-1); + if (!frame) return; + + targetPosition.set(frame.x, 0, frame.y); + ref.current.position.lerp(targetPosition, 0.2); + + targetQuaternion.setFromEuler(new THREE.Euler(0, -frame.yaw, 0)); + ref.current.quaternion.slerp(targetQuaternion, 0.2); + }); + + const hasSpawned = timeline.length > 0 && timeline[0].time <= time; + if (!isLoaded || !hasSpawned) return null; + + return ( + + + + ); +} diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/components/TrafficLight.tsx b/GEMstack/onboard/visualization/sr_viz/threeD/src/components/TrafficLight.tsx new file mode 100644 index 000000000..5ccced058 --- /dev/null +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/components/TrafficLight.tsx @@ -0,0 +1,60 @@ +"use client"; + +import { useRef, useMemo, useEffect, useState } from "react"; +import { useFrame } from "@react-three/fiber"; +import { Mesh, Object3D, MeshStandardMaterial } from "three"; +import { useGLTF } from "@react-three/drei"; +import { FrameData } from "@/types/FrameData"; +import { currentTrafficLight } from "@/config/trafficLightConfig"; + +interface TrafficLightProps { + id: string; + timeline: FrameData[]; + time: number; +} + +export default function TrafficLight({ id, timeline, time }: TrafficLightProps) { + const [mounted, setMounted] = useState(false); + + const ref = useRef(null); + const { modelPath, scale, rotation, offset, bodyColor } = currentTrafficLight; + const { scene } = useGLTF(modelPath); + const clonedScene = useMemo(() => scene.clone(true), [scene]); + + useEffect(() => { + setMounted(true); + }, []); + + useEffect(() => { + clonedScene.traverse((child) => { + if ( + child instanceof Mesh && + child.material instanceof MeshStandardMaterial + ) { + child.material = child.material.clone(); + child.material.color.set(bodyColor); + } + }); + }, [clonedScene, bodyColor]); + + useFrame(() => { + const frame = timeline.find((f) => f.time >= time); + if (frame && ref.current) { + ref.current.position.set(frame.x, frame.z, frame.y); + ref.current.rotation.y = -frame.yaw; + } + }); + + const hasSpawned = timeline.length > 0 && timeline[0].time <= time; + if (!mounted || !hasSpawned) return null; + + return ( + } + object={clonedScene} + scale={scale} + rotation={rotation} + position={offset} + /> + ); +} diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/components/Vehicle.tsx b/GEMstack/onboard/visualization/sr_viz/threeD/src/components/Vehicle.tsx index 22d55138b..5fabb99a1 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/src/components/Vehicle.tsx +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/components/Vehicle.tsx @@ -14,7 +14,7 @@ interface VehicleProps { export default function Vehicle({ timeline, time }: VehicleProps) { const ref = useRef(null); - const vehicleGroup = useRef(new THREE.Group()); // ← create empty group for the robot + const vehicleGroup = useRef(new THREE.Group()); const mode = useCameraController(ref, timeline, time); const targetPosition = useMemo(() => new THREE.Vector3(), []); diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/config/cameraConfig.ts b/GEMstack/onboard/visualization/sr_viz/threeD/src/config/cameraConfig.ts index 6de374087..3e30bb358 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/src/config/cameraConfig.ts +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/config/cameraConfig.ts @@ -10,8 +10,8 @@ type CameraConfigMap = { const cameraConfig: CameraConfigMap = { first: { - position: [0, 1.5, -0.3], // on top of vehicle - lookAt: [2, 1.5, 0], // looking forward (+Z) + position: [0, 1.3, 0], // on top of vehicle + lookAt: [10, 2, 0], // looking forward (+Z) damping: 0.1, }, chase: { diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/config/otherVehicleConfig.ts b/GEMstack/onboard/visualization/sr_viz/threeD/src/config/otherVehicleConfig.ts new file mode 100644 index 000000000..91be73319 --- /dev/null +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/config/otherVehicleConfig.ts @@ -0,0 +1,14 @@ +const otherVehicleConfig = { + car: { + name: "Car", + modelPath: "/models/model/gem_e4.urdf", + scale: [1, 1, 1], + rotation: [-Math.PI / 2, 0, 0], + offset: [0, 0, 0], + bodyColor: "#808080", + }, +}; + +const currentOtherVehicle = otherVehicleConfig.car; + +export { otherVehicleConfig, currentOtherVehicle }; diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/config/trafficLightConfig.ts b/GEMstack/onboard/visualization/sr_viz/threeD/src/config/trafficLightConfig.ts new file mode 100644 index 000000000..ef86a63ee --- /dev/null +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/config/trafficLightConfig.ts @@ -0,0 +1,14 @@ +const trafficLightConfig = { + trafficLight: { + name: "Traffic Light", + modelPath: "/models/traffic_light.glb", + scale: [0.03, 0.03, 0.03], + rotation: [0, 0, 0], + offset: [0, 0, 0], + bodyColor: "#FFD700", + }, +}; + +const currentTrafficLight = trafficLightConfig.trafficLight; + +export { trafficLightConfig, currentTrafficLight }; diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/config/vehicleConfig.ts b/GEMstack/onboard/visualization/sr_viz/threeD/src/config/vehicleConfig.ts index f51360701..a23435ad0 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/src/config/vehicleConfig.ts +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/config/vehicleConfig.ts @@ -6,29 +6,7 @@ const vehicles = { rotation: [-Math.PI / 2, 0, 0], offset: [0, 0, 0], bodyColor: "#808080", - }, - roadster: { - name: "Roadster", - modelPath: "/models/roadster.glb", - scale: [1, 1, 1], - rotation: [0, Math.PI / 2, 0], - offset: [0, 0, 0], - bodyColor: "#808080", - }, - suv: { - name: "SUV", - modelPath: "/models/roadster.glb", - scale: [1, 1, 1], - rotation: [0, Math.PI / 2, 0], - bodyColor: "#808080", - }, - truck: { - name: "Truck", - modelPath: "/models/roadster.glb", - scale: [1, 1, 1], - rotation: [0, Math.PI, 0], - bodyColor: "#808080", - }, + } }; const currentVehicle = vehicles.gemE4; diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/hooks/useTimelineStore.ts b/GEMstack/onboard/visualization/sr_viz/threeD/src/hooks/useTimelineStore.ts index 2dd500e93..e82ea1b9b 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/src/hooks/useTimelineStore.ts +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/hooks/useTimelineStore.ts @@ -4,5 +4,7 @@ import { create } from 'zustand'; export const useTimelineStore = create((set) => ({ vehicle: [], agents: {}, + trafficLights: {}, + otherVehicles: {}, setTimeline: (timeline) => set(timeline), })); diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/hooks/useVehicleControls.ts b/GEMstack/onboard/visualization/sr_viz/threeD/src/hooks/useVehicleControls.ts index 0dbe955a9..27eccfc5f 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/src/hooks/useVehicleControls.ts +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/hooks/useVehicleControls.ts @@ -36,7 +36,7 @@ export function useVehicleControls( state.moving = false; - const forward = new Vector3(0, 0, 1).applyEuler(currentRotation); + const forward = new Vector3(1, 0, 0).applyEuler(currentRotation); if (keys['w']) { moveDir.add(forward); diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/types/TimelineData.ts b/GEMstack/onboard/visualization/sr_viz/threeD/src/types/TimelineData.ts index 81de7652c..6599240aa 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/src/types/TimelineData.ts +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/types/TimelineData.ts @@ -3,4 +3,6 @@ import { FrameData } from './FrameData'; export interface TimelineData { vehicle: FrameData[]; agents: Record; + trafficLights: Record; + otherVehicles: Record; } diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/utils/buildTimeline.ts b/GEMstack/onboard/visualization/sr_viz/threeD/src/utils/buildTimeline.ts index a0a138002..93be558bd 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/src/utils/buildTimeline.ts +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/utils/buildTimeline.ts @@ -5,6 +5,8 @@ import { TimelineData } from '@/types/TimelineData'; export function buildTimeline(entries: LogEntry[]): TimelineData { const vehicle: FrameData[] = []; const agents: Record = {}; + const trafficLights: Record = {}; + const otherVehicles: Record = {}; for (const entry of entries) { const pose = entry.data?.pose; @@ -22,12 +24,20 @@ export function buildTimeline(entries: LogEntry[]): TimelineData { if (entry.key === 'vehicle') { vehicle.push(frame); - } else { + } else if (entry.type === 'AgentState') { const key = entry.key.trim(); if (!agents[key]) agents[key] = []; agents[key].push(frame); + } else if (entry.type === 'TrafficLightState') { + const key = entry.key.trim(); + if (!trafficLights[key]) trafficLights[key] = []; + trafficLights[key].push(frame); + } else if (entry.type === 'OtherVehicleState') { + const key = entry.key.trim(); + if (!otherVehicles[key]) otherVehicles[key] = []; + otherVehicles[key].push(frame); } } - return { vehicle, agents }; + return { vehicle, agents, trafficLights, otherVehicles }; } diff --git a/GEMstack/onboard/visualization/sr_viz/threeD/src/utils/parseLogFile.ts b/GEMstack/onboard/visualization/sr_viz/threeD/src/utils/parseLogFile.ts index 6d879c0aa..af59a372e 100644 --- a/GEMstack/onboard/visualization/sr_viz/threeD/src/utils/parseLogFile.ts +++ b/GEMstack/onboard/visualization/sr_viz/threeD/src/utils/parseLogFile.ts @@ -12,12 +12,7 @@ export async function parseLogFile(file: File): Promise { for (const [key, value] of Object.entries(parsed)) { if (key === 'time' || typeof value !== 'object' || value === null) continue; - if ( - key === 'vehicle' && - 'type' in value && - 'data' in value && - (value as any).data?.pose?.frame === 3 - ) { + if (key === 'vehicle' && 'type' in value && 'data' in value && (value as any).data?.pose?.frame === 3) { entries.push({ key, type: (value as any).type, @@ -27,19 +22,20 @@ export async function parseLogFile(file: File): Promise { continue; } - if (key === 'agents') { - for (const [agentId, agentValue] of Object.entries(value)) { - if ( - typeof agentValue === 'object' && - agentValue !== null && - 'data' in agentValue && - (agentValue as any).data?.pose?.frame === 1 - ) { + if (key === 'agents' || key === 'traffic_lights' || key === 'other_vehicles') { + for (const [itemId, itemValue] of Object.entries(value)) { + if (typeof itemValue === 'object' && itemValue !== null && 'data' in itemValue) { + const frame = (itemValue as any).data?.pose?.frame; + + if (key === 'agents' && frame !== 1) { + continue; + } + entries.push({ - key: agentId, - type: (agentValue as any).type ?? 'AgentState', + key: itemId, + type: (itemValue as any).type ?? guessTypeFromKey(key), time, - data: (agentValue as any).data, + data: (itemValue as any).data, }); } } @@ -52,3 +48,10 @@ export async function parseLogFile(file: File): Promise { return entries; } + +function guessTypeFromKey(key: string): string { + if (key === 'agents') return 'AgentState'; + if (key === 'traffic_lights') return 'TrafficLightState'; + if (key === 'other_vehicles') return 'OtherVehicleState'; + return 'Unknown'; +} diff --git a/log_dashboard/README.md b/log_dashboard/README.md new file mode 100644 index 000000000..86c65fdb1 --- /dev/null +++ b/log_dashboard/README.md @@ -0,0 +1,18 @@ +Log Dashboard + +This dashboard can be used to browse GEMSTACK logs in a web browser. + +- It should display summary information (date, run duration, termination reason, sim vs real, launch command) in a table on the splash screen. + +- Can filter logs based on date + +- Upon choosing a log, it displays more detailed information about the run, allows file exporing directly in the browser (Button to open the folder is also present). + +- Upon visualizing behavior.json, you see the trajectory length, and a plot of the trajectory driven. + +To run the code: +1. pip install -r requirements.txt +2. Run python app.py +3. Go to 127.0.0.1:5000 + + diff --git a/log_dashboard/app.py b/log_dashboard/app.py new file mode 100644 index 000000000..ac1e7a384 --- /dev/null +++ b/log_dashboard/app.py @@ -0,0 +1,579 @@ +from flask import Flask, render_template, request, jsonify, send_file +import os +import yaml +import datetime +import functools +import time +from cachelib import SimpleCache +import json +import numpy as np +import platform +import matplotlib +from flask import Response, stream_with_context +from flask_cors import CORS + +# Use the 'Agg' backend which is thread-safe and doesn't require a GUI +matplotlib.use("Agg") + +import matplotlib.pyplot as plt + +app = Flask(__name__) +CORS(app) +CORS(app, origins=["http://localhost:3000"]) + +# Configure cache +cache = SimpleCache(threshold=500, default_timeout=300) # 5 minutes cache timeout + +LOG_DIR = "../logs" + + +def generate_behavior_plots(log_folder, behavior_file, target_frame=3): + """ + Generate a comprehensive visualization plot for vehicle, agents, and trajectory + + Args: + log_folder (str): Name of the log folder + behavior_file (str): Path to the behavior.json file + target_frame (int, optional): Specific frame to filter data. Defaults to None. + + Returns: + dict: Paths to generated plot files + """ + target_frame = 3 + # Define output plot directory + plot_dir = os.path.join("./plots", log_folder, "viz") + os.makedirs(plot_dir, exist_ok=True) + + # Create cache file to track previous plot generation + cache_file = os.path.join(plot_dir, f"plot_cache_frame_{target_frame}.json") + + # Check if plots have been previously generated + if os.path.exists(cache_file): + with open(cache_file, "r") as f: + return json.load(f) + + # Initialize data collections + vehicle_data = [] + agent_data = {} + trajectory_data = [] + + # Parse behavior file + with open(behavior_file, "r") as f: + for line in f: + try: + entry = json.loads(line.strip()) + + # Vehicle state + if "vehicle" in entry and "data" in entry["vehicle"]: + vehicle_state = entry["vehicle"]["data"]["pose"] + # Check frame filter if specified + if ( + target_frame is None + or vehicle_state.get("frame") == target_frame + ): + vehicle_data.append( + { + "time": entry["time"], + "x": vehicle_state.get("x", 0), + "y": vehicle_state.get("y", 0), + "frame": vehicle_state.get("frame"), + } + ) + + # Agent states + if "agents" in entry: + for agent_name, agent_info in entry["agents"].items(): + agent_state = agent_info["data"]["pose"] + # Check frame filter if specified + if ( + target_frame is None + or agent_state.get("frame") == target_frame + ): + if agent_name not in agent_data: + agent_data[agent_name] = [] + + agent_data[agent_name].append( + { + "time": entry["time"], + "x": agent_state.get("x", 0), + "y": agent_state.get("y", 0), + "frame": agent_state.get("frame"), + } + ) + + # Trajectory + if "trajectory" in entry and "data" in entry["trajectory"]: + traj_points = entry["trajectory"]["data"]["points"] + traj_times = entry["trajectory"]["data"]["times"] + traj_frames = entry["trajectory"]["data"].get( + "frames", [None] * len(traj_points) + ) + + trajectory_data = [ + {"x": point[0], "y": point[1], "time": time, "frame": frame} + for point, time, frame in zip( + traj_points, traj_times, traj_frames + ) + if target_frame is None or frame == target_frame + ] + + except json.JSONDecodeError: + continue + + # Comprehensive Plot + plt.figure(figsize=(12, 8)) + + # Plot vehicle trajectory + if vehicle_data: + vehicle_xs = [v["x"] for v in vehicle_data] + vehicle_ys = [v["y"] for v in vehicle_data] + plt.plot( + vehicle_xs, + vehicle_ys, + label="Vehicle Path", + color="red", + linewidth=3, + marker="o", + markersize=5, + ) + + # Plot agent trajectories + for agent_name, positions in agent_data.items(): + agent_xs = [a["x"] for a in positions] + agent_ys = [a["y"] for a in positions] + plt.plot(agent_xs, agent_ys, label=agent_name, marker="x") + + # Plot planned trajectory + if trajectory_data: + traj_xs = [t["x"] for t in trajectory_data] + traj_ys = [t["y"] for t in trajectory_data] + plt.plot( + traj_xs, + traj_ys, + label="Planned Trajectory", + color="green", + linestyle="--", + linewidth=2, + ) + + plt.title(f"Comprehensive Movement Visualization (Frame {target_frame})") + plt.xlabel("X Position") + plt.ylabel("Y Position") + plt.legend() + plt.grid(True, linestyle="--", alpha=0.7) + + # Save the plot + plot_path = os.path.join( + plot_dir, f"comprehensive_trajectory_frame_{target_frame}.png" + ) + plt.savefig(plot_path, dpi=300, bbox_inches="tight") + plt.close() + + # Cache plot file paths + plot_files = {"comprehensive": plot_path} + with open(cache_file, "w") as f: + json.dump(plot_files, f) + + return plot_files + + +@app.route("/view_log//render") +def render_vis_html(log_folder): + print(f"Rendering visualization HTML for log folder: {log_folder}") + return render_template("render.html", log_folder=log_folder) + + +@app.route("/view_log//get_render") +def render_behavior_visualization(log_folder): + """ + Render behavior visualization for a specific log folder + + Returns: + JSON response with plot file paths + """ + log_folder_path = os.path.join(LOG_DIR, log_folder) + + # Find behavior.json file + behavior_files = [f for f in os.listdir(log_folder_path) if f == "behavior.json"] + + if not behavior_files: + return jsonify({"error": "No behavior.json file found"}), 404 + + behavior_file_path = os.path.join(log_folder_path, behavior_files[0]) + + # Get frame from query parameter, default to None if not specified + target_frame = request.args.get("frame", type=int) + + try: + # Generate behavior plots + plot_files = generate_behavior_plots( + log_folder, behavior_file_path, target_frame + ) + print(plot_files) + # return jsonify(plot_files) + # return render_template("render.html", image_path=plot_files) + return send_file(plot_files["comprehensive"], mimetype="image/png") + + except Exception as e: + return jsonify({"error": str(e)}), 500 + + +# Add a route to serve plot files +@app.route("/plots//viz/") +def serve_plot(log_folder, filename): + """ + Serve plot files from the plots directory + """ + plot_dir = os.path.join("./plots", log_folder, "viz") + return send_file(os.path.join(plot_dir, filename)) + + +def get_cache_key(prefix, *args): + """Generate a cache key with a prefix and arguments""" + return f"{prefix}_{hash(str(args))}" + + +def parse_behavior_data(file_path): + """ + Parse behavior.json file and extract vehicle and agent positions + + Returns: + { + 'vehicle': [{'time': float, 'x': float, 'y': float}, ...], + 'agents': { + 'ped1': [{'time': float, 'x': float, 'y': float}, ...], + 'ped2': [...], + ... + } + } + """ + try: + with open(file_path, "r") as f: + # Read file line by line to handle large files + positions = {"vehicle": [], "agents": {}} + + for line in f: + try: + entry = json.loads(line.strip()) + + # Process Vehicle State + if "vehicle" in entry: + vehicle_data = entry["vehicle"]["data"]["pose"] + positions["vehicle"].append( + { + "time": entry["time"], + "x": vehicle_data.get("x", 0), + "y": vehicle_data.get("y", 0), + } + ) + + # Process Agent States + if "agents" in entry: + for agent_name, agent_data in entry["agents"].items(): + if agent_name not in positions["agents"]: + positions["agents"][agent_name] = [] + + agent_pose = agent_data["data"]["pose"] + positions["agents"][agent_name].append( + { + "time": entry["time"], + "x": agent_pose.get("x", 0), + "y": agent_pose.get("y", 0), + } + ) + + except json.JSONDecodeError: + # Skip invalid JSON lines + continue + + return positions + except Exception as e: + print(f"Error parsing behavior data: {e}") + return None + + +@functools.lru_cache(maxsize=100) +def load_log_data(): + """Load all log data with caching""" + cache_key = "all_logs" + cached_logs = cache.get(cache_key) + + if cached_logs is not None: + return cached_logs + + start_time = time.time() + logs = [] + + for log_folder in sorted(os.listdir(LOG_DIR), reverse=True): + log_path = os.path.join(LOG_DIR, log_folder) + if not os.path.isdir(log_path): + continue + + meta_path = os.path.join(log_path, "meta.yaml") + settings_path = os.path.join(log_path, "settings.yaml") + + try: + with open(meta_path, "r") as meta_file: + meta_data = yaml.safe_load(meta_file) + with open(settings_path, "r") as settings_file: + settings_data = yaml.safe_load(settings_file).get("run", {}) + except Exception as e: + print(f"Error loading log data: {e}") + continue + + logs.append( + { + "date": log_folder, + "run_duration": meta_data.get("run_duration", "Unknown"), + "exit_reason": meta_data.get("exit_reason", "Unknown"), + "mode": settings_data.get("mode", "Unknown"), + "launch_command": settings_data.get("log", {}).get( + "launch_command", "Unknown" + ), + "folder": log_path, + } + ) + + # Store results in cache + cache.set(cache_key, logs) + end_time = time.time() + print(f"Log data loaded in {end_time - start_time:.2f} seconds") + print(logs) + return logs + + +def filter_logs_by_date(logs, start_date=None, end_date=None): + """Filter logs by date range""" + cache_key = get_cache_key("filtered_logs", start_date, end_date) + cached_result = cache.get(cache_key) + + if cached_result is not None: + return cached_result + + if start_date: + start_date = datetime.datetime.strptime(start_date, "%Y-%m-%d") + if end_date: + end_date = datetime.datetime.strptime(end_date, "%Y-%m-%d") + + filtered_logs = [] + for log in logs: + try: + log_date = datetime.datetime.strptime(log["date"][:10], "%Y-%m-%d") + if (not start_date or log_date >= start_date) and ( + not end_date or log_date <= end_date + ): + filtered_logs.append(log) + except ValueError: + # Skip logs with invalid date format + continue + + # Cache the filtered results + cache.set(cache_key, filtered_logs) + return filtered_logs + + +@functools.lru_cache(maxsize=50) +def get_log_metadata(log_folder_path): + """Get metadata for a specific log with caching""" + cache_key = f"metadata_{log_folder_path}" + cached_metadata = cache.get(cache_key) + + if cached_metadata is not None: + return cached_metadata + + metadata = {"folder": log_folder_path} + + # Read metadata from files + meta_path = os.path.join(log_folder_path, "meta.yaml") + settings_path = os.path.join(log_folder_path, "settings.yaml") + + try: + if os.path.exists(meta_path): + with open(meta_path, "r") as meta_file: + metadata.update(yaml.safe_load(meta_file)) + if os.path.exists(settings_path): + with open(settings_path, "r") as settings_file: + log_settings = yaml.safe_load(settings_file).get("run", {}) + + metadata.update( + { + "mode": log_settings.get("mode", "Unknown"), + "launch_command": log_settings.get("log", {}).get( + "launch_command", "Unknown" + ), + } + ) + except Exception as e: + print(f"Error loading metadata: {e}") + + # Cache the results + cache.set(cache_key, metadata) + return metadata + + +@app.route("/") +def index(): + logs = load_log_data() + return render_template("index.html", logs=logs) + + +@app.route("/filter_logs", methods=["POST"]) +def filter_logs(): + start_time = time.time() + logs = load_log_data() + data = request.json + start_date = data.get("start_date") + end_date = data.get("end_date") + + filtered_logs = filter_logs_by_date(logs, start_date, end_date) + + end_time = time.time() + print(f"Filtered logs in {end_time - start_time:.2f} seconds") + return jsonify(filtered_logs) + + +@app.route("/view_log/") +def view_log(log_folder): + log_folder_path = os.path.join(LOG_DIR, log_folder) + if not os.path.exists(log_folder_path): + return "Log folder not found!", 404 + + # Get metadata with caching + metadata = get_log_metadata(log_folder_path) + + # Get directory structure + files = sorted(os.listdir(log_folder_path)) + + return render_template( + "view_log.html", log_folder=log_folder, metadata=metadata, files=files + ) + + +@app.route("/open_folder/") +def open_folder(folder): + import os, platform + + full_path = os.path.abspath(os.path.join(LOG_DIR, folder)) + if not full_path.startswith(os.path.abspath(LOG_DIR)): + return "Invalid path", 400 + if not os.path.isdir(full_path): + return f"Folder does not exist: {folder}", 404 + + try: + if platform.system() == "Windows": + os.system(f'explorer "{full_path}"') + elif platform.system() == "Linux": + os.system(f'xdg-open "{full_path}"') + elif platform.system() == "Darwin": + os.system(f'open "{full_path}"') + else: + return "Unsupported platform", 400 + except Exception as e: + return f"Failed to open folder: {e}", 500 + + # if result != 0: + # return 'Failed to open folder', 500 + + return "Folder opened successfully.", 204 + + +@app.route("/view_file//") +def view_file(log_folder, filename): + file_path = os.path.join(LOG_DIR, log_folder, filename) + if not os.path.exists(file_path): + return jsonify({"error": "File not found!"}), 404 + + # Check file size first + file_size = os.path.getsize(file_path) + + # Define chunk size for pagination (50,000 lines or ~1MB) + CHUNK_SIZE = 1000 + + # Get page number from query parameter (default to 1) + page = request.args.get("page", 1, type=int) + + try: + with open(file_path, "r") as f: + # Skip lines for previous pages + for _ in range((page - 1) * CHUNK_SIZE): + f.readline() + + # Read next chunk of lines + lines = [f.readline() for _ in range(CHUNK_SIZE)] + # Check if there are more lines + has_more = bool(f.readline()) + + # Prepare response + return jsonify( + { + "filename": filename, + "content": "".join(lines), + "total_size": file_size, + "page": page, + "has_more": has_more, + } + ) + except UnicodeDecodeError: + return jsonify( + { + "filename": filename, + "content": "This file contains binary data and cannot be displayed in the browser.", + "total_size": file_size, + "page": page, + "has_more": False, + } + ) + + +@app.route("/raw_logs//") +def stream_raw_log(log_folder, filename): + file_path = os.path.join(LOG_DIR, log_folder, filename) + if not os.path.isfile(file_path): + return "File not found!", 404 + + def generate(): + with open(file_path, "r", encoding="utf-8") as f: + for line in f: + yield line + + return Response(stream_with_context(generate()), mimetype="text/plain") + + +@app.route("/parse_behavior//") +def parse_behavior(log_folder, filename): + """ + Parse behavior.json and return structured position data + """ + file_path = os.path.join(LOG_DIR, log_folder, filename) + + if not os.path.exists(file_path): + return jsonify({"error": "File not found!"}), 404 + + # Parse behavior data + behavior_data = parse_behavior_data(file_path) + + if behavior_data is None: + return jsonify({"error": "Could not parse behavior data"}), 500 + + return jsonify(behavior_data) + + +# Clear cache after certain time period +@app.after_request +def add_header(response): + # Invalidate cache for certain requests + if request.path == "/": + # Clear cache periodically for main page + current_time = int(time.time()) + last_cleared = cache.get("last_cache_clear") or 0 + + if current_time - last_cleared > 300: # 5 minutes + # Reset log data cache + load_log_data.cache_clear() + cache.set("last_cache_clear", current_time) + + return response + + +if __name__ == "__main__": + app.run(debug=True) diff --git a/log_dashboard/plots/.gitignore b/log_dashboard/plots/.gitignore new file mode 100644 index 000000000..9f992b4d7 --- /dev/null +++ b/log_dashboard/plots/.gitignore @@ -0,0 +1,5 @@ +* + +# track just these files +!.gitignore +!sample_plot.png diff --git a/log_dashboard/plots/sample_plot.png b/log_dashboard/plots/sample_plot.png new file mode 100644 index 0000000000000000000000000000000000000000..9d1fac35de7eac0e4f3cdb09c275a030dd817a6a GIT binary patch literal 142686 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 RC;CPk3^%X6wdUtz{{%PE$Ta`} literal 0 HcmV?d00001 diff --git a/log_dashboard/requirements.txt b/log_dashboard/requirements.txt new file mode 100644 index 000000000..cb006a29b --- /dev/null +++ b/log_dashboard/requirements.txt @@ -0,0 +1,5 @@ +flask +pyyaml +cachelib +numpy +matplotlib \ No newline at end of file diff --git a/log_dashboard/templates/index.html b/log_dashboard/templates/index.html new file mode 100644 index 000000000..d0401710b --- /dev/null +++ b/log_dashboard/templates/index.html @@ -0,0 +1,102 @@ + + + + + + GEMstack Log Dashboard + + + + + +

+

GEMstack Log Dashboard

+
+ + + + + +
+ + + + + + + + + + + + + {% for log in logs %} + + + + + + + + + {% endfor %} + +
DateRun Duration (s)Termination ReasonSim vs RealLaunch CommandActions
{{ log.date }}{{ log.run_duration }}{{ log.exit_reason }}{{ log.mode }}{{ log.launch_command }} +
+ View + Details + +
+
+
+ + + + \ No newline at end of file diff --git a/log_dashboard/templates/render.html b/log_dashboard/templates/render.html new file mode 100644 index 000000000..71e46d98b --- /dev/null +++ b/log_dashboard/templates/render.html @@ -0,0 +1,75 @@ + + + + + Render Trajectory + + + + + + + + +
+ + diff --git a/log_dashboard/templates/view_log.html b/log_dashboard/templates/view_log.html new file mode 100644 index 000000000..0d605a2f8 --- /dev/null +++ b/log_dashboard/templates/view_log.html @@ -0,0 +1,389 @@ + + + + + + View Log - {{ log_folder }} + + + + + + + + + +
+
+

Log Details for {{ log_folder }}

+
+ Back to Dashboard + +
+
+ +
+
+
+

Run Duration: {{ metadata.run_duration }}

+

Exit Reason: {{ metadata.exit_reason }}

+
+
+

Mode: {{ metadata.mode }}

+

Launch Command: {{ metadata.launch_command }}

+
+
+
+ +
+
+

Files

+
+ {% for file in files %} +
+ {% if file.endswith('.yaml') or file.endswith('.yml') %} + 📄 {{ file }} + {% elif file.endswith('.txt') or file.endswith('.log') %} + 📝 {{ file }} + {% elif file.endswith('.csv') %} + 📊 {{ file }} + {% else %} + 📄 {{ file }} + {% endif %} +
+ {% endfor %} +
+
+
+
+

Select a file to view

+
+
+
+
+
+ +
+
+
+
+ + + + + \ No newline at end of file
+

Rendered Trajectory

+
+
+ Image will be displayed here +
+ + +