Metadata-Version: 2.4
Name: ubicoders-vrsdk
Version: 0.1.10
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.

## Showcase solutions

`vrsdk.showcase` ships finished solutions to the estimation problems the
examples build up to. They arrive compiled rather than as source, so the
behaviour is the API: what a solution computes and when it converges are
documented, the implementation is not. This submodule is Python only, it has no
private channel to the simulator, and nothing else in the SDK needs it.

```python
from vrsdk import RobotType, VirtualRobot, showcase

robot = VirtualRobot(RobotType.GLOBALHAWK, sys_id=0, coord_frame_id="frd", axis_convention=2)
robot.connect()

est = showcase.AttitudeEstimator(robot)   # built once, after connect()
roll, pitch, yaw = est.fused_euler()      # radians, ZYX, folded up to the newest snapshot
```

`AttitudeEstimator` is a velocity-aided attitude estimate: roll and pitch are
absolute, and stay honest under sustained thrust and in turns because the motion
part of the specific force is removed using the reported body velocity; yaw is
gyro-integrated and drifts.

## 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.

