Metadata-Version: 2.4
Name: kimech
Version: 0.6.1
Summary: Planar mechanism kinematics for Python
Author: Pedro Jorge De Los Santos
License-Expression: MIT
Project-URL: Documentation, https://jorgedelossantos.github.io/kimech/
Project-URL: Repository, https://github.com/JorgeDeLosSantos/kimech
Project-URL: Changelog, https://github.com/JorgeDeLosSantos/kimech/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/JorgeDeLosSantos/kimech/issues
Keywords: mechanisms,kinematics,mechanical engineering,robotics
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Education
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.26
Requires-Dist: scipy>=1.11
Provides-Extra: viz
Requires-Dist: matplotlib>=3.8; extra == "viz"
Requires-Dist: pillow>=10; extra == "viz"
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: pytest-cov>=5; extra == "dev"
Provides-Extra: docs
Requires-Dist: sphinx>=8; extra == "docs"
Requires-Dist: myst-parser>=4; extra == "docs"
Requires-Dist: furo>=2024.8.6; extra == "docs"
Dynamic: license-file

# Kimech

Kimech is a small Python library for modeling and solving the kinematics of planar rigid-body mechanisms.

Public documentation: https://jorgedelossantos.github.io/kimech/

It provides declarative rigid-body models with revolute and prismatic joints, robust one-DOF position/velocity/acceleration solving, structural topology introspection, structured numerical diagnostics, driver-coordinate sensitivity analysis, and schematic plotting and animation.

Kimech supports position, velocity, and acceleration analysis for one-DOF planar R/P mechanisms driven by one `KinematicDriver`. The current `0.6.x` driver/time design is recorded in [`docs/study-0.6.0-kinematic-driver.md`](docs/study-0.6.0-kinematic-driver.md); earlier design baselines remain available in the `docs/` directory. [`docs/api.md`](docs/api.md) documents the implemented public API.

## Installation

Install Kimech from PyPI:

```bash
pip install kimech
```

For plotting, animation, and GIF support:

```bash
pip install "kimech[viz]"
```

For local development, clone the repository and use an editable install:

```bash
pip install -e ".[dev,viz,docs]"
pytest
```

## Quick start

The following builds a four-bar linkage and solves a differential kinematic sweep through the generic API:

```python
import numpy as np

from kimech import KinematicDriver, Mechanism, solve

mechanism = Mechanism("four_bar")
ground = mechanism.ground

ground_a = ground.add_point("A", (0.0, 0.0))
ground_d = ground.add_point("D", (0.30, 0.0))

crank = mechanism.add_link("crank")
crank_a = crank.add_point("A", (0.0, 0.0))
crank_b = crank.add_point("B", (0.08, 0.0))

coupler = mechanism.add_link("coupler")
coupler_b = coupler.add_point("B", (0.0, 0.0))
coupler_c = coupler.add_point("C", (0.22, 0.0))
point_p = coupler.add_point("P", (0.10, 0.05))

rocker = mechanism.add_link("rocker")
rocker_c = rocker.add_point("C", (0.0, 0.0))
rocker_d = rocker.add_point("D", (0.18, 0.0))

input_joint = mechanism.revolute(ground_a, crank_a, name="input")
mechanism.revolute(crank_b, coupler_b)
mechanism.revolute(coupler_c, rocker_c)
mechanism.revolute(rocker_d, ground_d)

initial_guess = {
    crank: (0.0, 0.0, 0.8),
    coupler: (0.05, 0.06, 0.2),
    rocker: (0.30, 0.0, 2.2),
}
input_positions = np.linspace(0.8, 1.3, 60)

driver = KinematicDriver(
    input_joint,
    position=input_positions,
    velocity=1.5,
    acceleration=0.0,
)

solution = solve(
    mechanism,
    driver=driver,
    initial_guess=initial_guess,
)

positions = solution.point_positions(point_p)
velocities = solution.point_velocities(point_p)
accelerations = solution.point_accelerations(point_p)
```

`KinematicDriver` packages the prescribed natural coordinate of a revolute or prismatic joint together with optional physical velocity and acceleration data. `position` may be a scalar or a one-dimensional sequence; scalar differential values are broadcast across sweeps. `solve()` always returns a `KinematicSolution`, so a scalar driver position produces a solution of length one and `solution[0]` returns its `Configuration`.

Position-only solving remains valid by constructing the driver with `position` only. An optional `time=` array may associate each requested sample with a physical instant; it does not control continuation or trigger numerical differentiation. Position sweeps use predictor-corrector continuation with warm-start fallback and bounded adaptive subdivision when recovery is needed. Solutions also expose structured numerical diagnostics through `solution.diagnostics`.

For example:

```python
diagnostics = solution.diagnostics

condition = diagnostics.condition_numbers
sigma_min = diagnostics.min_singular_values
strategies = diagnostics.strategies
subdivisions = diagnostics.subdivision_counts
residuals = diagnostics.residual_norms
```

These diagnostics describe the selected driven solve formulation. A configuration may therefore be regular for one chosen driver coordinate and singular for another.

Topology can be inspected independently of solved geometry:

```python
topology = mechanism.topology()
print(topology.cycle_rank)
print(topology.connected_components)
```

Driver-coordinate sensitivity is an explicit downstream analysis:

```python
from kimech import driver_sensitivity

sensitivity = driver_sensitivity(solution)
dq_du = sensitivity.coordinate_derivatives
point_dp_du = sensitivity.point_position_derivatives(point_p)
```

Sensitivity is with respect to the prescribed driver coordinate; it is not a time derivative.

## Visualization

Visualization remains presentation-only. When `solution.time` is available it records physical sample times, while animation `fps` still controls playback only:

```python
import matplotlib.pyplot as plt
from kimech.visualization import animate, plot_topology

animation = animate(solution, fps=30)

# Structural connectivity, independent of physical geometry
fig, ax = plot_topology(mechanism)

# Optional progressive trace for one or more mechanism points
animation = animate(solution, fps=30, trace_points=[point_p])
plt.show()
```

## Examples

The example set separates **motion/geometry** from **kinematic analysis** and validation:

```text
examples/
├── four_bar.py
├── four_bar_analysis.py
├── slider_crank.py
├── slider_crank_analysis.py
└── slider_crank_analysis_comparison.py
```

- [`examples/four_bar.py`](examples/four_bar.py) and [`examples/slider_crank.py`](examples/slider_crank.py) focus on position solving and animation.
- [`examples/four_bar_analysis.py`](examples/four_bar_analysis.py) plots rocker angle, angular velocity, angular acceleration, and coupler-point speed/acceleration magnitude versus the prescribed crank angle.
- [`examples/slider_crank_analysis.py`](examples/slider_crank_analysis.py) plots slider displacement, velocity, and acceleration versus crank angle and demonstrates reconstruction of the same state with the prismatic coordinate prescribed instead.
- [`examples/slider_crank_analysis_comparison.py`](examples/slider_crank_analysis_comparison.py) compares Kimech's slider displacement, velocity, and acceleration with the independent closed-form slider-crank solution and reports the maximum absolute errors.

See [`CHANGELOG.md`](CHANGELOG.md) for release changes and intentional breaking renames.
