v0.2 — BeltDrive, bevel gears, and a better error model
Three months since the initial release. The main things I wanted to fix: the complete absence of non-spur-gear support, and an error system that printed "solver did not converge" with no context whatsoever. Both are addressed in 0.2.
BeltDrive
Chain and belt transmissions are now first-class citizens. The BeltDrive class takes a driver and driven sprocket (which are just gears with tooth counts interpreted as sprocket teeth) and an optional slip fraction:
belt = ms.BeltDrive(
sprocket_driver=asm.add_gear(teeth=22, driven_by=motor_shaft),
sprocket_driven=asm.add_gear(teeth=66),
slip=0.015 # 1.5% creep
)
The slip model is the simplest possible thing — a constant fractional reduction on the driven sprocket velocity. It's not a tribology model; if you need Eytelwein creep equations you'll have to implement a custom Constraint. For most practical purposes the constant-slip approximation is fine.
Bevel gears
Right-angle shaft drives now work. The BevelPair constructor takes two gears and a shaft angle (default 90°). The kinematic model is exact for a 90° bevel pair; other angles use the standard pitch cone approximation which is accurate to within 0.5% for angles between 45° and 135°.
Better exceptions
The old solver raised a bare RuntimeError("solver did not converge"). The new exception hierarchy tells you what failed and why:
# Old
RuntimeError: solver did not converge
# New
molenspin.ConvergenceError: Newton solver failed at step 847 (t=0.847s)
Residual norm: 3.42e-2 (tolerance: 1e-6)
Largest residual: constraint 'PivotConstraint(wallower_shaft)' —
try loosening atol or checking for a near-singular configuration
This took longer to implement than the bevel gear support. Getting useful error messages out of a compiled Rust extension requires some care around how you ferry diagnostic state across the FFI boundary — I ended up using a thread-local error buffer in Rust that Python reads back on exception.
Breaking changes
Assembly.add_bevel_pair()replaced byms.BevelPair()(cleaner API)simulate()now returnsSimResultinstead of a raw dict- Minimum NumPy version raised to 1.24
See the full changelog for the complete list.