Metadata-Version: 2.4
Name: openflex-driver
Version: 1.0.0
Summary: Python SDK for OpenFlex robotic arm control via CAN bus
Author-email: Wei Lindong <weilindong02@gmail.com>
License-Expression: CC-BY-NC-SA-4.0
Project-URL: Homepage, https://www.openarmx.com
Project-URL: Documentation, https://docs.openarmx.com
Project-URL: Repository, https://www.openarmx.com
Project-URL: Issues, https://www.openarmx.com
Keywords: robotics,can-bus,motor-control,openflex,openarmx
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: python-can>=4.0.0
Requires-Dist: PyYAML>=5.4.0
Requires-Dist: numpy>=1.21.0
Requires-Dist: pin>=2.6.0
Dynamic: license-file

# OpenFlex Driver

> **Developed by Chengdu Changshu Robotics Co., Ltd.**

OpenFlex Driver is the Python SDK for OpenFlex / OpenArmX full-body robot control over CAN bus. It provides high-level interfaces for dual arms, head, lift column, and swerve chassis, while also exposing lower-level motor, CAN, calibration, and teleoperation utilities for integration and research workflows.

The package is designed for Linux robots using SocketCAN-compatible CAN adapters and Robstride / CANopen motor controllers.

## Features

- Dual-arm control through `Arm` and `Robot`
- Head control with yaw / pitch joints
- Lift column control over CANopen CiA402
- Four-wheel swerve chassis control with steering and driving modules
- MIT and CSP motor control modes
- Motor enable / disable, mode switching, status reading, zero calibration
- CAN interface discovery and setup helpers
- Automatic and passive zero calibration utilities
- VR teleoperation / IK interface based on Pinocchio
- Binary wheel build support with Cython-compiled internal modules

## Supported Components

| Component | Interface | Default CAN | Notes |
|---|---|---:|---|
| Right arm | `Arm`, `Robot.right_arm` | `can0` | Robstride arm motors, IDs 1-8 |
| Left arm | `Arm`, `Robot.left_arm` | `can1` | Robstride arm motors, IDs 1-8 |
| Head | `Head`, `Robot.head` | `can2` | Yaw ID 1, pitch ID 2 |
| Lift column | `Column`, `Robot.column` | `can3` | CANopen CiA402 node, default ID 16 |
| Chassis driving | `Chassis` | `can4` | UM wheel motors, default IDs 1-4 |
| Chassis steering | `Chassis` | `can5` | RS steering motors, default IDs 5-8 |

## Installation

Install from PyPI:

```bash
pip install openflex-driver
```

For local development:

```bash
git clone <your-repository-url>
cd openflex_driver
python3 -m pip install -e .
```

## Requirements

- Linux with SocketCAN support
- Python >= 3.9
- `python-can >= 4.0.0`
- `PyYAML >= 5.4.0`
- `numpy >= 1.21.0`
- `pin >= 2.6.0` for teleoperation / IK functionality
- Cython is required when building wheels from source

## CAN Setup

The driver can try to enable CAN interfaces automatically when `auto_enable_can=True`. For manual setup, use standard SocketCAN commands:

```bash
sudo ip link set can0 up type can bitrate 1000000
sudo ip link set can1 up type can bitrate 1000000
sudo ip link set can2 up type can bitrate 1000000
sudo ip link set can3 up type can bitrate 1000000
sudo ip link set can4 up type can bitrate 1000000
sudo ip link set can5 up type can bitrate 1000000
```

Check available CAN interfaces:

```python
from openflex_driver import get_available_can_interfaces, verify_can_interface

print(get_available_can_interfaces())
print(verify_can_interface("can0"))
```

## Quick Start

### Single Arm

```python
from openflex_driver import Arm

arm = Arm(can_channel="can0", side="right")

try:
    arm.enable_arm_motors()
    arm.set_mode("mit")
    arm.move_to_mit(
        motor_id=1,
        position=0.3,
        velocity=0.0,
        torque=0.0,
        kp=20.0,
        kd=1.0,
    )
    status = arm.get_motor_status(motor_id=1)
    print(status)
finally:
    arm.disable_arm_motors()
    arm.close()
```

### Dual Arms and Full Robot

```python
from openflex_driver import Robot

robot = Robot(
    right_arm_can="can0",
    left_arm_can="can1",
)

try:
    robot.enable_right_arm()
    robot.enable_left_arm()
    robot.right_arm.set_mode("mit")
    robot.left_arm.set_mode("mit")

    robot.move_to_mit_right_arm(
        motor_id=2,
        position=0.2,
        kp=20.0,
        kd=1.0,
    )
    robot.move_to_mit_left_arm(
        motor_id=2,
        position=0.2,
        kp=20.0,
        kd=1.0,
    )

    robot.show_arms_status()
finally:
    robot.disable_right_arm()
    robot.disable_left_arm()
    robot.shutdown()
```

To manage optional full-body components from `Robot`, pass `head_can`, `column_can`, `steering_can`, and `driving_can`, then initialize each component according to your hardware startup sequence.

## Component Examples

### Head

```python
from openflex_driver import Head, JOINT_YAW, JOINT_PITCH

head = Head(can_channel="can2")

try:
    head.connect()
    head.enable()
    head.move_to_mit(motor_id=JOINT_YAW, position=0.2)
    head.move_to_mit(motor_id=JOINT_PITCH, position=-0.1)
    print(head.get_joint_status())
finally:
    head.disable()
    head.disconnect()
```

### Lift Column

```python
from openflex_driver import Column

column = Column(can_interface="can3", node_id=16)

try:
    column.connect()
    column.enable()
    column.switch_to_position_mode()
    column.move_to_user_position(0.15)
    print(column.get_status())
    column.stop_motion()
finally:
    column.disable()
    column.close()
```

### Swerve Chassis

```python
from openflex_driver import Chassis

chassis = Chassis(steering_can="can5", driving_can="can4")

try:
    chassis.connect()
    chassis.enable_all()

    # vx: forward m/s, vy: left m/s, omega: counter-clockwise rad/s
    chassis.set_chassis_velocity(vx=0.2, vy=0.0, omega=0.0)
    chassis.stop_motion()

    print(chassis.get_status_table())
finally:
    chassis.disable_all()
    chassis.close()
```

### Motor Inventory

```python
from openflex_driver import position_motors, velocity_motors

for motor in position_motors():
    print(motor.component, motor.name, motor.can_channel, motor.motor_id)

for motor in velocity_motors():
    print(motor.component, motor.name, motor.can_channel, motor.motor_id)
```

## Public API Overview

Main classes:

- `Arm`: one arm controller
- `Robot`: full robot controller that owns left / right arms and optional head, column, chassis
- `Head`: two-axis head controller
- `Column`: lift column controller
- `Chassis`: swerve chassis controller
- `MotorConfigLoader`: load motor configuration and limits

Common helper APIs:

- CAN utilities: `get_available_can_interfaces`, `verify_can_interface`, `enable_can_interface`, `disable_can_interface`
- Motor management: `enable_motor`, `disable_motor`, `set_control_mode`, `get_motor_status_readonly`
- Motor control: `mit_motion_control`, `csp_motion_control`, `csp_set_speed_limits`
- Calibration: `auto_calibrate_zero`, `move_to_limit`, `move_to_position_smooth`
- Chassis kinematics: `ChassisSpeeds`, `SwerveDriveKinematics`, `default_module_positions`
- Teleoperation: `TeleopConfig`, `TeleopInputFrame`, `OpenArmTeleopController`, `PinocchioTeleopCore`

## Build From Source

The package compiles internal `_lib` modules into `.so` files during wheel / source distribution builds.

For local builds on a machine that already has build dependencies installed:

```bash
python3 -m build --no-isolation
```

For a clean isolated build, network access is required so Python can install build dependencies declared in `pyproject.toml`:

```bash
python3 -m build
```

Inspect generated wheels:

```bash
unzip -l dist/openflex_driver-*.whl
```

The helper scripts `build_so.py` and `clean_so.py` are local build tools and are excluded from the published source distribution.

## Publishing

This repository includes GitHub Actions workflow support under `.github/workflows/build.yml`.

- Push to `main`, `master`, or `linux_*`: build wheels and publish to TestPyPI when `TEST_PYPI_API_TOKEN` is configured.
- Push a tag like `v1.2.0`: build wheels and publish to PyPI when `PYPI_API_TOKEN` is configured.
- Supported build matrix: Python 3.9, 3.10, 3.11, 3.12 on `x86_64` and `aarch64`.

Before a release:

```bash
# Update version in pyproject.toml and src/openflex_driver/__init__.py
git add .
git commit -m "Release v1.2.0"
git tag -a v1.2.0 -m "Release version 1.2.0"
git push
git push origin v1.2.0
```

## Safety Notes

- Always verify CAN interfaces and motor IDs before enabling motors.
- Start with low velocity, low torque, and conservative `kp` / `kd` values.
- Keep the robot clear of people and obstacles during calibration and first motion tests.
- Run active zero calibration only when mechanical limits and emergency stop behavior are verified.
- Disable motors and close CAN connections when control is finished.

## License

This project is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

Commercial use requires a separate license from Chengdu Changshu Robotics Co., Ltd. See [LICENSE](LICENSE) for details.

## Contact Us

### Chengdu Changshu Robotics Co., Ltd.

| Contact | Information |
|---------|-------------|
| 📧 Email | wangxunyue1@163.com <br> openarmrobot@gmail.com |
| 📱 Phone/WeChat | +86-17746530375 |
| 🌐 Website | <https://openarmx.com/> |
| 🌐 Documentation | <http://docs.openarmx.com/> |
| 📍 Address | Xiqing District, Tianjin・Daochao Robotics Experience Center (Tomorrow City)・Tianjin Humanoid Robot Center |
| 👤 Contact Person | Mr. Wang |

Copyright © 2025 Chengdu Changshu Robotics Co., Ltd. All Rights Reserved.
