zero-franky
Use franky from a non-realtime machine through a ZeroMQ protocol.
flowchart LR
subgraph Client["client process"]
App["user code"]
LocalFranky["local franky construction objects"]
Proxy["zero-franky Robot proxy"]
end
subgraph Server["robot host process"]
Rpc["ZeroMQ RPC server"]
Builder["motion/policy builders"]
Session["tracker session policy loop"]
Handle["franky reference handle"]
RemoteFranky["real franky Robot"]
Pub["ZeroMQ state publisher"]
end
Robot["Franka robot"]
App --> LocalFranky
LocalFranky --> Proxy
App --> Proxy
Proxy -- "RPC: msgpack motion payloads" --> Rpc
Proxy -- "RPC: import ref or cloudpickle policy" --> Rpc
Rpc --> Builder
Builder --> RemoteFranky
Builder --> Session
Session -- "local update loop" --> Handle
Handle --> RemoteFranky
RemoteFranky <--> Robot
RemoteFranky --> Pub
Pub -- "SUB: robot.state" --> App
Usage
from zero_franky import setup_zero_franky
from zero_franky import Robot
from franky import Affine, CartesianMotion, ReferenceType
setup_zero_franky("server-ip", 18812)
robot = Robot("192.168.100.1")
motion = CartesianMotion(Affine([0.2, 0.0, 0.0]), ReferenceType.Relative)
robot.move(motion, asynchronous=True)
robot.join_motion()
Robot is a proxy, and real local franky objects like Affine, CartesianMotion, and JointMotion are encoded into plain msgpack payloads. The server reconstructs corresponding real franky objects next to the robot.
Server
On the robot host:
zero-franky server
By default this binds RPC on tcp://0.0.0.0:18812, state PUB on tcp://0.0.0.0:18813, and tracker updates on tcp://0.0.0.0:18814.
Common overrides:
zero-franky server --host 192.168.1.20 --port 18812
zero-franky server --port 19000 --no-pub
Robotiq gripper
Robotiq 2F-85 support is optional. Install both control-machine extras only on hosts that physically run the robot and gripper services:
pip install 'zero-franky[server,robotiq]'
The base installation contains the network client and does not import or
require pyrobotiqgripper.
Run the robot server together with the gripper server with --robotiq:
zero-franky server --robotiq --com-port auto
Or run the gripper service on its own (e.g. on a different host, or the robot server is already running separately):
zero-franky gripper serve --com-port auto
The gripper subcommand also provides diagnostic client commands:
zero-franky gripper status --host control-machine
zero-franky gripper open --host control-machine
The equivalent Python entry point is:
from zero_franky.zmq_server import ZmqRobotServer
ZmqRobotServer(
bind="tcp://0.0.0.0:18812",
pub_bind="tcp://0.0.0.0:18813",
tracker_bind="tcp://0.0.0.0:18814",
).serve_forever()
Implemented protocol
robot.createrobot.recover_from_errorsrobot.moverobot.join_motionrobot.poll_motionrobot.stoprobot.get_last_teleop_staterobot.start_joint_trackerrobot.start_cartesian_trackertracker.statustracker.stoptracker.set_joint_referencetracker.set_cartesian_referencetracker.set_joint_gainstracker.set_joint_cartesian_gainstracker.set_cartesian_gainstracker.set_nullspace_gains
Supported motion payloads cover position, velocity, waypoint, stop, and fixed impedance motions.
Telemetry
When the server has a pub_bind, RobotManager registers a motion callback and publishes snapshots on robot.state.
setup_zero_franky("server-ip", 18812)
subscriber = robot.state_subscriber()
topic, state = subscriber.recv()
Tracker Sessions
Tracker sessions are for JointImpedanceTrackingMotion and CartesianImpedanceTrackingMotion. They keep the impedance motion and reference handle on the robot host. By default, client code sets references through the returned proxy:
with robot.start_joint_impedance_session(stiffness=[10.0] * 7, damping=[6.0] * 7) as session:
session.set_joint_reference(q, velocity=dq)
session.set_joint_gains(stiffness=[20.0] * 7, damping=[8.0] * 7)
The proxy stops the tracker when the context block exits.
A session can also run a Python policy loop beside the reference handle. This avoids trying to servo over ZeroMQ while still letting client code define the policy.
There are two policy transports:
import: sendmodule+qualname; the server imports the policy. Use this for stable policies installed on the robot host.cloudpickle: serialize the function and send it over RPC. Use this for exploratory work on a trusted control network.
The built-in hold policies are importable:
from zero_franky.tracker_policies import hold_current_joint
with robot.start_joint_impedance_session(
hold_current_joint,
stiffness=[10.0] * 7,
damping=[6.0] * 7,
) as session:
status = session.status()
Or it can be shipped with cloudpickle for exploratory work:
import math
def wiggle_joints(context):
q = list(context.robot.current_joint_positions)
amplitude = 0.03
frequency = 0.25
phase_offsets = [index * math.pi / 7.0 for index in range(7)]
def step(context):
omega = 2.0 * math.pi * frequency
position = [
q_i + amplitude * math.sin(omega * context.elapsed + phase)
for q_i, phase in zip(q, phase_offsets)
]
velocity = [
amplitude * omega * math.cos(omega * context.elapsed + phase)
for phase in phase_offsets
]
return {"position": position, "velocity": velocity}
return step
with robot.start_joint_impedance_session(
wiggle_joints,
policy_transport="cloudpickle",
stiffness=[10.0] * 7,
) as session:
status = session.status()
cloudpickle policy transport executes client-provided Python on the robot host. Use it only on a trusted control network.
Cartesian sessions use the same policy shape and return an Affine target:
from zero_franky.tracker_policies import hold_current_cartesian
with robot.start_cartesian_impedance_session(
hold_current_cartesian,
translational_stiffness=250.0,
rotational_stiffness=25.0,
) as session:
session.set_cartesian_gains(translational_stiffness=300.0, rotational_stiffness=30.0)
status = session.status()
The policy function receives a context with franky, robot, elapsed, iterations, and stop(). A factory may return a step function, or the policy may act directly as the step function. Joint steps return {"position": q, "velocity": dq, "torque_feedforward": tau}. Cartesian steps return {"target": affine, "target_twist": twist}.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zero_franky-0.1.2.tar.gz.
File metadata
- Download URL: zero_franky-0.1.2.tar.gz
- Upload date:
- Size: 26.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bee70aaf9eb19b35b3b8b95aaeae941bd3407a29b9d9868a16c9e320bcfaea37
|
|
| MD5 |
cb8261cb52bc309df6242fd2d8fb25bf
|
|
| BLAKE2b-256 |
a62952f5d3a79a2f5097c2f30a855da01bfac03fe78c7863901009c2b2770f52
|
Provenance
The following attestation bundles were made for zero_franky-0.1.2.tar.gz:
Publisher:
publish.yml on nickswalker/zero-franky
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zero_franky-0.1.2.tar.gz -
Subject digest:
bee70aaf9eb19b35b3b8b95aaeae941bd3407a29b9d9868a16c9e320bcfaea37 - Sigstore transparency entry: 2187686228
- Sigstore integration time:
-
Permalink:
nickswalker/zero-franky@98a4c12799fb14b6a5f4b9bec380538a70e3c2ca -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/nickswalker
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@98a4c12799fb14b6a5f4b9bec380538a70e3c2ca -
Trigger Event:
release
-
Statement type:
File details
Details for the file zero_franky-0.1.2-py3-none-any.whl.
File metadata
- Download URL: zero_franky-0.1.2-py3-none-any.whl
- Upload date:
- Size: 28.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
092fb88ba5fd4717b70be30a4ce11efe69fcab3660481bccc2c2c7c6babf12ad
|
|
| MD5 |
d0fbc9a881d5ef7093b0b8f0fcc0da58
|
|
| BLAKE2b-256 |
f5b04de62abee811a4e4f44afcbaf1310e2d1fe296c2b50d2b72e2354603e6ec
|
Provenance
The following attestation bundles were made for zero_franky-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on nickswalker/zero-franky
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zero_franky-0.1.2-py3-none-any.whl -
Subject digest:
092fb88ba5fd4717b70be30a4ce11efe69fcab3660481bccc2c2c7c6babf12ad - Sigstore transparency entry: 2187686288
- Sigstore integration time:
-
Permalink:
nickswalker/zero-franky@98a4c12799fb14b6a5f4b9bec380538a70e3c2ca -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/nickswalker
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@98a4c12799fb14b6a5f4b9bec380538a70e3c2ca -
Trigger Event:
release
-
Statement type: