franka-rs

A Rust client for the Franka Control Interface

Send targets.
Get smooth motion.

Control a Franka FR3 or Panda from Rust or Python. Run on a realtime PC, or let a Raspberry Pi 5 handle the robot while you work from your laptop. Your application sends goals. Rust runs the control loop, 1,000 times a second.

FR3 + Panda / Native Rust / Python ready / Apache-2.0

Your application here. Control beside the arm.

The core library, franka-rs, turns goals into smooth motion and communicates directly with the robot. No libfranka or C++ to install.

Want to work from your laptop? Put franka-node on a Pi 5. It runs the trajectory generator and impedance controller there. Zenoh is just the messaging layer carrying goals and state between your laptop and the Pi. The Pi talks to the robot over wired Ethernet. No separate Zenoh router is needed.

Targets arrive at any rate. One continuous command leaves for the robot.
Laptop to Raspberry Pi 5 to robot A laptop sends targets over Zenoh to a Raspberry Pi 5 running franka-node. The Pi runs trajectory generation and impedance control at 1 kHz and drives the robot over a wired FCI link. Optional branches from the Pi: a camera node, the gripper, and a Rerun recording. Laptop your policy, teleop, script any OS, any language Zenoh targets in, state out Raspberry Pi 5 franka-node · PREEMPT_RT trajectory generation impedance control · 1 kHz wired FCI 1 kHz UDP Robot FR3 or Panda version negotiated camera node Rerun recording gripper dashed: optional
The laptop never touches the 1 kHz loop. Direct Rust and Python on the realtime host stay first class; the Pi is for commanders that are not on it.
  • Your application sets the goal. A script, a policy, or a device integration sends position or joint targets.
  • The Pi runs the control algorithm. franka-node uses franka-rs to generate motion and calculate torque commands every millisecond.
  • Add peripherals when needed. Cameras and recording run alongside control. The core library also works on its own.

Three ways in

Local, from Rust or Python

Your program runs on the Linux machine wired to the robot. Install the library, prepare the realtime host, and write your application.

Rust setup · Python setup

Remote, through a Pi

A Raspberry Pi 5 next to the robot runs franka-node. Your laptop, on any OS, installs a small Python client or speaks the documented wire layout from any language.

Pi setup · Full guide

Not sure? Choose your setup walks through the decision. See how the pieces fit →

Get started

Choose where your application runs. The machine wired to a real robot needs Linux realtime setup. A laptop that talks to the Pi needs ordinary Python.

Rust, on the realtime host

In an existing Cargo project. Rust 1.89 or newer; the library is imported as franka. Build with --release: a debug build of a stiff torque controller misses cycles.

cargo add franka-rs

Next: installation details, realtime setup, then your first program.

Python, on the realtime host

Use Python 3.9 or newer in a virtual environment on the Linux realtime host. Rust runs the control loop underneath your Python program.

python -m pip install franka-rs
import franka
robot = franka.Robot("172.16.0.2")
print(robot.read_once().q)  # read joint positions; no motion

The wheel is franka-rs, the import name franka. Prepare the robot connection first, then follow the examples in From Python.

A laptop and a Raspberry Pi 5

On the laptop, use a Python virtual environment:

python -m pip install franka-node-client
import franka_node
with franka_node.Node("tcp/<pi-host>:7447") as node:
    print(node.status("pi"))  # node name from the Pi guide; no motion

On the Pi, a Raspberry Pi 5 with a PREEMPT_RT kernel, wired to the robot, with Rust installed:

cargo install franka-node --locked

Replace <pi-host> with your Pi’s address after starting the node. Use the node and the client of the same version. Configuration and the first motion: Raspberry Pi guide and Serve arms over Zenoh.

The simulator

Watch the robot move: start the desktop viewer →

Start the simulator with Docker on Linux. Then use a Rust or Python client with realtime checks off. No robot is needed.

docker run --rm --network host ghcr.io/barisyazici/franka-sim:1.1.7

In a second terminal, from a source checkout with Rust installed:

FRANKA_REALTIME=ignore cargo run --release --example echo_robot_state -- 127.0.0.1

One container at a time: the ports are fixed by the protocol. Python uses the same environment variable. A node uses realtime = "ignore" in its TOML configuration. Divergences from the real arm are listed in Without a robot.

Direct Python uses franka-rs (import franka). Remote Python uses franka-node-client (import franka_node). They are different packages.

Optional, each one page

Gripper

Open, close, and grasp with a Franka Hand. Use it directly or through the node. Other grippers need a driver integration.

Use the gripper

Cameras

Stream USB cameras with franka-cam, a separate process beside the node. Cameras on the same host share its clock.

Peripherals

Recording

Enable recording to inspect robot motion and targets in Rerun. Give arms and cameras an episode name to view their recordings together.

Record and replay a run

Quest teleoperation

Drive an arm served by the node from a Meta Quest controller. The bridge reads the headset, the client clutches on the grip and clamps every target against the arm's measured pose.

Teleoperate with a Quest

Live tuning

Change impedance gains, budgets and feedforward on a running Cartesian session from a browser panel, within the node's own bounds. Nothing restarts.

Tune a running controller

What will you build?

Policies

Run your model on a GPU workstation and send its goals to the robot. The realtime host handles smooth target tracking between updates.

Teleoperation

Drive a node-served arm from a Meta Quest controller with the included franka-vr-teleop stack. For another joystick or tracker, your application turns its input into targets for the arm.

Recorded experiments

Record arm state, commands, and optional camera frames. Replay what happened and compare targets with the resulting motion.

The Quest stack is included; a policy, or an integration for another input device, is yours. Camera recording is currently tested with synthetic input; check peripheral status before planning an experiment.

See it in motion

From targets to motion. An illustration of the trajectory generator bridging different update rates. How target control works.
Understand a run. Inspect the robot and motion plots together in Rerun. Record and replay.

Questions

Which robots?

The Franka Research 3 (FCI v10) and the Franka Emika Robot, the Panda (FCI v5). One binary; the protocol version is negotiated when it connects. The published simulator image is an FR3.

Do I need a realtime kernel?

Wherever the 1 kHz loop runs, yes: a PREEMPT_RT kernel, an rtprio limit and a wired link. That is your machine for direct use, or the Pi for remote use. A laptop that only talks to a node needs nothing special. Against the simulator, realtime checks are simply turned off.

Is it a 1 kHz callback API too?

Yes. Write the loop as a callback, drive it with read_once and write_once, or let the crate run it and set targets from any thread. Target control is the recommended path for anything that is not a 1 kHz program.

How does it compare with libfranka?

Wire layouts, rate limiting, filtering and error text are checked against libfranka's sources. Measured side by side against the simulator, loop timing is the same and the model agrees to 1e-14. Figures and method: Compared with libfranka and Benchmarks.

What is not there yet?

A ros2_control hardware interface, the vacuum gripper and a published simulator image for the Panda. The impedance backend of target control, the default since 0.3.0, is not yet validated on an FR3. The node's gripper path is simulator-tested, and camera recording is tested with synthetic input. The changelog tracks each release.

Where is the code?

github.com/BarisYazici/franka-rs: the client, the Python bindings, franka-node, franka-cam, the flight recorder and the tests that run against the simulator in CI.