- amcl: tf_broadcast:false so AMCL no longer fights the camera_init->odom static bridge for odom's parent (AMCL still publishes /amcl_pose)
- Add a sibling camera_init->map static bridge so global_costmap's map frame keeps resolving with AMCL's TF broadcast disabled
- serial_bridge_node (C++): broadcast odom->base_link TF from wheel odometry, since nothing else in the stack was providing it
- rosbridge_websocket: raise max_message_size to 20MB so large messages (e.g. /map) are sent whole instead of split into 'fragment' messages roslib.js can't reassemble
- Port serial_bridge_node's low-level Modbus RTU transport to C++ (fori_serial_bridge_cpp) to remove Python control-loop delay, keeping the existing control algorithm/parameters unchanged
- Switch Nav2 and mock/patrol map to the Gunsan 2.5D site (pcd_gunsan_output), with terrain_speed_node scaling drive speed up on uphill grades and down on downhill grades for both Nav2 and patrol
- Unify Nav2 cruise speed and motor safety-clamp speed at 0.3 m/s
- Add nav2_collision_monitor as a final safety gate against sudden dynamic obstacles, routed so it can't be bypassed by velocity_smoother's internal remap
- Fix web dashboard map rendering (stray map_server process, oversized GetMap payload, rosbridge fragment size vs. roslib.js incompatibility) and PWA reachability via mDNS
- Fix TF tree: wheel-odometry broadcasts odom->base_link, and camera_init is statically bridged to both odom and map so AMCL's own map->odom broadcast no longer conflicts with the SLAM anchor frame