Molenspin exposes configuration at two levels: assembly-wide settings passed to ms.Assembly(), and per-simulation settings passed to .simulate().
asm = ms.Assembly(
name="my-gearbox", # str — label for exports and error messages
gravity=9.81, # float, m/s² — used only if dynamic mode enabled
default_module=2.0, # float, mm — tooth module for gears without explicit module
backlash=0.0, # float, radians — global backlash; override per gear pair
frame_origin=(0.0, 0.0), # tuple[float, float] — SVG coordinate origin
)
result = asm.simulate(
duration=2.0, # float, seconds
dt=1e-3, # float, seconds — timestep
integrator="rk4", # "rk4" | "verlet" | "euler" — default rk4
rtol=1e-6, # float — relative tolerance (adaptive integrators)
atol=1e-9, # float — absolute tolerance
warm_start=True, # bool — use previous state as initial condition
record_contacts=False, # bool — log contact forces (slow, for diagnostics)
)
| Integrator | Order | Use when |
|---|---|---|
rk4 | 4 | Default. Good accuracy/speed balance for smooth inputs. |
verlet | 2 (symplectic) | Long-duration runs where energy conservation matters. |
euler | 1 | Quick prototyping only — accumulates error fast. |
gear = asm.add_gear(
teeth=36, # int — tooth count, required
driven_by=some_shaft, # Shaft | None
meshes_with=other_gear, # Gear | None — at most one of driven_by/meshes_with
module=None, # float | None — overrides assembly default_module
pressure_angle=20.0, # float, degrees — involute pressure angle
helix_angle=0.0, # float, degrees — for helical gear approximation
name="g1", # str
)
For right-angle drives (e.g. the windmill vertical-to-horizontal shaft hand-off), use ms.BevelPair:
bevel = ms.BevelPair(
gear_a=asm.add_gear(teeth=24, driven_by=shaft_vertical),
gear_b=asm.add_gear(teeth=24),
shaft_angle=90.0, # degrees between the two shaft axes
)
belt = ms.BeltDrive(
sprocket_driver=asm.add_gear(teeth=18, driven_by=shaft_in),
sprocket_driven=asm.add_gear(teeth=54),
slip=0.0, # fraction — 0.02 = 2% slip
)
result.export_svg(
path="output.svg",
fps=30, # int — frames per second
duration=None, # float | None — trim to this many seconds
scale=1.0, # float — global scale factor
show_pitch_circles=True, # bool — draw pitch circle overlays
show_contact_points=False, # bool — mark instantaneous contact points
tooth_style={ # dict — SVG CSS overrides for tooth fills/strokes
"fill": "#1c2130",
"stroke": "#e08a30",
"stroke-width": "0.5",
},
background="#10131a", # str — SVG background color
)
result.export_json("timeseries.json", indent=2)
# Produces: { "dt": 0.001, "shafts": { "input": { "omega": [...], "theta": [...] }, ... } }
record_contacts=True increases memory by roughly 6× and slows simulation by 30–40%. Only enable it when you actually need contact force data.
import logging
logging.basicConfig(level=logging.DEBUG)
import molenspin as ms
# The molenspin logger is named "molenspin"
# Set to WARNING in production — DEBUG prints every constraint iteration