rainbow-rb-sdk 0.0.9.dev16__tar.gz → 0.0.9.dev18__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. {rainbow_rb_sdk-0.0.9.dev16/src/rainbow_rb_sdk.egg-info → rainbow_rb_sdk-0.0.9.dev18}/PKG-INFO +138 -7
  2. rainbow_rb_sdk-0.0.9.dev16/PKG-INFO → rainbow_rb_sdk-0.0.9.dev18/README.md +132 -15
  3. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/pyproject.toml +7 -7
  4. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr_sdk/amr_setting.py +43 -67
  5. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/base.py +23 -4
  6. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_config.py +37 -37
  7. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_io.py +36 -36
  8. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_maintenance.py +13 -13
  9. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_move.py +237 -40
  10. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_point.py +1 -1
  11. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_program.py +3 -3
  12. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_service.py +124 -38
  13. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/schema/manipulate_move_schema.py +2 -2
  14. rainbow_rb_sdk-0.0.9.dev16/README.md → rainbow_rb_sdk-0.0.9.dev18/src/rainbow_rb_sdk.egg-info/PKG-INFO +146 -1
  15. rainbow_rb_sdk-0.0.9.dev18/src/rainbow_rb_sdk.egg-info/requires.txt +6 -0
  16. rainbow_rb_sdk-0.0.9.dev16/src/rainbow_rb_sdk.egg-info/requires.txt +0 -6
  17. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/setup.cfg +0 -0
  18. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/__init__.py +0 -0
  19. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr.py +0 -0
  20. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr_sdk/__init__.py +0 -0
  21. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr_sdk/amr_accessory.py +0 -0
  22. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr_sdk/amr_capability.py +0 -0
  23. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr_sdk/amr_control.py +0 -0
  24. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr_sdk/amr_file.py +0 -0
  25. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr_sdk/amr_localization.py +0 -0
  26. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr_sdk/amr_map.py +0 -0
  27. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr_sdk/amr_move.py +0 -0
  28. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr_sdk/amr_program.py +0 -0
  29. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr_sdk/amr_status.py +0 -0
  30. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/amr_sdk/schema/__init__.py +0 -0
  31. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/base_sdk/__init__.py +0 -0
  32. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/base_sdk/base_schema.py +0 -0
  33. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate.py +0 -0
  34. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/__init__.py +0 -0
  35. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_get_data.py +0 -0
  36. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_state.py +0 -0
  37. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/schema/__init__.py +0 -0
  38. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/schema/manipulate_config_schema.py +0 -0
  39. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/schema/manipulate_io_schema.py +0 -0
  40. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/manipulate_sdk/schema/manipulate_program_schema.py +0 -0
  41. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/program_sdk/__init__.py +0 -0
  42. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/program_sdk/client_modules.pyi +0 -0
  43. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/program_sdk/program.py +0 -0
  44. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/program_sdk/program_interface.py +0 -0
  45. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/program_sdk/test_binding.py +0 -0
  46. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/rby1.py +0 -0
  47. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/rby1_sdk/__init__.py +0 -0
  48. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/rby1_sdk/base.py +0 -0
  49. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/rby1_sdk/client.py +0 -0
  50. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/rby1_sdk/config.py +0 -0
  51. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/rby1_sdk/control.py +0 -0
  52. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/rby1_sdk/exceptions.py +0 -0
  53. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/rby1_sdk/state.py +0 -0
  54. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/schema/__init__.py +0 -0
  55. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/schema/amr_schema.py +0 -0
  56. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/schema/base_schema.py +0 -0
  57. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/schema/manipulate_schema.py +0 -0
  58. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow/rb_sdk/schema/program_schema.py +0 -0
  59. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow_rb_sdk.egg-info/SOURCES.txt +0 -0
  60. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow_rb_sdk.egg-info/dependency_links.txt +0 -0
  61. {rainbow_rb_sdk-0.0.9.dev16 → rainbow_rb_sdk-0.0.9.dev18}/src/rainbow_rb_sdk.egg-info/top_level.txt +0 -0
@@ -1,15 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rainbow-rb-sdk
3
- Version: 0.0.9.dev16
3
+ Version: 0.0.9.dev18
4
4
  Summary: Rainbow Robotics 통합 Python SDK — AMR, 매니퓰레이터, RB-Y1 휴머노이드와 Rainbow Robot Service(common) 연동
5
5
  Author-email: Derek <dfd1123@rainbow-robotics.com>
6
6
  Requires-Python: <3.13,>=3.12
7
7
  Description-Content-Type: text/markdown
8
- Requires-Dist: rainbow-rb-utils==0.0.9.dev16
9
- Requires-Dist: rainbow-rb-zenoh==0.0.9.dev16
10
- Requires-Dist: rainbow-rb-flat-buffers==0.0.9.dev16
11
- Requires-Dist: rainbow-rb-schemas==0.0.9.dev16
12
- Requires-Dist: rainbow-rb-log==0.0.9.dev16
8
+ Requires-Dist: rainbow-rb-utils==0.0.9.dev18
9
+ Requires-Dist: rainbow-rb-zenoh==0.0.9.dev18
10
+ Requires-Dist: rainbow-rb-flat-buffers==0.0.9.dev18
11
+ Requires-Dist: rainbow-rb-schemas==0.0.9.dev18
12
+ Requires-Dist: rainbow-rb-log==0.0.9.dev18
13
13
  Requires-Dist: rby1-sdk>=0.9.1
14
14
 
15
15
  # rb_sdk
@@ -326,6 +326,137 @@ RBBaseSDK.close_all_for_pid() # 현재 프로세스의 모든 SDK 인스
326
326
 
327
327
  ---
328
328
 
329
- ## 11. 라이선스 / 문의
329
+ ## 11. Subscribe / Queryable
330
+
331
+ SDK를 상속하거나 직접 사용해 **Zenoh 이벤트를 수신(subscribe)** 하거나 **RPC 응답자(queryable)** 를 등록할 수 있습니다.
332
+
333
+ ### 11-1. `zenoh_subscribe` — 토픽 구독 (데코레이터)
334
+
335
+ ```python
336
+ from rb_sdk import RBManipulateSDK
337
+ from rb_zenoh.schema import SubscribeOptions, OverflowPolicy
338
+
339
+ sdk = RBManipulateSDK()
340
+
341
+ # dict 페이로드로 수신 (기본)
342
+ @sdk.zenoh_subscribe("amr/AMR001/status")
343
+ def on_status(*, dict_payload: dict | None, **kwargs):
344
+ print("status:", dict_payload)
345
+
346
+ # FlatBuffer 오브젝트로 수신
347
+ from rb_flat_buffers.IPC.MoveStatus import MoveStatusT
348
+
349
+ @sdk.zenoh_subscribe(
350
+ "amr/AMR001/moveStatus",
351
+ flatbuffer_obj_t=MoveStatusT,
352
+ opts=SubscribeOptions(
353
+ dispatch="queue",
354
+ overflow=OverflowPolicy.LATEST_ONLY,
355
+ parse_dict_payload=False,
356
+ ),
357
+ )
358
+ def on_move_status(*, obj_payload: MoveStatusT, **kwargs):
359
+ print("move status:", obj_payload)
360
+
361
+ # mv를 직접 받아 수동으로 파싱하는 패턴 (flatbuffer_obj_t 미지정)
362
+ from rb_flat_buffers.IPC.State_Core import State_Core
363
+
364
+ @sdk.zenoh_subscribe(
365
+ "C500920/state_core",
366
+ opts=SubscribeOptions(
367
+ dispatch="queue",
368
+ overflow=OverflowPolicy.LATEST_ONLY,
369
+ parse_dict_payload=False,
370
+ ),
371
+ )
372
+ def on_state_core(*, mv=None, **kwargs):
373
+ if mv is None:
374
+ return
375
+ obj = State_Core.GetRootAs(mv, 0)
376
+ print("motion mode:", obj.MotionMode())
377
+ ```
378
+
379
+ #### `zenoh_subscribe` 인자
380
+
381
+ | 인자 | 타입 | 기본 | 설명 |
382
+ |---|---|---|---|
383
+ | `topic` | `str` | (필수) | Zenoh key expression (예: `"amr/{model}/status"`) |
384
+ | `flatbuffer_obj_t` | FlatBuffer T 클래스 \| `None` | `None` | FlatBuffer로 역직렬화할 때 지정. `None`이면 콜백에 `mv: memoryview` 전달 |
385
+ | `opts` | `SubscribeOptions \| None` | `None` | 디스패치 / 오버플로우 옵션 |
386
+
387
+ #### `SubscribeOptions` 필드
388
+
389
+ | 필드 | 기본 | 설명 |
390
+ |---|---|---|
391
+ | `dispatch` | `"immediate"` | `"immediate"`: 수신 스레드에서 바로 콜백. `"queue"`: C++ bounded queue + 전용 dispatch 스레드 |
392
+ | `parse_dict_payload` | `True` | FlatBuffer 수신 시 `False`로 지정 |
393
+ | `overflow` | `DROP_OLDEST` | `DROP_OLDEST` / `DROP_NEW` / `LATEST_ONLY` |
394
+ | `maxsize` | `50` | `"queue"` 모드의 C++ 큐 최대 크기 |
395
+ | `rate_limit_per_sec` | `None` | 초당 최대 콜백 호출 수 |
396
+ | `sample_every` | `1` | N개 중 1개만 전달 (1 = 전부) |
397
+ | `max_async_inflight` | `1` | async 콜백 동시 실행 허용 수 |
398
+
399
+ #### 직접 subscribe (handle 보관이 필요한 경우)
400
+
401
+ 데코레이터 대신 `zenoh_client.subscribe()`를 직접 호출하면 handle을 직접 관리할 수 있습니다.
402
+
403
+ ```python
404
+ sub_handle = sdk.zenoh_client.subscribe(
405
+ "amr/AMR001/moveStatus",
406
+ callback,
407
+ flatbuffer_obj_t=MoveStatusT,
408
+ options=SubscribeOptions(dispatch="queue", overflow=OverflowPolicy.LATEST_ONLY),
409
+ )
410
+
411
+ # 구독 해제
412
+ sub_handle.close()
413
+ ```
414
+
415
+ ---
416
+
417
+ ### 11-2. `zenoh_queryable` — RPC 응답자 (데코레이터)
418
+
419
+ 원격에서 `get(keyexpr)` 요청이 오면 등록된 handler가 호출되어 응답을 반환합니다.
420
+
421
+ ```python
422
+ from rb_sdk import RBManipulateSDK
423
+
424
+ sdk = RBManipulateSDK()
425
+
426
+ # dict 요청 (payload 없음) → dict 반환
427
+ # params는 URL query string (예: ?model=C500920)을 파싱한 dict[str, str]
428
+ @sdk.zenoh_queryable("my_service/robot_status")
429
+ def handle_status_query(*, params: dict[str, str]) -> dict:
430
+ return {"status": "ok", "model": params.get("model")}
431
+
432
+ # FlatBuffer 요청 수신 → FlatBuffer 응답
433
+ from rb_flat_buffers.manipulate.RB_Functions import RB_FunctionsT
434
+
435
+ @sdk.zenoh_queryable(
436
+ "my_service/move_j",
437
+ flatbuffer_req_T_class=RB_FunctionsT,
438
+ flatbuffer_res_buf_size=256,
439
+ )
440
+ def handle_move_j(*, req: RB_FunctionsT, params: dict[str, str]) -> RB_FunctionsT:
441
+ res = RB_FunctionsT()
442
+ res.returnValue = 0
443
+ return res
444
+ ```
445
+
446
+ #### `zenoh_queryable` 인자
447
+
448
+ | 인자 | 타입 | 기본 | 설명 |
449
+ |---|---|---|---|
450
+ | `keyexpr` | `str` | (필수) | Zenoh key expression (예: `"my_service/status"`) |
451
+ | `flatbuffer_req_T_class` | FlatBuffer T 클래스 \| `None` | `None` | 요청 페이로드를 FlatBuffer로 역직렬화할 때 지정 |
452
+ | `flatbuffer_res_buf_size` | `int \| None` | `None` | FlatBuffer 응답 직렬화 버퍼 크기(바이트). FlatBuffer 응답 시 필수 |
453
+
454
+ #### 중복 등록 방지
455
+
456
+ 같은 `keyexpr`로 이미 등록된 queryable이 있으면 경고 메시지를 출력하고 기존 handler를 유지합니다. SDK `close()` 시 자동 해제됩니다.
457
+
458
+ ---
459
+
460
+ ## 12. 라이선스 / 문의
330
461
 
331
462
  © Rainbow Robotics. 내부 이슈/문의: [GitHub Issues](https://github.com/rainbow-mobile/rainbow-release-apps/issues)
@@ -1,17 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: rainbow-rb-sdk
3
- Version: 0.0.9.dev16
4
- Summary: Rainbow Robotics 통합 Python SDK — AMR, 매니퓰레이터, RB-Y1 휴머노이드와 Rainbow Robot Service(common) 연동
5
- Author-email: Derek <dfd1123@rainbow-robotics.com>
6
- Requires-Python: <3.13,>=3.12
7
- Description-Content-Type: text/markdown
8
- Requires-Dist: rainbow-rb-utils==0.0.9.dev16
9
- Requires-Dist: rainbow-rb-zenoh==0.0.9.dev16
10
- Requires-Dist: rainbow-rb-flat-buffers==0.0.9.dev16
11
- Requires-Dist: rainbow-rb-schemas==0.0.9.dev16
12
- Requires-Dist: rainbow-rb-log==0.0.9.dev16
13
- Requires-Dist: rby1-sdk>=0.9.1
14
-
15
1
  # rb_sdk
16
2
 
17
3
  Rainbow Robotics 통합 Python SDK. AMR · Manipulator · RB-Y1 양팔로봇 제어와 Rainbow Robot Service(common) 연동을 단일 API로 제공합니다.
@@ -326,6 +312,137 @@ RBBaseSDK.close_all_for_pid() # 현재 프로세스의 모든 SDK 인스
326
312
 
327
313
  ---
328
314
 
329
- ## 11. 라이선스 / 문의
315
+ ## 11. Subscribe / Queryable
316
+
317
+ SDK를 상속하거나 직접 사용해 **Zenoh 이벤트를 수신(subscribe)** 하거나 **RPC 응답자(queryable)** 를 등록할 수 있습니다.
318
+
319
+ ### 11-1. `zenoh_subscribe` — 토픽 구독 (데코레이터)
320
+
321
+ ```python
322
+ from rb_sdk import RBManipulateSDK
323
+ from rb_zenoh.schema import SubscribeOptions, OverflowPolicy
324
+
325
+ sdk = RBManipulateSDK()
326
+
327
+ # dict 페이로드로 수신 (기본)
328
+ @sdk.zenoh_subscribe("amr/AMR001/status")
329
+ def on_status(*, dict_payload: dict | None, **kwargs):
330
+ print("status:", dict_payload)
331
+
332
+ # FlatBuffer 오브젝트로 수신
333
+ from rb_flat_buffers.IPC.MoveStatus import MoveStatusT
334
+
335
+ @sdk.zenoh_subscribe(
336
+ "amr/AMR001/moveStatus",
337
+ flatbuffer_obj_t=MoveStatusT,
338
+ opts=SubscribeOptions(
339
+ dispatch="queue",
340
+ overflow=OverflowPolicy.LATEST_ONLY,
341
+ parse_dict_payload=False,
342
+ ),
343
+ )
344
+ def on_move_status(*, obj_payload: MoveStatusT, **kwargs):
345
+ print("move status:", obj_payload)
346
+
347
+ # mv를 직접 받아 수동으로 파싱하는 패턴 (flatbuffer_obj_t 미지정)
348
+ from rb_flat_buffers.IPC.State_Core import State_Core
349
+
350
+ @sdk.zenoh_subscribe(
351
+ "C500920/state_core",
352
+ opts=SubscribeOptions(
353
+ dispatch="queue",
354
+ overflow=OverflowPolicy.LATEST_ONLY,
355
+ parse_dict_payload=False,
356
+ ),
357
+ )
358
+ def on_state_core(*, mv=None, **kwargs):
359
+ if mv is None:
360
+ return
361
+ obj = State_Core.GetRootAs(mv, 0)
362
+ print("motion mode:", obj.MotionMode())
363
+ ```
364
+
365
+ #### `zenoh_subscribe` 인자
366
+
367
+ | 인자 | 타입 | 기본 | 설명 |
368
+ |---|---|---|---|
369
+ | `topic` | `str` | (필수) | Zenoh key expression (예: `"amr/{model}/status"`) |
370
+ | `flatbuffer_obj_t` | FlatBuffer T 클래스 \| `None` | `None` | FlatBuffer로 역직렬화할 때 지정. `None`이면 콜백에 `mv: memoryview` 전달 |
371
+ | `opts` | `SubscribeOptions \| None` | `None` | 디스패치 / 오버플로우 옵션 |
372
+
373
+ #### `SubscribeOptions` 필드
374
+
375
+ | 필드 | 기본 | 설명 |
376
+ |---|---|---|
377
+ | `dispatch` | `"immediate"` | `"immediate"`: 수신 스레드에서 바로 콜백. `"queue"`: C++ bounded queue + 전용 dispatch 스레드 |
378
+ | `parse_dict_payload` | `True` | FlatBuffer 수신 시 `False`로 지정 |
379
+ | `overflow` | `DROP_OLDEST` | `DROP_OLDEST` / `DROP_NEW` / `LATEST_ONLY` |
380
+ | `maxsize` | `50` | `"queue"` 모드의 C++ 큐 최대 크기 |
381
+ | `rate_limit_per_sec` | `None` | 초당 최대 콜백 호출 수 |
382
+ | `sample_every` | `1` | N개 중 1개만 전달 (1 = 전부) |
383
+ | `max_async_inflight` | `1` | async 콜백 동시 실행 허용 수 |
384
+
385
+ #### 직접 subscribe (handle 보관이 필요한 경우)
386
+
387
+ 데코레이터 대신 `zenoh_client.subscribe()`를 직접 호출하면 handle을 직접 관리할 수 있습니다.
388
+
389
+ ```python
390
+ sub_handle = sdk.zenoh_client.subscribe(
391
+ "amr/AMR001/moveStatus",
392
+ callback,
393
+ flatbuffer_obj_t=MoveStatusT,
394
+ options=SubscribeOptions(dispatch="queue", overflow=OverflowPolicy.LATEST_ONLY),
395
+ )
396
+
397
+ # 구독 해제
398
+ sub_handle.close()
399
+ ```
400
+
401
+ ---
402
+
403
+ ### 11-2. `zenoh_queryable` — RPC 응답자 (데코레이터)
404
+
405
+ 원격에서 `get(keyexpr)` 요청이 오면 등록된 handler가 호출되어 응답을 반환합니다.
406
+
407
+ ```python
408
+ from rb_sdk import RBManipulateSDK
409
+
410
+ sdk = RBManipulateSDK()
411
+
412
+ # dict 요청 (payload 없음) → dict 반환
413
+ # params는 URL query string (예: ?model=C500920)을 파싱한 dict[str, str]
414
+ @sdk.zenoh_queryable("my_service/robot_status")
415
+ def handle_status_query(*, params: dict[str, str]) -> dict:
416
+ return {"status": "ok", "model": params.get("model")}
417
+
418
+ # FlatBuffer 요청 수신 → FlatBuffer 응답
419
+ from rb_flat_buffers.manipulate.RB_Functions import RB_FunctionsT
420
+
421
+ @sdk.zenoh_queryable(
422
+ "my_service/move_j",
423
+ flatbuffer_req_T_class=RB_FunctionsT,
424
+ flatbuffer_res_buf_size=256,
425
+ )
426
+ def handle_move_j(*, req: RB_FunctionsT, params: dict[str, str]) -> RB_FunctionsT:
427
+ res = RB_FunctionsT()
428
+ res.returnValue = 0
429
+ return res
430
+ ```
431
+
432
+ #### `zenoh_queryable` 인자
433
+
434
+ | 인자 | 타입 | 기본 | 설명 |
435
+ |---|---|---|---|
436
+ | `keyexpr` | `str` | (필수) | Zenoh key expression (예: `"my_service/status"`) |
437
+ | `flatbuffer_req_T_class` | FlatBuffer T 클래스 \| `None` | `None` | 요청 페이로드를 FlatBuffer로 역직렬화할 때 지정 |
438
+ | `flatbuffer_res_buf_size` | `int \| None` | `None` | FlatBuffer 응답 직렬화 버퍼 크기(바이트). FlatBuffer 응답 시 필수 |
439
+
440
+ #### 중복 등록 방지
441
+
442
+ 같은 `keyexpr`로 이미 등록된 queryable이 있으면 경고 메시지를 출력하고 기존 handler를 유지합니다. SDK `close()` 시 자동 해제됩니다.
443
+
444
+ ---
445
+
446
+ ## 12. 라이선스 / 문의
330
447
 
331
448
  © Rainbow Robotics. 내부 이슈/문의: [GitHub Issues](https://github.com/rainbow-mobile/rainbow-release-apps/issues)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rainbow-rb-sdk"
7
- version = "0.0.9.dev16"
7
+ version = "0.0.9.dev18"
8
8
  requires-python = ">=3.12,<3.13"
9
9
  description = "Rainbow Robotics 통합 Python SDK — AMR, 매니퓰레이터, RB-Y1 휴머노이드와 Rainbow Robot Service(common) 연동"
10
10
  authors = [
@@ -13,11 +13,11 @@ authors = [
13
13
  readme = "README.md"
14
14
 
15
15
  dependencies = [
16
- "rainbow-rb-utils==0.0.9.dev16",
17
- "rainbow-rb-zenoh==0.0.9.dev16",
18
- "rainbow-rb-flat-buffers==0.0.9.dev16",
19
- "rainbow-rb-schemas==0.0.9.dev16",
20
- "rainbow-rb-log==0.0.9.dev16",
16
+ "rainbow-rb-utils==0.0.9.dev18",
17
+ "rainbow-rb-zenoh==0.0.9.dev18",
18
+ "rainbow-rb-flat-buffers==0.0.9.dev18",
19
+ "rainbow-rb-schemas==0.0.9.dev18",
20
+ "rainbow-rb-log==0.0.9.dev18",
21
21
  "rby1-sdk>=0.9.1",
22
22
  ]
23
23
 
@@ -30,4 +30,4 @@ where = ["src"]
30
30
  include = ["rainbow.rb_sdk*"]
31
31
 
32
32
  [tool.setuptools.package-data]
33
- "*" = ["py.typed"]
33
+ "*" = ["py.typed", "*.pyi", "_core*.so", "_core*.pyd"]
@@ -9,6 +9,7 @@ from rainbow.rb_flat_buffers.SLAMNAV.RequestGetSensorInfo import RequestGetSenso
9
9
  from rainbow.rb_flat_buffers.SLAMNAV.RequestGetSensorMode import RequestGetSensorModeT
10
10
  from rainbow.rb_flat_buffers.SLAMNAV.RequestGetSettingCategory import RequestGetSettingCategoryT
11
11
  from rainbow.rb_flat_buffers.SLAMNAV.RequestGetSettingParam import RequestGetSettingParamT
12
+ from rainbow.rb_flat_buffers.SLAMNAV.RequestRTSPSubscribe import RequestRTSPSubscribeT
12
13
  from rainbow.rb_flat_buffers.SLAMNAV.RequestSetPduParam import RequestSetPduParamT
13
14
  from rainbow.rb_flat_buffers.SLAMNAV.RequestSetRobotType import RequestSetRobotTypeT
14
15
  from rainbow.rb_flat_buffers.SLAMNAV.RequestSetSensorInfo import RequestSetSensorInfoT
@@ -17,10 +18,12 @@ from rainbow.rb_flat_buffers.SLAMNAV.RequestSetSettingParam import RequestSetSet
17
18
  from rainbow.rb_flat_buffers.SLAMNAV.ResponseGetDriveParam import ResponseGetDriveParamT
18
19
  from rainbow.rb_flat_buffers.SLAMNAV.ResponseGetPduParam import ResponseGetPduParamT
19
20
  from rainbow.rb_flat_buffers.SLAMNAV.ResponseGetRobotType import ResponseGetRobotTypeT
21
+ from rainbow.rb_flat_buffers.SLAMNAV.ResponseGetRTSPInfo import ResponseGetRTSPInfoT
20
22
  from rainbow.rb_flat_buffers.SLAMNAV.ResponseGetSensorInfo import ResponseGetSensorInfoT
21
23
  from rainbow.rb_flat_buffers.SLAMNAV.ResponseGetSensorMode import ResponseGetSensorModeT
22
24
  from rainbow.rb_flat_buffers.SLAMNAV.ResponseGetSettingCategory import ResponseGetSettingCategoryT
23
25
  from rainbow.rb_flat_buffers.SLAMNAV.ResponseGetSettingParam import ResponseGetSettingParamT
26
+ from rainbow.rb_flat_buffers.SLAMNAV.ResponseRTSPSubscribe import ResponseRTSPSubscribeT
24
27
  from rainbow.rb_flat_buffers.SLAMNAV.ResponseSetPduParam import ResponseSetPduParamT
25
28
  from rainbow.rb_flat_buffers.SLAMNAV.ResponseSetRobotType import ResponseSetRobotTypeT
26
29
  from rainbow.rb_flat_buffers.SLAMNAV.ResponseSetSensorInfo import ResponseSetSensorInfoT
@@ -599,70 +602,43 @@ class RBAmrSettingSDK(RBBaseSDK):
599
602
 
600
603
  return result.get("obj_payload")
601
604
 
602
- # def set_rtsp_mode(self, robot_model: str, switch: bool, cam_id: list[int], req_id: str | None = None, flow_manager_args: FlowManagerArgs | None = None) -> ResponseSetSensorModeT:
603
- # """
604
- # [RTSP 모드 설정]
605
- # - req_id: 요청 ID
606
- # - switch: RTSP 모드
607
- # - cam_id: 카메라 ID (특정 카메라만 켜기 / 없으면 전부, switch가 off면 null)
608
- # """
609
- # if req_id is None:
610
- # req_id = str(uuid.uuid4())
611
-
612
- # # 1) RequestSetRTSPModeT 객체 생성
613
- # req = RequestSetRTSPModeT()
614
- # req.id = req_id
615
- # req.switch = switch
616
- # req.cam_id = cam_id
617
-
618
- # # 2) 요청 전송
619
- # result = self.zenoh_client.query_one(
620
- # f"amr/{robot_model}/setting/setRTSPMode",
621
- # flatbuffer_req_obj=req,
622
- # flatbuffer_res_T_class=ResponseSetRTSPModeT,
623
- # flatbuffer_buf_size=125,
624
- # )
625
- # # 3) 결과 처리 및 반환
626
- # if result.get("obj_payload") is None:
627
- # raise RuntimeError("Call Set RTSP Mode failed: obj_payload is None")
628
-
629
- # if flow_manager_args is not None:
630
- # if result["dict_payload"].get("result") == "accept":
631
- # flow_manager_args.done()
632
- # else:
633
- # raise RuntimeError(result["dict_payload"].get("message"))
634
-
635
- # return result.get("obj_payload")
636
-
637
- # def get_rtsp_mode(self, robot_model: str, req_id: str | None = None, flow_manager_args: FlowManagerArgs | None = None) -> ResponseSetSensorModeT:
638
- # """
639
- # [RTSP 모드 설정]
640
- # - req_id: 요청 ID
641
- # - switch: RTSP 모드
642
- # - cam_id: 카메라 ID (특정 카메라만 켜기 / 없으면 전부, switch가 off면 null)
643
- # """
644
- # if req_id is None:
645
- # req_id = str(uuid.uuid4())
646
-
647
- # # 1) RequestSetRTSPModeT 객체 생성
648
- # req = RequestGetRTSPModeT()
649
- # req.id = req_id
650
-
651
- # # 2) 요청 전송
652
- # result = self.zenoh_client.query_one(
653
- # f"amr/{robot_model}/setting/getRTSPMode",
654
- # flatbuffer_req_obj=req,
655
- # flatbuffer_res_T_class=ResponseGetRTSPModeT,
656
- # flatbuffer_buf_size=125,
657
- # )
658
- # # 3) 결과 처리 및 반환
659
- # if result.get("obj_payload") is None:
660
- # raise RuntimeError("Call Get RTSP Mode failed: obj_payload is None")
661
-
662
- # if flow_manager_args is not None:
663
- # if result["dict_payload"].get("result") == "accept":
664
- # flow_manager_args.done()
665
- # else:
666
- # raise RuntimeError(result["dict_payload"].get("message"))
667
-
668
- # return result.get("obj_payload")
605
+ def rtsp_subscribe(self, robot_model: str, cam_id: int, quality: str) -> ResponseRTSPSubscribeT:
606
+ """
607
+ [RTSP 구독]
608
+ - robot_model: 로봇 모델
609
+ - cam_id: 카메라 ID
610
+ - quality: 비디오 품질
611
+ - ResponseRTSPSubscribeT 객체 반환
612
+ """
613
+ req = RequestRTSPSubscribeT()
614
+ req.camId = cam_id
615
+ req.quality = quality
616
+
617
+ result = self.zenoh_client.query_one(
618
+ f"amr/{robot_model}/setting/rtsp/subscribe",
619
+ flatbuffer_req_obj=req,
620
+ flatbuffer_res_T_class=ResponseRTSPSubscribeT,
621
+ flatbuffer_buf_size=125,
622
+ )
623
+
624
+ if result.get("obj_payload") is None:
625
+ raise RuntimeError("Call RTSP Subscribe failed: obj_payload is None")
626
+
627
+ return result.get("obj_payload")
628
+
629
+ def get_rtsp_info(self, robot_model: str) -> ResponseGetRTSPInfoT:
630
+ """
631
+ [RTSP 정보 조회]
632
+ - robot_model: 로봇 모델
633
+ - ResponseGetRTSPInfoT 객체 반환
634
+ """
635
+ result = self.zenoh_client.query_one(
636
+ f"amr/{robot_model}/setting/rtsp/getInfo",
637
+ flatbuffer_res_T_class=ResponseGetRTSPInfoT,
638
+ flatbuffer_buf_size=125,
639
+ )
640
+
641
+ if result.get("obj_payload") is None:
642
+ raise RuntimeError("Call Get RTSP Info failed: obj_payload is None")
643
+
644
+ return result.get("obj_payload")
@@ -50,19 +50,27 @@ class RBBaseSDK:
50
50
  # PID별 ZenohClient 인스턴스
51
51
  _zenoh_clients: ClassVar[dict[int, ZenohClient]] = {}
52
52
 
53
- _lock: ClassVar[threading.Lock] = threading.Lock()
53
+ # RLock: __new__ _refresh_zenoh_client_for_pid 재진입 가능
54
+ _lock: ClassVar[threading.RLock] = threading.RLock()
54
55
 
55
56
  @staticmethod
56
57
  def _is_client_session_alive(client: ZenohClient | None) -> bool:
57
- """Zenoh 세션 객체의 기본 생존 상태를 점검한다."""
58
+ """Zenoh 세션 객체의 기본 생존 상태를 점검한다.
59
+
60
+ C++ 마이그레이션 후 ZenohClient는 ._core (ZenohClientCore) 를 보유한다.
61
+ close() 시 ._core 가 None 으로 설정되므로 그것을 생존 신호로 사용한다.
62
+ """
58
63
  if client is None:
59
64
  return False
60
65
 
66
+ # C++ core 경로 (현재 구현)
67
+ if getattr(client, "_core", None) is not None:
68
+ return True
69
+
70
+ # 레거시 python-zenoh 경로 호환 (혹시 남아 있을 경우 대비)
61
71
  session = getattr(client, "session", None)
62
72
  if session is None:
63
73
  return False
64
-
65
- # zenoh 바인딩 버전에 따라 closed/is_closed 형태가 다를 수 있다.
66
74
  for attr_name in ("is_closed", "closed"):
67
75
  attr = getattr(session, attr_name, None)
68
76
  if attr is None:
@@ -710,6 +718,17 @@ class RBBaseSDK:
710
718
  )
711
719
 
712
720
  print(f"[SDK] disconnected zenoh peer {peer_id}", flush=True)
721
+
722
+ # peer 해제 후 Zenoh 세션도 닫아 gossip/multihop 경로까지 완전히 차단
723
+ self._cleanup_resources()
724
+ pid = getattr(self, "_pid", None)
725
+ if pid is not None:
726
+ with RBBaseSDK._lock:
727
+ zenoh_client = RBBaseSDK._zenoh_clients.pop(pid, None)
728
+ if zenoh_client is not None:
729
+ with contextlib.suppress(Exception):
730
+ zenoh_client.close()
731
+
713
732
  return True
714
733
 
715
734
  async def _heartbeat_loop(self, peer_id: str, *, ttl: int, interval: float) -> None: