dynibo 0.5.2

Tree-structured robot kinematics and dynamics with runtime-size workspace APIs
Documentation
# Errors and Thread Safety

Bindings expose the same broad error categories through language-appropriate
mechanisms.

## Error mapping

| Condition | Rust | Python | C++ | C |
|---|---|---|---|---|
| Invalid argument, handle, or length | `Error` with `InvalidInput` category | `ValueError` | `dynibo::Error` | `DYNIBO_STATUS_INVALID_ARGUMENT` |
| URDF/model failure | `Error` with `Model` category | `ModelError` | `dynibo::Error` | `DYNIBO_STATUS_MODEL_ERROR` |
| IK numerical failure/non-convergence | `Error` with `Solver` category | `SolverError` | `dynibo::Error` | `DYNIBO_STATUS_SOLVER_ERROR` |
| Panic caught at ABI boundary | Not applicable to native Rust calls | `PanicError` | `dynibo::Error` | `DYNIBO_STATUS_PANIC` |

Do not branch on human-readable error text. Rust exposes `ErrorCategory`, C has
stable status values, Python has exception types, and C++ `Error::status()`
retains the C status.

## C error messages

`dynibo_last_error_message()` returns a thread-local string. It remains valid
until the next fallible dynibo call on that thread; a successful call clears it.
Copy the string when it must outlive the next call.

## Thread-safety rules

- Rust `RobotModel` is immutable and can be shared across threads without a lock.
- Immutable model queries may be read when no thread is changing a fixed
  `Robot` base frame.
- Each Rust `Robot` or `FloatingRobot` owns one mutable workspace; calculation
  methods require mutable access. Use `fork()` to obtain an independent
  instance for each concurrent calculation.
- C callers create one typed workspace per concurrent calculation:
  `DyniboWorkspace` for fixed and `DyniboFloatingWorkspace` for floating.
- Python serializes methods on one `Robot` or `FloatingRobot`; `fork()` creates
  independent instances for parallel native calls while sharing model data.
- The C++ wrapper has no internal lock; use one `dynibo::Robot` or
  `dynibo::FloatingRobot` per worker.
- Never destroy or move an object while another thread is using its handles.

## Recovery

Joint state, generalized forces, loads, and tool poses must contain finite
values. Rejected inputs leave caller-owned calculation output buffers unchanged.
Overflow while accumulating otherwise finite loads is a solver error. Outputs
are unspecified after a solver error and must only be consumed after success.

Argument and solver errors do not invalidate a robot or workspace. Correct the
input and call again. A caught ABI panic is reported instead of unwinding across
the foreign-language boundary, but it indicates an unexpected internal failure;
record the message and dynibo version before deciding whether to continue.