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 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 161 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). Each live client (Write, Speak, Telemetry, Camera, and so on) owns its own rosbridge WebSocket and should be closed or used as a context manager.

Robot is a convenient lifecycle/configuration bundle. It constructs Write, Speak, and Telemetry once each and exposes one stateless BackendClient; it does not multiplex those clients over one WebSocket. Create only the specialized client you need when connection count matters.

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

Public movement and kinematics APIs use degrees and millimetres. The SDK converts motor commands to pib-backend's internal hundredths-of-a-degree representation at the service boundary. The exception is the low-level Write.send_timed_trajectory, whose positions are deliberately already in those internal units. 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 also returns False after service-call failures), so check booleans when command delivery matters. 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 degrees
q_deg = ik("right", xyz=[-400, 100, 900])
print("IK angles:", q_deg)

# Forward kinematics: joint angles in degrees -> end-effector pose
pose = fk("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: degrees. Order is base → tip, as printed by python -m pib_sdk.robot_model.
  • Orientation: roll–pitch–yaw in degrees, 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_deg None Target orientation. None → position-only IK.
initial_guess_deg zeros Starting joint configuration (degrees).
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.

Release files for pib-sdk 0.5.2

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.5.2
File Size Uploaded
pib_sdk-0.5.2.tar.gz 116.6 kB Details

Built distribution (wheel)

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

Total release size: 194.0 kB

Release files / pib_sdk-0.5.2.tar.gz

Download URL pib_sdk-0.5.2.tar.gz
Size 116.6 kB
Tags Source
SHA-256 checksum
How to use checksums
2273e59ccc5d23dbc7fb6ea019e2e8702a95b0323cbdc1cb5f429b406dfd2030
BLAKE2b-256 checksum
How to use checksums
edf9956d9eea935c644433f8aa78fd8ab264b3723142da4b3a9406430c4228d2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

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

Download URL pib_sdk-0.5.2-py3-none-any.whl
Size 77.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
138e3aeee54bad405341acf054c3aa604f2c548af585a2f2611c96fb300b614c
BLAKE2b-256 checksum
How to use checksums
2eb5073912337412841d6ab607cfab201d80916f4ddeb91bac25fb55119efd58
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.5.4

2 release files

0.5.3

2 release files

This release

0.5.2 This release

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4

2 release files

0.3

2 release files

0.2

2 release files

0.1

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