Metadata-Version: 2.4
Name: ubicoders-vrsdk
Version: 0.1.4
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Rust
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Requires-Dist: numpy>=1.22
Requires-Dist: opencv-python>=4.5 ; extra == 'examples'
Provides-Extra: examples
Summary: Python SDK for controlling Ubicoders virtual robots in the Unity simulator
Keywords: robotics,simulation,zenoh,iceoryx2,flatbuffers,unity
Requires-Python: >=3.8
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Repository, https://github.com/ubicoders0/vrobots_sdk

# ubicoders-vrsdk

Python SDK for controlling [Ubicoders](https://github.com/ubicoders0) virtual
robots running in the Unity simulator. It is a thin binding over the Rust core
(`vrobots-sdk`), which speaks zenoh + iceoryx2 with FlatBuffers on the wire — so
the Python, C++ and Rust surfaces share one implementation and behave
identically.

```bash
pip install ubicoders-vrsdk
vrobots topic list          # is the sim publishing, and under which id?
```

```python
from vrsdk import VirtualRobot, RobotType

def main():
    # ===== setup =====
    mr = VirtualRobot(RobotType.MULTIROTOR, sys_id=1)
    mr.connect()
    cam = mr.mount_camera("left", "720p", "rgb8")

    # ===== loop =====
    while True:
        s = mr.states
        x, y, z = s.kin.lin_pos
        print(f"State t={s.elapsed:.3f} pos=({x:.3f},{y:.2f},{z:.2f})")

        mr.set_mr_pwm(1501, 1501, 1501, 1501)

        if cam.fresh:
            img = cam.image        # numpy (h, w, c) uint8, top-down, RGB
        mr.rate(100)

if __name__ == "__main__":
    main()
```

`main()` does setup and then owns the loop. There is no base class, no runner
and no callbacks — the SDK never calls your code.

## Things that surprise people

- **`states` never blocks and never fails.** If the sim stops it keeps handing
  back the last snapshot; watch `elapsed`, or call `wait_new_state()`, to notice.
- **Images are RGB, not BGR.** Rows are already flipped top-down and the stride
  is tight, but channel order is the renderer's. For OpenCV:
  `cv2.cvtColor(cam.image, cv2.COLOR_RGB2BGR)`.
- **States and frames are separate streams.** No frame belongs to any state;
  compare `t_ns` when fusing.
- **Robots outlive the process.** Attach with `sys_id`; only `delete()` removes
  one. Letting the handle be collected closes the session and leaves the robot
  flying.
- **Camera resolution is robot-wide**, not per camera. `mount_camera` *adds*
  one camera and `unmount_camera` removes one by name; the robot's other
  cameras are left alone either way.
- **Commands are setpoints and are never acknowledged.** Proof that one landed
  is `states.actuator.pwm` echoing it back.

## Errors and logging

Every failure raises `vrsdk.VrError` carrying a stable numeric `code`:

```python
try:
    mr.connect()
except vrsdk.VrError as e:
    if e.code == vrsdk.err.TIMEOUT:
        print("no sim on the wire:", e.detail)
```

The core's `tracing` events are bridged into Python `logging` on import;
`vrsdk.init_logging("info")` turns the volume up.

## Requirements

CPython 3.8 through 3.13 and later, on x86-64 Windows or Linux (one `cp38-abi3`
wheel per OS covers every one of them), plus numpy. `opencv-python` is only needed by
the image example. Camera streams use shared memory and are therefore
**same-host only**; states, commands and services work across a network with
`VirtualRobot(..., router="tcp/<host>:7447")`.

## Examples

The full series lives in [`examples/python`](../../examples/python): hello
states, control, image, service, car.

