Skip to main content

videosdk-teleop

Drive a robot arm over the internet, and know exactly what the operator was looking at when they moved it.

A WebRTC transport for robot teleoperation, with frame-accurate observation/action correlation, a safety envelope that cannot be bypassed, and a recorder that turns every session into training data.

Torq architecture: physical robots behind follower adapters, a VideoSDK room carrying synced action and video, and leader adapters in front of a human operator, VR headset, simulation or AI agent


Install

pip install videosdk-teleop               # transport + cameras, ready to run
pip install "videosdk-teleop[lerobot]"    # + the lerobot adapters
pip install "videosdk-teleop[ros2]"       # + the ROS 2 nodes

Python 3.10-3.12. The first line is enough to teleoperate: the WebRTC transport and the camera stack are core dependencies, not extras.

Your robot, in three methods

Everything else is inherited: lease negotiation, clamping, the watchdog, the e-stop latch, correlation, recording.

from videosdk_teleop import Follower, SafetyConfig, single_group_descriptor

class MyArm(Follower):
    def descriptor(self):            return single_group_descriptor(...)
    def read_joints(self):           return {"shoulder": 12.4, "elbow": -3.1}
    def write_joints(self, joints):  ...        # RAISE on failure

MyArm("abcd-efgh-ijkl", safety=SafetyConfig(slew=12.0)).run(hz=50)

Already on lerobot? Wrap the device instead of subclassing:

from videosdk_teleop.adapters.lerobot import (SO101FollowerAdapter,
                                              SO101LeaderAdapter)

follower = SO101FollowerAdapter("abcd-efgh-ijkl", robot=arm, token=TOKEN)

On ROS 2, teleop_bridge_node does the same against your driver topics.

Meeting ids come from the VideoSDK API, or videosdk_teleop.rooms.create_room().

Run it locally, no robot needed

Runnable examples live in videosdk-teleops-examples:

git clone https://github.com/videosdk-live/videosdk-teleops-examples
cd videosdk-teleops-examples

python quickstart/remote_teleop.py --ticks 100   # full chain, in-process
python quickstart/my_arm.py                      # port your own arm
python quickstart/protocol_demo.py               # the wire format, live

remote_teleop.py runs a real follower against a real leader: real gates, real clamps, real observation log. Only the network is swapped for a loopback.

You own the loop

leader.tick()                 # one control period, never blocks
leader.run(hz=50)             # or let it pace the loop for you
for _ in leader.ticks(hz=50):
    obs = leader.observation()          # joints + pixels, same instant
    print(obs.observation_id, obs.joints, obs.images)

    frame = leader.peek_synced()        # watch only: does not arm the echo

Safety

SafetyConfig(
    slew=12.0,                          # max change per joint per tick
    watchdog_timeout_s=0.5,             # silence for this long -> failsafe
    max_staleness_ms=100.0,             # older commands are dropped
    require_deadman=True,
    on_starvation=FailsafeAction.HOLD,
    resume_requires_reclaim=False)
follower.estop()          # unauthenticated by design: anyone can stop an arm
follower.clear_estop()    # latched: only a human on the follower host resumes

Every command is checked before it reaches the motors: who sent it, whether it arrived too late, and how far it moves the arm. If the operator stops sending, the arm holds where it is.

Knowing what the operator saw

Every action is tagged with the exact camera frame the operator was looking at when they sent it. The tag travels with the command, so the two machines never need their clocks in sync.

Recording

follower.start_recording("./sessions")
follower.start_episode("pick up the cube")
...                                          # your loop runs
follower.end_episode(success=True)
follower.stop_recording()

On the follower this captures pixels before an encoder or a network touched them. Episodes open and close on the deadman by default.

VideoSDK can also record the session in the cloud:

follower = MyArm("abcd-efgh-ijkl", cloud_recording=True)

follower.cloud_recording_state    # idle / requested / starting / ready / failed

If the cloud recorder never comes up, recording carries on locally and the state says so.

Watching a session

from videosdk_teleop import attach

attach(follower, host="0.0.0.0", port=8080)   # live page + /snapshot.json

On ROS 2

One node, teleop_bridge_node, one role per host. It never talks to your motors directly: it reads your driver's joint-state topic and writes to your driver's joint-command topic, exactly like any other ROS node.

ros2 launch videosdk_teleop_ros bridge.launch.py \
    role:=follower_side robot_id:=my_arm cameras:=cam_a,cam_b labels:=wrist,front

ros2 service call /videosdk_bridge/enable std_srvs/srv/SetBool "{data: true}"

The bridge sits idle until enable is called, so launching it moves nothing.

Install into the same Python that ROS 2 uses, not whatever python3 your shell resolves to:

/usr/bin/python3 -m pip install --user videosdk-teleop

Documentation

Full documentation at docs.videosdk.live.


Apache-2.0 · docs.videosdk.live · examples

Release files for videosdk-teleop 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for videosdk-teleop 0.1.3
File Size Uploaded
videosdk_teleop-0.1.3.tar.gz 371.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for videosdk-teleop 0.1.3
File Interpreter ABI Platform
videosdk_teleop-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 622.4 kB

Release files / videosdk_teleop-0.1.3.tar.gz

Download URL videosdk_teleop-0.1.3.tar.gz
Size 371.1 kB
Tags Source
SHA-256 checksum
How to use checksums
744f793b9436a7675bc0424c001bd7eaeae071cce6aa9e1b56fc2ad8ffe406e9
BLAKE2b-256 checksum
How to use checksums
05b3fd07736d88fc70676a1710e5b910a7a52ed19196a17261ec51a1aa6c13bf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.9

Release files / videosdk_teleop-0.1.3-py3-none-any.whl

Download URL videosdk_teleop-0.1.3-py3-none-any.whl
Size 251.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7fd6f060d3111935a5c2057f3f5e477e6ce1a0c8b238f377f872d1bba8e1f05a
BLAKE2b-256 checksum
How to use checksums
dd2ca079722af1e4719ad3a50f0f1628c56d7ecb36a06a4a2bff45af7a2037e6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.9

Release history Release notifications | RSS feed

0.1.11

3 release files

0.1.10

3 release files

0.1.9

3 release files

0.1.8

3 release files

0.1.7

3 release files

0.1.6

3 release files

0.1.5

2 release files

0.1.4

2 release files

This release

0.1.3 This release

2 release files

0.1.2

1 release file

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page