- Wrap rclpy.shutdown() in try/except across all nodes to avoid
"rcl_shutdown already called" errors when launched via ros2 launch.
- Replace web_node's server.shutdown() with server_close() to prevent
the HTTP server from hanging on SIGINT (shutdown() waits on an event
only set by serve_forever, which the timer-based approach doesn't use).
- Set rosbridge_websocket default_call_service_timeout=5.0,
call_services_in_new_thread=True, send_action_goals_in_new_thread=True
to match upcoming Jazzy defaults and silence startup warnings.
- camera_node (driver_pkg): Hikrobot MvCamera SDK image capture
- vision_node (algorithm_pkg): Otsu threshold + contour detection + target tracking
- web_node (application_pkg): HTTP server with MJPEG preview and mode switch API
- gimbal_node (gimbal_control_pkg): UART serial communication per gimbal protocol
- bringup_pkg: launch file for full pipeline
- config: nginx reverse-proxy for MJPEG streaming and API routing