Skip to main content

Experimental Python-owned Flexiv RT torque-control shim

Project description

aioflexiv

aioflexiv logo

PyPI version License

aioflexiv is an experimental asyncio-based Python library for controlling Flexiv robots from a Python-owned real-time torque loop. It combines flexivrdk for Flexiv robot access, a small pybind11 shim for RT joint-torque mode, and Ruckig for smooth joint-space trajectory generation.

The library is designed for research workflows that need direct torque control, joint impedance control, operational-space control, and minimal ceremony around async Python experiments.

If you want the same kind of Python control workflow for a Franka FR3 robot, check out aiofranka.

This is a hardware-control experiment. Keep clear of the robot, verify your limits, and be ready to stop the robot before running any command or script.

Installation

Install from PyPI:

pip install aioflexiv

Or install this repository for development:

git clone https://github.com/Improbable-AI/aioflexiv.git
cd aioflexiv
pip install -e .

The install pulls flexivrdk==1.9.1, mujoco, numpy, and ruckig, builds the pybind11 RT shim from source, and installs the aioflexiv console command. PyPI releases are source distributions, so installation requires a local C++17 compiler.

Quick Start

Run the torque loop in-process with asyncio:

  • Single script: no separate server process
  • Direct access: controller state and commands stay in Python
  • Async discipline: avoid blocking calls after controller.start() because the background torque loop must keep stepping

Pass the serial explicitly on first use. After a successful connection, aioflexiv stores it in ~/.config/aioflexiv/config.json; later scripts can use FlexivController() or FlexivController(None) to reuse the latest serial. Pass tool="<TOOL_NAME>" to switch the robot's active Flexiv tool before the real-time torque loop starts. When the MuJoCo model backend is active, aioflexiv also reads the active Flexiv tool payload and injects it into the MuJoCo model used for OSC dynamics.

Use FlexivController("mujoco") to run the same controller against the bundled MuJoCo Flexiv scene instead of hardware. The simulator opens a passive MuJoCo viewer when the platform supports it and advances physics at 1 kHz by default. Import ToolPayload from aioflexiv and pass mujoco_tool_payload=ToolPayload(...) to test a simulated payload.

import asyncio
import numpy as np
from aioflexiv import FlexivController

async def main():
    controller = FlexivController("<ROBOT_SN>", tool="MyGripper")

    await controller.start()
    try:
        await controller.move()

        controller.switch("impedance")
        controller.kp = np.ones(controller.dof) * 80.0
        controller.kd = np.ones(controller.dof) * 4.0
        controller.set_freq(50)

        q0 = controller.initial_qpos.copy()
        for cnt in range(250):
            target = q0.copy()
            target[0] += 0.05 * np.sin(cnt / 50.0)
            await controller.set("q_desired", target)
    finally:
        await controller.stop()

if __name__ == "__main__":
    asyncio.run(main())

CLI Reference

aioflexiv status [ROBOT_SN] [--network-interface IP] [--events N] [--verbose]
aioflexiv tool status [ROBOT_SN] [--json]
aioflexiv tool list [ROBOT_SN] [--json]
aioflexiv tool load TOOL [ROBOT_SN]
aioflexiv tool calibrate TOOL [ROBOT_SN] [--tcp-location X Y Z QW QX QY QZ] [--load]

status

Show Flexiv robot connection, system, state, tool, device, and recent event information.

aioflexiv status <ROBOT_SN>

After a successful connection, aioflexiv stores the latest serial number in ~/.config/aioflexiv/config.json. Later CLI runs can omit ROBOT_SN and reuse that saved serial:

aioflexiv status

Use --network-interface to whitelist one or more local IPv4 interfaces while searching for the specified robot:

aioflexiv status <ROBOT_SN> --network-interface 192.168.2.10

tool

Manage Flexiv tool payloads through the official flexivrdk.Tool API. Tool changes and payload calibration require the robot to be in IDLE, so stop any running torque controller first.

Show the active tool:

aioflexiv tool status <ROBOT_SN>

List saved tools and their payload parameters:

aioflexiv tool list <ROBOT_SN>

Load a saved tool on the robot. Future torque loops use the robot's active tool for Flexiv-side gravity compensation, and the MuJoCo OSC backend reads that same active tool payload at startup:

aioflexiv tool load MyGripper <ROBOT_SN>

Interactively calibrate payload mass, center of mass, and inertia, then save the result as a Flexiv tool:

aioflexiv tool calibrate MyGripper <ROBOT_SN>

Flexiv's calibration result does not contain a valid TCP pose. For an existing tool, aioflexiv preserves the current TCP. For a new tool, it defaults to the flange TCP unless you provide one:

aioflexiv tool calibrate MyGripper <ROBOT_SN> \
  --tcp-location 0.0 0.0 0.12 1.0 0.0 0.0 0.0 \
  --load

Core Concepts

Torque Loop

FlexivController.start() starts the Flexiv RT joint-torque bridge and launches an asyncio task that repeatedly computes and sends torque commands. Stop with await controller.stop() in a finally block so the robot exits torque mode cleanly.

Safety Limits

Torque clipping is enabled by default and uses Flexiv RDK RobotInfo::tau_max. No torque-rate limit is guessed by default. Set controller.torque_diff_limit = <Nm/s> if you want an additional user-space slew limit.

By default, FlexivController(ext_offset=True) records the initial tau_ext when the torque loop starts and sends commanded_torque - initial_tau_ext to the robot. Pass ext_offset=False to disable this compensation.

Rate Limiting

Use set_freq() to pace command updates:

controller.set_freq(50)

for target in trajectory:
    await controller.set("q_desired", target)

Force/Torque Sensing

For compatible robots with an F/T sensor, controller.robot.info["has_FT_sensor"] reports availability and controller.state exposes 6D wrench readings as NumPy arrays:

state = controller.state
raw_flange_wrench = state["ft_sensor_raw"]          # [fx, fy, fz, mx, my, mz]
tcp_wrench = state["ext_wrench_in_tcp"]             # [N, N, N, Nm, Nm, Nm]
world_wrench = state["ext_wrench_in_world"]

Controllers

1. Joint Impedance

Joint-space spring-damper control:

controller.switch("impedance")
controller.kp = np.ones(controller.dof) * 80.0
controller.kd = np.ones(controller.dof) * 4.0
await controller.set("q_desired", target_qpos)

Use case: compliant joint-space holding and trajectory tracking.

2. Operational Space

End-effector pose control. By default the library computes end-effector pose, Jacobian, mass matrix, Coriolis, and gravity terms from the bundled MuJoCo Flexiv model, tracking the attachment_site MuJoCo site. On hardware, the active Flexiv tool payload is loaded into a temporary MuJoCo model before compilation, so OSC uses the same attached mass properties that Flexiv uses for tool gravity compensation:

controller = FlexivController("<ROBOT_SN>")
await controller.start()

controller.switch("osc")
controller.ee_kp = np.array([150, 150, 150, 20, 20, 20], dtype=float)
controller.ee_kd = np.array([20, 20, 20, 3, 3, 3], dtype=float)

target = controller.initial_ee.copy()
target[2, 3] += 0.03
await controller.set("ee_desired", target)

Use case: Cartesian holding and small task-space motions.

If automatic model selection cannot read RobotInfo.model_name, pass mujoco_model_path="models/flexiv_rizon4/flexiv_rizon4.xml" or the matching Rizon4S XML explicitly. Pass model_backend="rdk" only when you explicitly want to compare against Flexiv RDK model data.

3. Direct Torque

Direct user torque commands:

controller.switch("torque")
controller.set_freq(10)
await controller.set("torque", np.zeros(controller.dof))

Use case: low-level experiments where you want to own the torque command.

4. Ruckig Moves

Point-to-point joint motions are generated with Ruckig and tracked through the same Python torque loop:

await controller.move()
await controller.move([0.0, -0.7, 0.0, 1.57, 0.0, 0.7, 0.0])

Examples

python examples/00_move.py mujoco
python examples/01_joint_impedance.py <ROBOT_SN>
python examples/02_osc_hold.py <ROBOT_SN>

Use mujoco in place of <ROBOT_SN> in the controller examples to open the MuJoCo simulator. examples/02_osc_hold.py also accepts --model-backend rdk when connected to real hardware for comparison against the Flexiv RDK model path.

License

Apache-2.0. See LICENSE.

Citation

If you use this library in your research, please cite:

@software{aioflexiv,
  author = {Park, Younghyo},
  title = {aioflexiv: Asyncio-based Flexiv Robot Control},
  year = {2026},
  url = {https://github.com/Improbable-AI/aioflexiv}
}

Acknowledgments

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aioflexiv-0.2.0.tar.gz (4.8 MB view details)

Uploaded Source

File details

Details for the file aioflexiv-0.2.0.tar.gz.

File metadata

  • Download URL: aioflexiv-0.2.0.tar.gz
  • Upload date:
  • Size: 4.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for aioflexiv-0.2.0.tar.gz
Algorithm Hash digest
SHA256 5ccad2914f532858371c6002fe83e108e989af15a1197e6d52376f213c9ce7ca
MD5 36d5c41b02305f8e708ad91d9c06d6e1
BLAKE2b-256 be891c10818f3b0927cf53c49be1f8ce58c9899b31239079f8fabe98d9f7d531

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page