Import fix#2783
Conversation
jeff-hykin
commented
Jul 7, 2026
…OS/dimos into andrew/feat/navigation-dev-2
…tion-dev-2' of github.com:dimensionalOS/dimos into andrew/feat/navigation-dev-2
…OS/dimos into andrew/feat/navigation-dev-2
…OS/dimos into andrew/feat/navigation-dev-2
Greptile SummaryThis PR changes the ray-tracing map and 3D navigation stack. The main changes are:
Confidence Score: 4/5The changed mapping and planner paths can produce missing map data or disconnected routes under realistic robot timing and terrain.
dimos/mapping/ray_tracing/rust/src/main.rs, dimos/navigation/nav_3d/mls_planner/rust/src/main.rs, dimos/navigation/nav_3d/mls_planner/rust/src/mls_planner.rs Important Files Changed
Reviews (1): Last reviewed commit: "fixup import" | Re-trigger Greptile |
| let Some((translation, rotation)) = nearest_pose(&self.poses, time_secs(&msg.header.stamp)) | ||
| else { | ||
| warn_throttled!( | ||
| Duration::from_secs(1), | ||
| "No odometry within tolerance of the cloud stamp, dropped a cloud.", | ||
| ); | ||
| return; | ||
| }; |
There was a problem hiding this comment.
Tight Stamp Match Drops Clouds
When lidar and odometry header stamps differ by more than 100ms, this branch returns before update_map runs. At common 10Hz odometry rates that leaves almost no room for skew or batching, so a normal timing offset can make the voxel map stop updating while the robot is moving.
| let points = emit_points(&self.map, voxel_size, Some(cyl), support_min, &live); | ||
| let local = points_to_cloud(&points, out_frame_id, stamp); |
There was a problem hiding this comment.
Local Map Hides Isolated Obstacles
The local map now applies support_min to healthy voxels while the global map does not. With the default support_min=4, a real but isolated occupied voxel, such as a pole or sparse obstacle in the planner cylinder, is omitted from local_map even though it remains in the global map, so local planning can ignore it.
| let z_max = bounds.pose.orientation.z as f32; | ||
| let sensor_z = self | ||
| .latest_start | ||
| .lock() | ||
| .expect("start mutex") | ||
| .map_or(z_max, |(_, _, z)| z); | ||
| let bounds = RegionBounds::capped( | ||
| bounds.pose.position.x as f32, | ||
| bounds.pose.position.y as f32, | ||
| bounds.pose.orientation.x as f32, | ||
| bounds.pose.orientation.y as f32, | ||
| z_max, | ||
| sensor_z, | ||
| self.config.max_overhead_m, | ||
| ); |
There was a problem hiding this comment.
This native path feeds the ground-projected start z into RegionBounds::capped, while the Python transformer passes the raw pose z. With max_overhead_m=2.0, a robot at ground level can cap the region near ground_z + 2m and drop valid upper surfaces from the local update, making stairs or elevated traversable areas disappear from the planner graph.
|
|
||
| /// Max traversable vertical step in cells. | ||
| pub fn step_cells(&self) -> i32 { | ||
| (self.step_threshold_m / self.voxel_size).floor() as i32 |
There was a problem hiding this comment.
step_cells() now floors the metric threshold, so non-integral ratios become stricter than the configured step_threshold_m. For example, 0.15m with 0.08m voxels allows only one cell of climb, causing routes over steps below the configured metric limit to be treated as disconnected.
|
|
||
| /// Spare a clearing miss only when a grazing ray skims a recently hit planar | ||
| /// surface. Stale voxels or those with no normal are left to the health checks. | ||
| fn should_spare( | ||
| c: &Voxel, | ||
| ray_unit: Vector3<f32>, | ||
| graze_cos: f32, | ||
| frame: u32, | ||
| recency_window: u32, | ||
| ) -> bool { | ||
| /// Spare a clearing miss when a grazing ray skims a planar surface. | ||
| fn should_spare(c: &Voxel, ray_unit: Vector3<f32>, graze_cos: f32) -> bool { | ||
| match c.normal { | ||
| Some(n) => { | ||
| frame.saturating_sub(c.recency) <= recency_window && ray_unit.dot(&n).abs() < graze_cos | ||
| } | ||
| Some(n) => ray_unit.dot(&n).abs() < graze_cos, | ||
| None => false, |
There was a problem hiding this comment.
…/navigation-dev-2
❌ 2 Tests Failed:
View the full list of 2 ❄️ flaky test(s)
To view more test analytics, go to the Test Analytics Dashboard |