Metadata-Version: 2.4
Name: marinholab-sas-core
Version: 26.9.15
Summary: Python bindings for the ROS-free SmartArmStack C++ core (marinholab_sas_core).
Author-email: "Murilo M. Marinho" <murilomarinho@ieee.org>
Maintainer-email: "Murilo M. Marinho" <murilomarinho@ieee.org>
License: LGPL-3.0-or-later
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Operating System :: POSIX :: Linux
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy
Requires-Dist: dqrobotics>=26.4.0a7
Requires-Dist: marinholab-solvers-qpoases
Requires-Dist: termcolor
Dynamic: license-file

# marinholab-sas-core

> Python bindings for the ROS-free SmartArmStack C++ core.
>
> This repository wraps
> [MarinhoLab/sas_cpp](https://github.com/MarinhoLab/sas_cpp)
> (the pure-C++ part of
> [SmartArmStack/sas_core](https://github.com/SmartArmStack/sas_core)) with
> pybind11, exposing it to Python as the `marinholab.sas.core` package.
>
> More information about SmartArmStack is available in
> [smartarmstack.github.io](https://smartarmstack.github.io/).

## Contents

- `marinholab/sas/core/` — the Python package.
  - `_core.*` — compiled pybind11 extension (the C++ bindings live in `src/`).
  - `modeling/` — kinematic modeling bindings (re-exported from `_core`).
  - `papers/` — reference implementations from published work.
    - `papers/icra2019/` — the task-space `Controller` (RCM + joint-limit
      constraints as a QP) from "A Unified Framework for the Teleoperation of
      Surgical Robots in Constrained Workspaces" (ICRA 2019).
  - `example_*.py` — example scripts (also installed as commands).
- `src/` — the C++ binding sources (ported from `SmartArmStack/sas_core`).
- `submodules/sas_cpp` — the C++ core (git submodule, consumed via CMake).
- `submodules/dqrobotics_cpp` — the dqrobotics C++ library (git submodule,
  pinned to the commit the required `dqrobotics` Python release is built from).
- `submodules/pybind11` — pybind11 (git submodule, pinned to v3.0.4).
- `docker/` — `ubuntu:noble` build environment and full test pipeline.

The C++ core depends on **Eigen3** and **dqrobotics**. dqrobotics is compiled
from the `submodules/dqrobotics_cpp` submodule and linked statically into the
extension module, together with the C++ core, so no dqrobotics library needs
to be installed. The Python package additionally depends on the `dqrobotics`
Python package, which registers the dual-quaternion and robot-model types the
bindings expose (pybind11 shares them between the two extension modules, so
the submodule is kept at the same dqrobotics/cpp commit as that release).

## Installation

From PyPI, with wheels for Python 3.10–3.14 on Linux (x86_64, aarch64), macOS
(arm64, 14.0 or later) and Windows (x86_64):

```bash
pip install marinholab-sas-core
```

The wheels match the Python versions that `dqrobotics` publishes wheels for,
in its pre-releases, which the requirement `dqrobotics>=26.4.0a7` selects.

From source:

```bash
git clone --recursive https://github.com/MarinhoLab/sas_py.git
cd sas_py
pip install . --no-build-isolation
```

Building requires `cmake` (>= 3.16), `ninja`, a C++17 compiler and Eigen3.
On Debian/Ubuntu:

```bash
sudo apt install build-essential g++ cmake ninja-build python3-dev libeigen3-dev
```

On macOS, with Eigen from Homebrew:

```bash
brew install eigen cmake ninja
CMAKE_ARGS="-DCMAKE_PREFIX_PATH=$(brew --prefix)" pip install . --no-build-isolation
```

On Windows, Eigen comes from vcpkg, expected at `C:/vcpkg`
(`vcpkg install eigen3:x64-windows`).

## Usage

```python
from marinholab.sas.core import (
    Clock,
    Statistics,
    RobotDriver,
    ShutdownSignaler,
)

# High-resolution sampling clock
clock = Clock(0.01)          # 10 ms sampling period
clock.init()
for _ in range(100):
    clock.update_and_sleep()
print(clock.get_statistics(Statistics.Mean, Clock.TimeType.Computational))

# Subclass RobotDriver to drive hardware
class MyDriver(RobotDriver):
    def __init__(self, ss):
        super().__init__(ss)
    def get_joint_positions(self):
        return np.zeros(6)
    def set_target_joint_positions(self, target):
        ...
    def connect(self):
        ...
    def disconnect(self):
        ...
    def initialize(self):
        ...
    def deinitialize(self):
        ...
```

### Kinematic modeling

```python
import numpy as np
from dqrobotics import DQ
from marinholab.sas.core import SerialManipulatorSimulatorFriendly

# 3 revolute joints about X, Y, Z with zero per-joint offsets.
arm = SerialManipulatorSimulatorFriendly(
    offset_before=[DQ([1]), DQ([1]), DQ([1])],
    offset_after=[DQ([1]), DQ([1]), DQ([1])],
    actuation_types=[
        SerialManipulatorSimulatorFriendly.ActuationType.RX,
        SerialManipulatorSimulatorFriendly.ActuationType.RY,
        SerialManipulatorSimulatorFriendly.ActuationType.RZ,
    ],
)
q = np.array([0.1, -0.2, 0.3])
x = arm.raw_fkm(q, 2)                 # dual-quaternion pose of the end-effector
J = arm.raw_pose_jacobian(q, 2)       # 8 x 3 pose Jacobian
```

The examples are installed as commands:

- `sas_core_clock_example` — a 10 ms `Clock` with timing statistics.
- `sas_core_clock_sched_fifo_example` — a 1 ms `Clock` under `SCHED_FIFO`.
- `sas_core_robot_driver_subclass_example` — subclass `RobotDriver` in Python
  and exercise the trampoline (connect / initialize / targets / limits).

## Versioning

The version is computed from git tags at build time by
`setuptools-git-versioning`. A monthly version tag of the form `YY.MM`
(e.g. `26.09`) plus the number of commits since that tag yields a rolling
`YY.MM.NN` version (e.g. `26.09.3`), mirroring `MarinhoLab/sas_cpp`.
An untagged checkout builds as `0.0.1` (a development version).

## Testing

A full build + test pipeline runs in an `ubuntu:noble` container:

```bash
cd docker
docker compose run --rm marinholab_sas_core
```

## License

See [`LICENSE`](LICENSE) for details (LGPLv3).
