|
21 | 21 |
|
22 | 22 | # If mass is too small, we do not care much about spatial inertia discrepancy |
23 | 23 | MASS_EPS = 0.005 |
| 24 | +AABB_EPS = 0.002 |
24 | 25 | INERTIA_RATIO_MAX = 100.0 |
25 | 26 |
|
26 | 27 |
|
@@ -137,6 +138,8 @@ def _build(self): |
137 | 138 | hint_mass = 0.0 |
138 | 139 | hint_com = np.zeros(3, dtype=gs.np_float) |
139 | 140 | hint_inertia = np.zeros((3, 3), dtype=gs.np_float) |
| 141 | + aabb_min = np.full((3,), float("inf"), dtype=gs.np_float) |
| 142 | + aabb_max = np.full((3,), float("-inf"), dtype=gs.np_float) |
140 | 143 | if not self._is_fixed: |
141 | 144 | # Determine which geom list to use: geoms first, then vgeoms, then fallback |
142 | 145 | if self._geoms: |
@@ -220,15 +223,37 @@ def _build(self): |
220 | 223 | hint_mass, hint_com, hint_inertia, geom_mass, geom_com_link, geom_inertia_link |
221 | 224 | ) |
222 | 225 |
|
| 226 | + # Compute the bounding box of the links using both visual and collision geometries to be conservative |
| 227 | + for geoms, is_visual in zip((self._geoms, self._vgeoms), (False, True)): |
| 228 | + for geom in geoms: |
| 229 | + verts = geom.init_vverts if is_visual else geom.init_verts |
| 230 | + verts = gu.transform_by_trans_quat(verts, geom._init_pos, geom._init_quat) |
| 231 | + aabb_min = np.minimum(aabb_min, verts.min(axis=0)) |
| 232 | + aabb_max = np.maximum(aabb_max, verts.max(axis=0)) |
| 233 | + |
223 | 234 | # Make sure that provided spatial inertia is consistent with the estimate from the geometries if not fixed |
224 | 235 | if hint_mass > MASS_EPS: |
| 236 | + if self._inertial_pos is not None: |
| 237 | + tol = (aabb_max - aabb_min) * AABB_EPS + AABB_EPS |
| 238 | + if not ((aabb_min - tol < self._inertial_pos) & (self._inertial_pos < aabb_max + tol)).all(): |
| 239 | + com_str: list[str] = [] |
| 240 | + aabb_str: list[str] = [] |
| 241 | + for name, pos, axis_min, axis_max in zip(("x", "y", "z"), self._inertial_pos, aabb_min, aabb_max): |
| 242 | + com_str.append(f"{name}={pos:0.3f}") |
| 243 | + aabb_str.append(f"{name}=({axis_min:0.3f}, {axis_max:0.3f})") |
| 244 | + gs.logger.warning( |
| 245 | + f"Link '{self._name}' has dubious center of mass [{', '.join(com_str)}] compared to the " |
| 246 | + f"bounding box from geometry [{', '.join(aabb_str)}]." |
| 247 | + ) |
| 248 | + |
225 | 249 | if self._inertial_mass is not None: |
226 | 250 | if not (hint_mass / INERTIA_RATIO_MAX <= self._inertial_mass <= INERTIA_RATIO_MAX * hint_mass): |
227 | 251 | gs.logger.warning( |
228 | 252 | f"Link '{self._name}' has dubious mass {self._inertial_mass:0.3f} compared to the estimate " |
229 | 253 | f"from geometry {hint_mass:0.3f} given material density {rho:0.0f}." |
230 | 254 | ) |
231 | 255 | hint_inertia *= self._inertial_mass / hint_mass |
| 256 | + |
232 | 257 | if self._inertial_i is not None: |
233 | 258 | inertia_diag = np.diag(self._inertial_i) |
234 | 259 | hint_inertia_diag = np.diag(hint_inertia) |
|
0 commit comments