Skip to main content

pib-sdk

A Python SDK for pib humanoid robot: kinematics, motor control, speech, live telemetry, and everything a user can create in Cerebra (pib's web UI) — poses, Blockly programs, RGB-button bindings, the voice assistant, and more.

Positions are in millimetres, joint angles in radians (every angle-taking function has a *_deg sibling that takes or returns degrees), and orientations as roll–pitch–yaw (see Conventions).

Documentation

This README is the entry point. Continue with:

Document Use it for
API reference Signatures, parameters, return values, exceptions, units, and backend caveats for all 169 public API elements
Tutorials Guided tasks from first connection through IK, poses, depth vision, IMU, drawing, programs, buttons, display, and relay
Runnable examples An index of scripts under examples/ and whether each needs a live robot
Architecture Call-flow diagrams for rosbridge, REST, kinematics, programs, poses, telemetry, and IMU

Architecture at a glance

pib-sdk is one of two independent clients of the same robot-side services — the other is Cerebra. Neither wraps the other: both call the same rosbridge services/topics and the same pib-backend REST routes, so nothing this SDK does (including the voice assistant and Blockly programs) is a reimplementation of logic that already lives on the robot.

flowchart LR
    SDK["pib-sdk\n(your script)"] -- "WebSocket JSON" --> RB{{"rosbridge : 9090"}}
    SDK -- "HTTP JSON" --> BE["pib-backend : 5000"]
    CEREBRA["Cerebra\n(web UI)"] -- "WebSocket JSON" --> RB
    CEREBRA -- "HTTP JSON" --> BE
    RB --- Nodes["ROS2 nodes\nmotor · voice assistant ·\nprogram executor · camera ..."]
    BE --- DB[("database")]

Full control-flow diagrams — the voice assistant call sequence, the Blockly program proxy, the kinematics/Pinocchio layering, telemetry pull-vs-push — live in docs/ARCHITECTURE.md.


Concepts

Two equal clients

Cerebra and pib-sdk are peers. A change made through either client reaches the same robot-side services and persisted resources. The SDK does not automate the Cerebra UI or duplicate its assistant, pose, or program logic.

Connection and lifecycle model

Use one host name for a robot, normally pib.local. Real-time APIs connect to rosbridge (9090); persisted Cerebra data uses pib-backend HTTP (5000). Every live client (Write, Speak, Telemetry, Camera, and so on) shares one rosbridge WebSocket per host and port for the whole process (pib_sdk.ros_client). Close a client or use it as a context manager when you are done with it; that releases the shared connection without disconnecting it, so the next client in the same script still connects.

Robot is a convenient lifecycle/configuration bundle. It constructs Write, Speak, and Telemetry once each, over that one shared WebSocket, and exposes one stateless BackendClient.

Motor selectors and names

Write accepts literal firmware motor names such as "elbow_right" and selector tokens such as right_arm, left_hand, head, and All. Group tokens expand locally, in a stable order, without querying the backend. Write.move(group, angle) applies one angle to all selected motors; Write.move(group, *angles) consumes one angle per expanded motor. Hand action tokens (open_right_hand, etc.) are complete actions and take no angle. See Joint ↔ motor names.

Units and conventions

Kinematics APIs use radians and millimetres, with *_deg wrappers for callers that think in degrees. Write.move takes degrees at the public boundary (same as before). Joint positions on rosbridge (/apply_joint_trajectory, /joint_trajectory) are sent in radians; pib-backend HTTP and pose storage still use integer centidegrees. Timed motion uses the standard JointTrajectory layout (send_timed_trajectory_rad in radians, send_timed_trajectory_deg in degrees, or send_timed_trajectory in centidegrees for pose storage). Depth pixels are unsigned 16-bit millimetres, where zero means invalid.

Errors and command results

Argument and model problems raise TypeError, ValueError, KeyError, or FileNotFoundError. Connection setup raises ConnectionError or RuntimeError, depending on the client; waiting APIs may raise TimeoutError. REST failures raise BackendError. Several live command methods instead return False on backend rejection (and Write.move also returns False after trajectory failures), with per-motor error_code values on Write.last_joint_trajectory_result. Camera depth reads use None/0.0 for unavailable data. Exact behavior is listed in the API reference.


Requirements

  • Python 3.9+ (3.11+ works out of the box on current Raspberry Pi OS).
  • Pinocchio (pin) >= 3.1 — the kinematics backend, installed automatically from PyPI wheels.
  • numpy >= 1.22.
  • roslibpy >= 1.6 — rosbridge client (only needed for things that talk to hardware; pure kinematics needs no connection).
  • A running rosbridge server on the robot (WebSocket, default port 9090) for motor control, speech, telemetry, and live program/voice- assistant control.
  • pib-backend's REST API (default port 5000, same host, no authentication) for anything sourced from Cerebra: poses, programs, button bindings, camera/motor settings, personalities, chats.

There are no system packages to install and no version-pinned scientific dependencies. Pinocchio ships prebuilt wheels (including aarch64 for the Raspberry Pi), so a plain pip install works — no apt, no conda, no building from source.


Installation

From PyPI:

pip install pib-sdk

Quick start

Kinematics

from pib_sdk import fk, ik

# Inverse kinematics: target position in millimetres -> joint angles in radians
q_rad = ik("right", xyz=[-400, 100, 900])
print("IK angles:", q_rad)

# Forward kinematics: joint angles in radians -> end-effector pose
import numpy as np
pose = fk("right", np.deg2rad([0, 45, 0, 0, 90, 0]))
# ... or with degrees in and out:
pose = fk_deg("right", [0, 45, 0, 0, 90, 0])
print("palm position (mm):", pose.translation)
print("palm orientation (3x3):\n", pose.rotation)

fk returns a pinocchio.SE3; read pose.translation (mm) and pose.rotation, or convert:

from pib_sdk import pose_to_xyz_rpy
xyz_mm, rpy_deg = pose_to_xyz_rpy(pose)

Need raw Pinocchio? You already have it — fk/ik consume and return real pinocchio.SE3 objects, not a pib-sdk wrapper type. For the underlying model, pib_sdk.robot_model.get_arm_model("right").model is the actual pin.Model (and .create_data() a fresh pin.Data) that ik solves against — useful for calling Pinocchio functions directly (custom Jacobians, etc.) against that same model. pinocchio itself is a required dependency (pin>=3.1), so import pinocchio as pin always works standalone; pib-sdk just never re-exports the module as pib_sdk.pin. Details: docs/ARCHITECTURE.md.

Driving the arm with an IK solution

The IK joint order matches the right_arm / left_arm motor groups exactly, so the result feeds straight into Write.move:

from pib_sdk import Write, ik, right_arm

q_deg = ik("right", xyz=[-400, 100, 900])

with Write(host="pib.local") as w:   # rosbridge on the robot (constructor default: localhost)
    w.move(right_arm, *q_deg)        # one angle per joint, in order

Motor control

from pib_sdk import Write, All, default, right_arm, left_hand, zero_position, open_right_hand

w = Write(host="localhost")            # connects to rosbridge

w.set(All, default)                    # apply the default MotorSettings to all motors
w.set(left_hand, velocity=6000)        # override settings for one group

w.move(right_arm, -30.0)               # uniform: one angle applied to the whole group
w.move(right_arm, 10, -20, 5, 30, -10, 0)   # vector: one angle per joint
w.move(All, zero_position)             # everything to 0°
w.move(open_right_hand)                # hand shortcut

Speech

from pib_sdk import Speak

with Speak(host="localhost") as sp:
    sp.say("hello world")                # default voice: Emma (Female, English)
    sp.say("guten Tag", voice="Hannah")  # preset -> Female / German

Head camera pose (kinematics)

from pib_sdk import camera_pose

pose = camera_pose(pan_deg=30, tilt_deg=-10)     # camera pose in the base frame (mm)

This is forward kinematics for the head/camera frame — not to be confused with pib_sdk.features.camera, which fetches an actual JPEG snapshot; see docs/REFERENCE.md.

Everything else: one configured bundle

Robot bundles motor control, speech, telemetry, and pib-backend's REST API behind a single host and context manager. The three live clients retain their own rosbridge connections:

from pib_sdk import right_arm
from pib_sdk.robot import Robot

with Robot(host="pib.local") as robot:
    robot.write.move(right_arm, -30.0)
    robot.speak.say("moving my arm")
    print(robot.telemetry.get_position_deg("shoulder_vertical_right"))
    print(robot.backend.list_poses())
Want to... Use
Read a motor's last commanded position / live current draw pib_sdk.telemetry.Telemetry
Talk to pib-backend's REST API directly (poses, programs, motors, camera, voice assistant...) pib_sdk.backend.BackendClient
Turn an image into an arm-drawn trajectory pib_sdk.features.drawing
Drive to / save poses created in Cerebra pib_sdk.features.poses
Run or stop a Blockly program saved in Cerebra pib_sdk.features.programs
See/change which program an RGB button triggers pib_sdk.features.buttons
Grab a camera snapshot or millimetre depth data pib_sdk.features.camera
Drive the voice assistant: state, chats, personalities pib_sdk.features.assistant
Push an image to pib's screen pib_sdk.features.display
Read/set the solid-state relay pib_sdk.features.relay
Read the latest IMU acceleration and gyro sample pib_sdk.features.imu

features.assistant and features.programs call the exact same rosbridge services and REST routes Cerebra itself uses for chat and "run program" — see Two equal clients.

Details, caveats, and full examples for each: docs/REFERENCE.md. For guided workflows, continue with docs/TUTORIALS.md.


Joint ↔ motor names

The URDF and the motor firmware use slightly different names for a few joints. The SDK keeps both: kinematics is expressed in URDF joint order, and each chain also carries the matching motor name so IK output lines up with Write.move. You normally never need this table — it's here for reference.

Chain URDF joint pib motor Limits (°)
right_arm shoulder_vertical_right shoulder_vertical_right −90 … 90
right_arm shoulder_horizontal_right shoulder_horizontal_right −90 … 90
right_arm upper_arm_right upper_arm_right_rotation −90 … 90
right_arm elbow_right elbow_right −45 … 90
right_arm forearm_right lower_arm_right_rotation −90 … 90
right_arm wrist_right wrist_right −30 … 30
head head_horizontal turn_head_motor −90 … 90
head head_vertical tilt_forward_motor −45 … 70

The left arm mirrors the right. Inspect any chain yourself:

python -m pib_sdk.robot_model

Hardware sign check. The URDF's zero pose has both arms pointing straight out to the sides, matching pib's motor zero. Joint directions in the URDF follow the URDF's axis conventions; if a real motor turns opposite to the model on your unit, flip it with the motor's invert setting (w.set("<motor>", invert=True)) rather than negating angles in your code. Verify one joint at a time on first bring-up.


Conventions

  • Positions: millimetres.
  • Joint angles: radians (canonical). Order is base → tip, as printed by python -m pib_sdk.robot_model. Each angle-taking function has a *_deg sibling for degrees; the wrappers convert and delegate, they carry no logic.
  • Orientation: roll–pitch–yaw in radians (or degrees via *_deg), applied as R = Rz(yaw) · Ry(pitch) · Rx(roll) (ZYX — the same convention the previous Robotics Toolbox implementation used).
  • Poses: pinocchio.SE3, expressed in pib's base frame.

Inverse kinematics options

ik(side, xyz=..., ...) (and ArmKinematics.inverse) accept:

Option Default Meaning
rpy_rad None Target orientation in radians. None → position-only IK.
rpy_deg None Same target in degrees; the result is then returned in degrees (legacy path).
initial_guess_rad zeros Starting joint configuration in radians.
initial_guess_deg — Starting configuration in degrees; only together with rpy_deg.
tolerance 1e-4 Convergence threshold on the pose error (mm-scaled).
max_iterations 200 Solver iterations per attempt.
mask auto 6-element [x, y, z, rx, ry, rz] selector over the pose error.
restarts 50 Random in-limit restarts if the first solve misses.
respect_limits True Keep the solution within mechanical joint limits.

With respect_limits=True (the default), a returned solution is within the loaded URDF's joint limits. Write.move separately accepts only [-90, 90]° and can still return False if the backend rejects a command; verify custom URDF limits against the real robot. IK raises ValueError if it cannot reach the target.


Using a different or updated URDF

The package ships pib's V3 URDF at pib_sdk/data/pib_model.urdf. To use another file — a newer revision, or a variant of your robot — point the loader at it:

from pib_sdk import set_urdf_path
set_urdf_path("/path/to/robot.urdf")

or set the PIB_URDF_PATH environment variable before importing. The joint and frame names in pib_sdk.robot_model (RIGHT_ARM, LEFT_ARM, HEAD) must match those in your URDF; mismatches raise a clear error listing the names the URDF actually provides.

Meshes are not required. Kinematics uses only the URDF's joint tree, so the visual/collision .stl meshes referenced by the URDF are not needed and are not bundled. Pinocchio loads the kinematic model without them.


Development

pip install -e ".[dev]"

pytest          # run the test suite
ruff check src tests
ruff format src tests
python tools/check_doc_coverage.py
python tools/check_doc_links.py
python tools/check_examples.py
python -m build # build the sdist and wheel

The tests include an independent forward-kinematics implementation (URDF parsed with xml.etree, transforms multiplied with plain numpy) that cross-checks the Pinocchio models to machine precision — a guard against URDF-loading or unit-scaling regressions. Everything that talks to rosbridge or pib-backend is tested offline against fakes (see tests/conftest.py) — no real robot or server needed to run the suite.


License

MIT — see LICENSE.

Metadata

Release files for pib-sdk 0.7.4

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

Source distribution (sdist)

Source distribution for pib-sdk 0.7.4
File Size Uploaded Provenance Actions
pib_sdk-0.7.4.tar.gz 138.5 kB Without provenance Details for pib_sdk-0.7.4.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for pib-sdk 0.7.4
File Interpreter ABI Platform Actions
pib_sdk-0.7.4-py3-none-any.whl Python 3 none any Details for pib_sdk-0.7.4-py3-none-any.whl

Total release size: 226.5 kB

Release files / pib_sdk-0.7.4.tar.gz

Download URL pib_sdk-0.7.4.tar.gz
Size 138.5 kB
Tags Source
SHA-256 checksum
How to use checksums
96c9df9fe17fa007430c3c2a58529aee951e2ffc9410d4078c5310f48a979d1e
BLAKE2b-256 checksum
How to use checksums
399d54c70415a7b1c15f21d2834552ec64fc3869d60312def177436054ac0b0e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / pib_sdk-0.7.4-py3-none-any.whl

Download URL pib_sdk-0.7.4-py3-none-any.whl
Size 87.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d9dfc48608c2e8c54924e7ef76cb99ee236618a3384d81ba11b616a26014e32b
BLAKE2b-256 checksum
How to use checksums
78730e42cd4276c7b99b0b7300e9c513439ef72623ed0e7c7cb31467c59dead4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Security for pib-sdk 0.7.4

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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