Repository navigation
v3.0.0 — 闭式积分、渲染契约、有限观测空间、基准协议
3.0.0 是 API 稳定线:从这一版起本包承诺 semver,因此 classifier 保持
Development Status :: 5 - Production/Stable,不降级为 Beta。
Breaking
- Gymnasium id 由
-v0改成-v1:ChassisSim-{Ackermann,DiffDrive,Mecanum}-v0不再注册,
gym.make("ChassisSim-Ackermann-v0")抛gym.error.DeprecatedEnv,消息里直接点名要用的-v1id。
三个-v1id 的entry_point、动作空间与max_episode_steps与 2.x 相同。 - 默认场景改为
dense_static:EnvConfig.default_scenario默认"dense_static",reset()不带
显式 seed 时每回合重掷地图(default_scenario=None才回到 2.x 的straight直线兜底)。
2.x 里reset()拿到的是固定直线场景,所以这既是默认值变更,也会改变无 seed 训练的分布。 observation_space从无界Box(±inf)变成全有限:各段按物理上界声明——path段的 ρ 上界是
world_diag + lookahead + 0.1 = 34.24213790893555、角度段 π、归一化段1 + 1 ulp = 1.0000001192092896;
非零有限界各放宽 1 ulp。真正越界的观测值才被 clip,并在info["obs_clipped"]给出计数(计数为 0 时该键不出现)。
依赖low/high为inf的包装器要改用新值。- 闭式积分替换 Euler 步进:同一动作序列下位姿会变——圆周 max-radial 误差
5.04e-2→3.33e-16m,
60 步开环序列的 xy 最大差0.0403m,θ 通道逐位不变;|ω·dt| ≤ 1.49e-8(sqrt(float64 eps))时仍走
与 2.x 逐位相同的 Euler 分支。用 2.x 生成的 golden 必须重录:本仓tests/data/ackermann_golden.json
已重录,旧轨迹以poses_euler_legacy保留并与 HEAD 的 posesnp.array_equal=True。
Added
- 观测段可声明物理上界:新增
BoundContext(dt/v_max/v_min/vy_max/omega_max/
lookahead/world_diag/lidar)与ResolvedObsSpec.bounds(),内置段各自给出界,
Custom段也能带自己的界;observation_space由这些界拼成,不再是无界 Box。 - 渲染契约:
render_mode支持None/"human"/"rgb_array",render()返回uint8 (600, 600, 3),
metadata带render_modes与render_fps = 10;新增chassis_sim.render.render_to_array(bridge, dpi=...)
供无窗口取帧。缺matplotlib时抛带pip install "chassis-sim[viz]"的ImportError。 - 轮级运动学层(纯只读):
Chassis.wheel_kinematics(cmd) -> WheelKinematics | None,给出 Ackermann 的
内外前轮角、DiffDrive 的左右轮速、Mecanum 的四轮速(逆 Jacobian);Ackermann 另有front_wheel_angles(delta)。
不支持时返回None,不返回空 dict;积分器与动作语义一律未动。 integration_substeps与ccd:前者把一步切成 N 段分别积分与碰撞采样,后者在每段内按0.02 m/
0.05 rad采样内部位姿(上限 64 个)以拦住薄墙穿透。默认1/False,与 2.x 逐位相同;
ccd只接受bool,1/0/"false"一律ValueError。- 基准协议:
chassis_sim.eval.benchmark(...)(策略 × held-out 场景 × ≥3 seed、同 (场景, seed) 的地图在
策略间共享做配对、Wilson 区间、独立样本闸门——地图指纹有重复时success_ci返回None而不是给假数字),
四基线zero/random/pp/dwa,以及python -m chassis_sim benchmark子命令。evaluate()签名未动。 EnvConfig.default_scenario:默认"dense_static",设为None回到 2.x 的直线兜底。- CI 的 ubuntu 矩阵覆盖 NumPy 1.x 与 2.x 两档(
matrix.numpy:numpy<2/
numpy>=2),每档都跑完整套件,并用一步断言实测到的 NumPy 主版本与矩阵档位一致。
3.13 × numpy<2显式排除:PyPI 上 cp313 的 NumPy 从 2.1.0 才开始发布
(pip download --python-version 3.13 "numpy<2"报
No matching distribution found),pip 只能退回源码构建。3.13 仍在
numpy>=2档真跑:numba 的 cp313 轮子从 0.61.0 起提供,numba>=0.60在
3.13 上会解析到 0.61+。 - 新增 CI 的
docsjob 与tools/check_readme_blocks.py:把两份 README 里的
python围栏块逐个放进独立子进程执行,任一失败即红;块首行写# no-exec
才允许跳过,跳过计入 skipped 而不是 passed,一个 python 块都没有也算失败。 devextra 自带全部闸门工具:mypy==2.4.1、pytest-cov==7.1.0、
types-PyYAML==6.0.12.20261103。pip install -e ".[dev]"之后即可直接跑
MYPYPATH=src mypy与pytest --cov,不必再单独装工具。
Changed
- planning extra 的 numba 下界
>=0.56→>=0.60:Numba 0.60.0 是第一个提供
NumPy 2.0 二进制支持的版本,更早的组合与numpy>=2在 import 阶段就失败。
运行依赖numpy>=1.24不变 —— 1.x 与 2.x 都仍然支持。 - README 与包定位改口径:从 “Gymnasium benchmark” 改为「底盘控制 + 观测/奖励工作台」,并写明三条边界
(底盘级运动学而非轮级刚体动力学、碰撞是几何判据无接触力、无 GPU 并行);CITATION.cff的标题与摘要同步。 - 闭式积分下的
integration_substeps语义:精度不再随分段数改善(已到浮点噪声),它的作用只剩提高碰撞采样密度;
文档与 docstring 都按这个口径写,不宣称「更高精度积分」。
Fixed
- 注入的桥不再被塞进 env 的内置场景:2.x 起
ChassisSimEnv(bridge=...)且reset()不带options时,
env 会把default_scenario的obstacles/path_waypoints/initial_heading直接递给调用方的桥,
而桥照单全收、不报错(主仓的PhysicalCommandBridge(NumpySimBridge)正是这种注入形态)。现在只有
「options is None+ 桥由 env 自造 + 无map_generator+ 配了default_scenario」四条全成立才接管;
注入桥保留调用方自己的世界。 render()与渲染元数据补齐:2.x 的metadata只有render_modes=["human"]、没有render_fps,
env.render()直接NotImplementedError,gym.make(..., render_mode="rgb_array")会TypeError。
3.0 起三者都按 Gymnasium 契约工作,gymnasium.utils.env_checker.check_env(..., skip_render_check=False)
在三种底盘上都不再报Box maximum value is infinity。