Experimental Python-owned Flexiv RT torque-control shim
Project description
aioflexiv
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 this repository:
pip install .
Or for development:
git clone https://github.com/Improbable-AI/aioflexiv.git
cd aioflexiv
pip install -e .
The install pulls flexivrdk==1.9.1, numpy, and ruckig, builds the
pybind11 RT shim, and installs the aioflexiv console command.
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.
import asyncio
import numpy as np
from aioflexiv import FlexivController
async def main():
controller = FlexivController("<ROBOT_SN>")
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
The CLI currently focuses on status inspection.
aioflexiv status [ROBOT_SN] [--network-interface IP] [--events N] [--verbose]
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
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 using Flexiv RDK model data:
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.
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/01_joint_impedance.py <ROBOT_SN>
python examples/02_osc_hold.py <ROBOT_SN>
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
- Built on Flexiv RDK
- Trajectory generation with Ruckig
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
File details
Details for the file aioflexiv-0.0.1.tar.gz.
File metadata
- Download URL: aioflexiv-0.0.1.tar.gz
- Upload date:
- Size: 1.1 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5f59c251931d040cf81feeda199c3a7a2ae050f993447da3fd084bf57dece69e
|
|
| MD5 |
d4438a2a05a2e00ec3647c27714eef14
|
|
| BLAKE2b-256 |
a312dd1a08a9fb4ce873db3f9d26e83ab08ccf222adbc6268b446fff2453f621
|