Skip to main content

PhysicalAI LeKiwi Plugin

Third-party LeKiwi mobile manipulator plugin for PhysicalAI, the Python library and runtime for robot control, transport, and CLI workflows. It registers with Physical AI Studio, the application that discovers catalog plugins and provides robot setup, teleoperation, and workflow experiences. Part of the physicalai-plugins monorepo.

PyPI version Python versions

Features

  • Concrete implementation of the Robot protocol — no inheritance or registration required
  • 6-DOF SO-ARM100 arm + 3-wheel holonomic base, in normalized or raw-ticks units
  • Follower and leader (read-only) roles for teleoperation
  • Bundled URDF for kinematics and gravity compensation
  • KeyboardTeleop and CompositeTeleop action sources for physicalai run

Hardware

Class Robot Motors Protocol
LeKiwi 6-DOF SO-ARM100 arm + 3-wheel holonomic base Feetech STS3215 (via scservo_sdk) POSITION / VELOCITY

Screenshots

Placeholder images — replace them with real screenshots.

LeKiwi in the PhysicalAI Studio robot catalog

Connecting to a LeKiwi in PhysicalAI Studio

LeKiwi composite teleop in the PhysicalAI CLI

Installation

uv add physicalai-lekiwi-plugin

scservo_sdk (Feetech servo serial SDK) is included as a core dependency.

No calibration JSON is bundled. You must provide your own calibration file (LeRobot format) or use uncalibrated/ticks mode.

Quick start

Basic follower (with calibration file)

import numpy as np
from physicalai.robot import connect
from physicalai_lekiwi_plugin import LeKiwiCalibration, LeKiwi

robot = LeKiwi(
    port="/dev/ttyACM0",
    role="follower",
    calibration=LeKiwiCalibration.from_path("calibration.json"),
)

with connect(robot) as robot:
    obs = robot.get_observation()
    action = obs.joint_positions.copy()
    robot.send_action(action)

In Studio catalog payloads, calibration_id is optional. When provided, the plugin loads that calibration and runs in normalized units. When omitted, the driver falls back to explicit uncalibrated ticks mode.

Calibration from a dict

cal = LeKiwiCalibration.from_dict({
    "arm_shoulder_pan":  {"id": 1, "drive_mode": 0, "homing_offset": 0,    "range_min": 0,    "range_max": 4095},
    "arm_shoulder_lift": {"id": 2, "drive_mode": 0, "homing_offset": -512, "range_min": 512,  "range_max": 3583},
    "arm_elbow_flex":    {"id": 3, "drive_mode": 0, "homing_offset": 0,    "range_min": 0,    "range_max": 4095},
    "arm_wrist_flex":    {"id": 4, "drive_mode": 1, "homing_offset": 0,    "range_min": 0,    "range_max": 4095},
    "arm_wrist_roll":    {"id": 5, "drive_mode": 0, "homing_offset": 0,    "range_min": 0,    "range_max": 4095},
    "arm_gripper":       {"id": 6, "drive_mode": 0, "homing_offset": 0,    "range_min": 2048, "range_max": 3072},
    "base_left_wheel":   {"id": 7, "drive_mode": 0, "homing_offset": 0,    "range_min": 0,    "range_max": 4095},
    "base_back_wheel":   {"id": 8, "drive_mode": 0, "homing_offset": 0,    "range_min": 0,    "range_max": 4095},
    "base_right_wheel":  {"id": 9, "drive_mode": 0, "homing_offset": 0,    "range_min": 0,    "range_max": 4095},
})

robot = LeKiwi(port="/dev/ttyACM0", role="follower", calibration=cal)

Uncalibrated bringup mode

robot = LeKiwi.uncalibrated(port="/dev/ttyACM0", role="follower")

Observations and actions use raw servo ticks (0–4095). No calibration file needed.

Leader (read-only teleoperation)

robot = LeKiwi.uncalibrated(port="/dev/ttyACM0", role="leader")

with connect(robot) as robot:
    while True:
        obs = robot.get_observation()
        print(obs.joint_positions)

Leader mode disables torque on all motors so the arm can be moved manually.

Run with the PhysicalAI CLI

The PhysicalAI CLI run subcommand executes a RobotRuntime from a YAML config. Run the bundled configs from the repo root:

# Keyboard drive of the base (arm holds its position)
uv run physicalai run --config packages/physicalai-lekiwi-plugin/examples/runtime/drive-keyboard.yaml

# Composite teleop: leader arm positions the arm, keyboard drives the base
uv run physicalai run --config packages/physicalai-lekiwi-plugin/examples/runtime/teleop.yaml

Press Ctrl+C to stop. Optionally cap the run with --run.duration_s=60.

Keyboard controls

Key Action
w / s forward / backward
a / d rotate left / right
q / e strafe left / right
space stop (zero the base)

Teleop action sources

physicalai-lekiwi-plugin bundles reusable action sources:

from physicalai_lekiwi_plugin.teleop import CompositeTeleop, KeyboardTeleop
Source Purpose
KeyboardTeleop WASD/QE base velocities; arm held at its observed pose
CompositeTeleop Combine a leader arm with a base source into one action

Sinusoidal motion and joint reading

uv run physicalai run --config packages/physicalai-lekiwi-plugin/examples/runtime/move-joints.yaml
uv run physicalai run --config packages/physicalai-lekiwi-plugin/examples/runtime/read-joints.yaml

URDF Model

from physicalai_lekiwi_plugin import get_urdf_path

urdf_path = get_urdf_path()
URDF Model Use
lekiwi/urdf/LeKiwi.urdf LeKiwi mobile manipulator Kinematics & gravity compensation

The URDF references original STL mesh files from the SIGRobotics-UIUC/LeKiwi project.

Kinematics Model

The base uses a three-wheel holonomic drive with wheels at 240°, 0°, and 120°:

# Body-frame velocities -> individual wheel raw speeds
wheel_raw = robot._body_to_wheel_raw(vx, vy, vtheta)

# Individual wheel raw speeds -> body-frame velocities
body_vel = robot._wheel_raw_to_body(left_raw, back_raw, right_raw)

The helper methods above are internal; prefer the Robot protocol (get_observation / send_action) in application code.

Parameter Value
Wheel angles 240°, 0°, 120°
Wheel radius 0.05 m
Base radius 0.125 m
Max raw wheel 3000

Development

uv sync
uv run pytest packages/physicalai-lekiwi-plugin/tests/

Acknowledgments

The URDF model for the LeKiwi is from the SIGRobotics-UIUC/LeKiwi project.

Metadata

Release files for physicalai-lekiwi-plugin 0.3.1

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

Source distribution (sdist)

Source distribution for physicalai-lekiwi-plugin 0.3.1
File Size Uploaded
physicalai_lekiwi_plugin-0.3.1.tar.gz 22.1 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for physicalai-lekiwi-plugin 0.3.1
File Interpreter ABI Platform
physicalai_lekiwi_plugin-0.3.1-py3-none-any.whl Python 3 none any Details

Total release size: 44.1 MB

Release files / physicalai_lekiwi_plugin-0.3.1.tar.gz

Download URL physicalai_lekiwi_plugin-0.3.1.tar.gz
Size 22.1 MB
Tags Source
SHA-256 checksum
How to use checksums
7043d670d65aeea58050c972b73b666760b54115e0129632ea328e161549c3a5
BLAKE2b-256 checksum
How to use checksums
d9f9fe98ebba31c90a700709a0ed443a06c612bafd54d4c4412ad0751c797055
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release files / physicalai_lekiwi_plugin-0.3.1-py3-none-any.whl

Download URL physicalai_lekiwi_plugin-0.3.1-py3-none-any.whl
Size 22.1 MB
Tags Python 3
SHA-256 checksum
How to use checksums
f3bbaf985932c83f27ca6227db0d31515429e66b7e4733e1bc75b8d8a530437e
BLAKE2b-256 checksum
How to use checksums
c74466144e438501da554ed78817aca1f0f286c51f7f0311bc72f1e31a1817b8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 10, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.1 This release

2 release files

0.3.0

2 release files

0.2.3

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