rainbow-rb-sdk 0.0.9.dev18__tar.gz → 0.0.9.dev20__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.dev18/src/rainbow_rb_sdk.egg-info → rainbow_rb_sdk-0.0.9.dev20}/PKG-INFO +65 -41
  2. rainbow_rb_sdk-0.0.9.dev18/PKG-INFO → rainbow_rb_sdk-0.0.9.dev20/README.md +58 -48
  3. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/pyproject.toml +7 -7
  4. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/base.py +32 -6
  5. rainbow_rb_sdk-0.0.9.dev18/README.md → rainbow_rb_sdk-0.0.9.dev20/src/rainbow_rb_sdk.egg-info/PKG-INFO +72 -34
  6. rainbow_rb_sdk-0.0.9.dev20/src/rainbow_rb_sdk.egg-info/requires.txt +6 -0
  7. rainbow_rb_sdk-0.0.9.dev18/src/rainbow_rb_sdk.egg-info/requires.txt +0 -6
  8. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/setup.cfg +0 -0
  9. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/__init__.py +0 -0
  10. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr.py +0 -0
  11. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr_sdk/__init__.py +0 -0
  12. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr_sdk/amr_accessory.py +0 -0
  13. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr_sdk/amr_capability.py +0 -0
  14. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr_sdk/amr_control.py +0 -0
  15. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr_sdk/amr_file.py +0 -0
  16. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr_sdk/amr_localization.py +0 -0
  17. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr_sdk/amr_map.py +0 -0
  18. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr_sdk/amr_move.py +0 -0
  19. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr_sdk/amr_program.py +0 -0
  20. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr_sdk/amr_setting.py +0 -0
  21. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr_sdk/amr_status.py +0 -0
  22. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/amr_sdk/schema/__init__.py +0 -0
  23. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/base_sdk/__init__.py +0 -0
  24. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/base_sdk/base_schema.py +0 -0
  25. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate.py +0 -0
  26. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/__init__.py +0 -0
  27. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_config.py +0 -0
  28. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_get_data.py +0 -0
  29. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_io.py +0 -0
  30. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_maintenance.py +0 -0
  31. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_move.py +0 -0
  32. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_point.py +0 -0
  33. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_program.py +0 -0
  34. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_service.py +0 -0
  35. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/manipulate_state.py +0 -0
  36. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/schema/__init__.py +0 -0
  37. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/schema/manipulate_config_schema.py +0 -0
  38. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/schema/manipulate_io_schema.py +0 -0
  39. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/schema/manipulate_move_schema.py +0 -0
  40. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/manipulate_sdk/schema/manipulate_program_schema.py +0 -0
  41. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/program_sdk/__init__.py +0 -0
  42. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/program_sdk/client_modules.pyi +0 -0
  43. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/program_sdk/program.py +0 -0
  44. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/program_sdk/program_interface.py +0 -0
  45. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/program_sdk/test_binding.py +0 -0
  46. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/rby1.py +0 -0
  47. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/rby1_sdk/__init__.py +0 -0
  48. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/rby1_sdk/base.py +0 -0
  49. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/rby1_sdk/client.py +0 -0
  50. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/rby1_sdk/config.py +0 -0
  51. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/rby1_sdk/control.py +0 -0
  52. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/rby1_sdk/exceptions.py +0 -0
  53. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/rby1_sdk/state.py +0 -0
  54. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/schema/__init__.py +0 -0
  55. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/schema/amr_schema.py +0 -0
  56. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/schema/base_schema.py +0 -0
  57. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/schema/manipulate_schema.py +0 -0
  58. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow/rb_sdk/schema/program_schema.py +0 -0
  59. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow_rb_sdk.egg-info/SOURCES.txt +0 -0
  60. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/src/rainbow_rb_sdk.egg-info/dependency_links.txt +0 -0
  61. {rainbow_rb_sdk-0.0.9.dev18 → rainbow_rb_sdk-0.0.9.dev20}/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.dev18
3
+ Version: 0.0.9.dev20
4
4
  Summary: Rainbow Robotics 통합 Python SDK — AMR, 매니퓰레이터, RB-Y1 휴머노이드와 Rainbow Robot Service(common) 연동
5
5
  Author-email: Derek <dfd1123@rainbow-robotics.com>
6
- Requires-Python: <3.13,>=3.12
6
+ Requires-Python: >=3.11
7
7
  Description-Content-Type: text/markdown
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
8
+ Requires-Dist: rainbow-rb-utils==0.0.9.dev20
9
+ Requires-Dist: rainbow-rb-zenoh==0.0.9.dev20
10
+ Requires-Dist: rainbow-rb-flat-buffers==0.0.9.dev20
11
+ Requires-Dist: rainbow-rb-schemas==0.0.9.dev20
12
+ Requires-Dist: rainbow-rb-log==0.0.9.dev20
13
13
  Requires-Dist: rby1-sdk>=0.9.1
14
14
 
15
15
  # rb_sdk
@@ -67,24 +67,50 @@ manipulate.move.call_move_j(
67
67
  ```python
68
68
  import asyncio
69
69
  from rb_sdk import RBManipulateSDK
70
+ from rb_flat_buffers.IPC.State_Core import State_CoreT
71
+ from rb_zenoh.schema import SubscribeOptions
70
72
 
71
- async def main():
72
- sdk = RBManipulateSDK()
73
-
74
- # 로봇(common 서비스)에 외부 peer로 등록 + 자동 heartbeat 시작
75
- peer_id = await sdk.connect(
76
- token="외부 서비스 Token", # Muscat이 생성한 서비스 Token
77
- host="192.168.1.100", # 로봇 IP
78
- # ttl=30, # 서버 측 세션 TTL(초). heartbeat 끊기면 자동 해제
79
- # zenoh_port=None, # None → OS가 빈 포트 자동 배정 (충돌 없음)
80
- # heartbeat_interval=15.0, # 기본: ttl / 2
81
- )
73
+ sdk = RBManipulateSDK()
82
74
 
83
- sdk.move.call_move_j(robot_model="C500920", target={...})
84
75
 
85
- await sdk.disconnect()
76
+ async def main():
77
+ # ⚠️ subscribe는 반드시 connect() 이후에 등록해야 한다.
78
+ # connect() 내부에서 ZenohClient를 close() 후 재연결하므로
79
+ # connect() 전에 등록한 subscribe는 세션과 함께 모두 사라진다.
80
+ await sdk.connect(
81
+ token="서비스 Token",
82
+ host="192.168.1.100",
83
+ # ttl=30,
84
+ # zenoh_port=None,
85
+ # heartbeat_interval=15.0,
86
+ )
86
87
 
87
- asyncio.run(main())
88
+ @sdk.zenoh_subscribe(
89
+ "C500920/state_core",
90
+ flatbuffer_obj_t=State_CoreT,
91
+ opts=SubscribeOptions(parse_dict_payload=False),
92
+ )
93
+ def on_state_core(*, obj_payload: State_CoreT | None, **kwargs):
94
+ if obj_payload is None:
95
+ return
96
+ print("motion mode:", obj_payload.motionMode)
97
+
98
+ try:
99
+ # heartbeat task는 asyncio.run()이 살아있는 동안만 동작한다.
100
+ # asyncio.run()이 반환되면 event loop가 닫히고 heartbeat가 취소되어
101
+ # TTL 후 서버가 peer를 제거하므로 loop 안에서 대기해야 한다.
102
+ while True:
103
+ await asyncio.sleep(1)
104
+ except asyncio.CancelledError:
105
+ pass
106
+ finally:
107
+ await sdk.disconnect()
108
+
109
+
110
+ try:
111
+ asyncio.run(main())
112
+ except KeyboardInterrupt:
113
+ print("Ctrl+C pressed")
88
114
  ```
89
115
 
90
116
  #### 주요 특징
@@ -338,42 +364,40 @@ from rb_zenoh.schema import SubscribeOptions, OverflowPolicy
338
364
 
339
365
  sdk = RBManipulateSDK()
340
366
 
341
- # dict 페이로드로 수신 (기본)
367
+ # ── 패턴 1: dict 페이로드 수신 (JSON 토픽) ──
342
368
  @sdk.zenoh_subscribe("amr/AMR001/status")
343
369
  def on_status(*, dict_payload: dict | None, **kwargs):
344
370
  print("status:", dict_payload)
345
371
 
346
- # FlatBuffer 오브젝트로 수신
347
- from rb_flat_buffers.IPC.MoveStatus import MoveStatusT
372
+ # ── 패턴 2: Object API (T 클래스) — 권장 ──
373
+ # flatbuffer_obj_t 지정 시 InitFromPackedBuf로 역직렬화된 T 객체가 obj_payload로 전달됨
374
+ # T 클래스 필드는 snake_case 속성으로 직접 접근 가능
375
+ from rb_flat_buffers.IPC.State_Core import State_CoreT
348
376
 
349
377
  @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
- ),
378
+ "C500920/state_core",
379
+ flatbuffer_obj_t=State_CoreT,
380
+ opts=SubscribeOptions(parse_dict_payload=False),
357
381
  )
358
- def on_move_status(*, obj_payload: MoveStatusT, **kwargs):
359
- print("move status:", obj_payload)
382
+ def on_state_core(*, obj_payload: State_CoreT | None, **kwargs):
383
+ if obj_payload is None:
384
+ return
385
+ print("motion mode:", obj_payload.motionMode) # snake_case 속성
360
386
 
361
- # mv 직접 받아 수동으로 파싱하는 패턴 (flatbuffer_obj_t 미지정)
387
+ # ── 패턴 3: Table API (mv + GetRootAs) lazy access, 성능 우선 시 ──
388
+ # flatbuffer_obj_t 미지정 → mv(memoryview)를 직접 받아 수동 파싱
389
+ # GetRootAs는 필요한 필드만 lazy 접근하므로 T 클래스보다 빠름
362
390
  from rb_flat_buffers.IPC.State_Core import State_Core
363
391
 
364
392
  @sdk.zenoh_subscribe(
365
393
  "C500920/state_core",
366
- opts=SubscribeOptions(
367
- dispatch="queue",
368
- overflow=OverflowPolicy.LATEST_ONLY,
369
- parse_dict_payload=False,
370
- ),
394
+ opts=SubscribeOptions(parse_dict_payload=False),
371
395
  )
372
- def on_state_core(*, mv=None, **kwargs):
396
+ def on_state_core_mv(*, mv=None, **kwargs):
373
397
  if mv is None:
374
398
  return
375
399
  obj = State_Core.GetRootAs(mv, 0)
376
- print("motion mode:", obj.MotionMode())
400
+ print("motion mode:", obj.MotionMode()) # 메서드 호출
377
401
  ```
378
402
 
379
403
  #### `zenoh_subscribe` 인자
@@ -1,17 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: rainbow-rb-sdk
3
- Version: 0.0.9.dev18
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.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
- 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로 제공합니다.
@@ -67,24 +53,50 @@ manipulate.move.call_move_j(
67
53
  ```python
68
54
  import asyncio
69
55
  from rb_sdk import RBManipulateSDK
56
+ from rb_flat_buffers.IPC.State_Core import State_CoreT
57
+ from rb_zenoh.schema import SubscribeOptions
70
58
 
71
- async def main():
72
- sdk = RBManipulateSDK()
73
-
74
- # 로봇(common 서비스)에 외부 peer로 등록 + 자동 heartbeat 시작
75
- peer_id = await sdk.connect(
76
- token="외부 서비스 Token", # Muscat이 생성한 서비스 Token
77
- host="192.168.1.100", # 로봇 IP
78
- # ttl=30, # 서버 측 세션 TTL(초). heartbeat 끊기면 자동 해제
79
- # zenoh_port=None, # None → OS가 빈 포트 자동 배정 (충돌 없음)
80
- # heartbeat_interval=15.0, # 기본: ttl / 2
81
- )
59
+ sdk = RBManipulateSDK()
82
60
 
83
- sdk.move.call_move_j(robot_model="C500920", target={...})
84
61
 
85
- await sdk.disconnect()
62
+ async def main():
63
+ # ⚠️ subscribe는 반드시 connect() 이후에 등록해야 한다.
64
+ # connect() 내부에서 ZenohClient를 close() 후 재연결하므로
65
+ # connect() 전에 등록한 subscribe는 세션과 함께 모두 사라진다.
66
+ await sdk.connect(
67
+ token="서비스 Token",
68
+ host="192.168.1.100",
69
+ # ttl=30,
70
+ # zenoh_port=None,
71
+ # heartbeat_interval=15.0,
72
+ )
86
73
 
87
- asyncio.run(main())
74
+ @sdk.zenoh_subscribe(
75
+ "C500920/state_core",
76
+ flatbuffer_obj_t=State_CoreT,
77
+ opts=SubscribeOptions(parse_dict_payload=False),
78
+ )
79
+ def on_state_core(*, obj_payload: State_CoreT | None, **kwargs):
80
+ if obj_payload is None:
81
+ return
82
+ print("motion mode:", obj_payload.motionMode)
83
+
84
+ try:
85
+ # heartbeat task는 asyncio.run()이 살아있는 동안만 동작한다.
86
+ # asyncio.run()이 반환되면 event loop가 닫히고 heartbeat가 취소되어
87
+ # TTL 후 서버가 peer를 제거하므로 loop 안에서 대기해야 한다.
88
+ while True:
89
+ await asyncio.sleep(1)
90
+ except asyncio.CancelledError:
91
+ pass
92
+ finally:
93
+ await sdk.disconnect()
94
+
95
+
96
+ try:
97
+ asyncio.run(main())
98
+ except KeyboardInterrupt:
99
+ print("Ctrl+C pressed")
88
100
  ```
89
101
 
90
102
  #### 주요 특징
@@ -338,42 +350,40 @@ from rb_zenoh.schema import SubscribeOptions, OverflowPolicy
338
350
 
339
351
  sdk = RBManipulateSDK()
340
352
 
341
- # dict 페이로드로 수신 (기본)
353
+ # ── 패턴 1: dict 페이로드 수신 (JSON 토픽) ──
342
354
  @sdk.zenoh_subscribe("amr/AMR001/status")
343
355
  def on_status(*, dict_payload: dict | None, **kwargs):
344
356
  print("status:", dict_payload)
345
357
 
346
- # FlatBuffer 오브젝트로 수신
347
- from rb_flat_buffers.IPC.MoveStatus import MoveStatusT
358
+ # ── 패턴 2: Object API (T 클래스) — 권장 ──
359
+ # flatbuffer_obj_t 지정 시 InitFromPackedBuf로 역직렬화된 T 객체가 obj_payload로 전달됨
360
+ # T 클래스 필드는 snake_case 속성으로 직접 접근 가능
361
+ from rb_flat_buffers.IPC.State_Core import State_CoreT
348
362
 
349
363
  @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
- ),
364
+ "C500920/state_core",
365
+ flatbuffer_obj_t=State_CoreT,
366
+ opts=SubscribeOptions(parse_dict_payload=False),
357
367
  )
358
- def on_move_status(*, obj_payload: MoveStatusT, **kwargs):
359
- print("move status:", obj_payload)
368
+ def on_state_core(*, obj_payload: State_CoreT | None, **kwargs):
369
+ if obj_payload is None:
370
+ return
371
+ print("motion mode:", obj_payload.motionMode) # snake_case 속성
360
372
 
361
- # mv 직접 받아 수동으로 파싱하는 패턴 (flatbuffer_obj_t 미지정)
373
+ # ── 패턴 3: Table API (mv + GetRootAs) lazy access, 성능 우선 시 ──
374
+ # flatbuffer_obj_t 미지정 → mv(memoryview)를 직접 받아 수동 파싱
375
+ # GetRootAs는 필요한 필드만 lazy 접근하므로 T 클래스보다 빠름
362
376
  from rb_flat_buffers.IPC.State_Core import State_Core
363
377
 
364
378
  @sdk.zenoh_subscribe(
365
379
  "C500920/state_core",
366
- opts=SubscribeOptions(
367
- dispatch="queue",
368
- overflow=OverflowPolicy.LATEST_ONLY,
369
- parse_dict_payload=False,
370
- ),
380
+ opts=SubscribeOptions(parse_dict_payload=False),
371
381
  )
372
- def on_state_core(*, mv=None, **kwargs):
382
+ def on_state_core_mv(*, mv=None, **kwargs):
373
383
  if mv is None:
374
384
  return
375
385
  obj = State_Core.GetRootAs(mv, 0)
376
- print("motion mode:", obj.MotionMode())
386
+ print("motion mode:", obj.MotionMode()) # 메서드 호출
377
387
  ```
378
388
 
379
389
  #### `zenoh_subscribe` 인자
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "rainbow-rb-sdk"
7
- version = "0.0.9.dev18"
8
- requires-python = ">=3.12,<3.13"
7
+ version = "0.0.9.dev20"
8
+ requires-python = ">=3.11"
9
9
  description = "Rainbow Robotics 통합 Python SDK — AMR, 매니퓰레이터, RB-Y1 휴머노이드와 Rainbow Robot Service(common) 연동"
10
10
  authors = [
11
11
  { name = "Derek", email = "dfd1123@rainbow-robotics.com" },
@@ -13,11 +13,11 @@ authors = [
13
13
  readme = "README.md"
14
14
 
15
15
  dependencies = [
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",
16
+ "rainbow-rb-utils==0.0.9.dev20",
17
+ "rainbow-rb-zenoh==0.0.9.dev20",
18
+ "rainbow-rb-flat-buffers==0.0.9.dev20",
19
+ "rainbow-rb-schemas==0.0.9.dev20",
20
+ "rainbow-rb-log==0.0.9.dev20",
21
21
  "rby1-sdk>=0.9.1",
22
22
  ]
23
23
 
@@ -145,7 +145,16 @@ class RBBaseSDK:
145
145
  async def _async_wrapper(*args, **kwargs):
146
146
  try:
147
147
  if args and isinstance(args[0], RBBaseSDK):
148
- args[0]._ensure_zenoh_client_alive()
148
+ sdk_inst = args[0]
149
+ # disconnect() 후 명시적 close 상태이면 auto-reconnect를 막는다.
150
+ # C++ manually_closed_ 플래그를 Python facade를 통해 확인.
151
+ zc = getattr(sdk_inst, "zenoh_client", None)
152
+ if zc is not None and getattr(zc, "manually_closed", False):
153
+ raise RuntimeError(
154
+ "Zenoh session was explicitly closed via disconnect(). "
155
+ "Call connect() before using the SDK again."
156
+ )
157
+ sdk_inst._ensure_zenoh_client_alive()
149
158
  return await fn(*args, **kwargs)
150
159
  except (TypeError, ValueError, AttributeError, KeyError) as e:
151
160
  print(f"[{fn.__name__}] invalid param: {e}", flush=True)
@@ -182,7 +191,14 @@ class RBBaseSDK:
182
191
  def _sync_wrapper(*args, **kwargs):
183
192
  try:
184
193
  if args and isinstance(args[0], RBBaseSDK):
185
- args[0]._ensure_zenoh_client_alive()
194
+ sdk_inst = args[0]
195
+ zc = getattr(sdk_inst, "zenoh_client", None)
196
+ if zc is not None and getattr(zc, "manually_closed", False):
197
+ raise RuntimeError(
198
+ "Zenoh session was explicitly closed via disconnect(). "
199
+ "Call connect() before using the SDK again."
200
+ )
201
+ sdk_inst._ensure_zenoh_client_alive()
186
202
  return fn(*args, **kwargs)
187
203
  except (TypeError, ValueError, AttributeError, KeyError) as e:
188
204
  print(f"[{fn.__name__}] invalid param: {e}", flush=True)
@@ -477,10 +493,17 @@ class RBBaseSDK:
477
493
  """
478
494
  self._merge_endpoint_env("ZENOH_PEER_LISTEN_ENDPOINTS", f"tcp/0.0.0.0:{listen_port}")
479
495
 
480
- zenoh_client = self._refresh_zenoh_client_for_pid(self._pid)
496
+ # connect() 명시 호출: manually_closed 상태이더라도 재연결을 허용한다.
497
+ # dict에 기존 client가 있으면 그대로 쓰고, 없으면 새로 만든다.
498
+ with RBBaseSDK._lock:
499
+ zenoh_client = RBBaseSDK._zenoh_clients.get(self._pid)
500
+ if zenoh_client is None:
501
+ zenoh_client = ZenohClient()
502
+ RBBaseSDK._zenoh_clients[self._pid] = zenoh_client
503
+ self.zenoh_client = zenoh_client
481
504
  with contextlib.suppress(Exception):
482
505
  zenoh_client.close()
483
- zenoh_client.connect()
506
+ zenoh_client.connect() # C++ connect_with_pairs clears manually_closed_
484
507
 
485
508
  async def _wait_for_zenoh_echo(
486
509
  self,
@@ -719,12 +742,15 @@ class RBBaseSDK:
719
742
 
720
743
  print(f"[SDK] disconnected zenoh peer {peer_id}", flush=True)
721
744
 
722
- # peer 해제 후 Zenoh 세션도 닫아 gossip/multihop 경로까지 완전히 차단
745
+ # peer 해제 후 Zenoh 세션도 닫아 gossip/multihop 경로까지 완전히 차단.
746
+ # 주의: dict에서 pop하지 않고 close()만 한다.
747
+ # → _zenoh_clients에 manually_closed 상태의 client가 남아있게 되어
748
+ # _refresh_zenoh_client_for_pid 에서 auto-reconnect를 막을 수 있다.
723
749
  self._cleanup_resources()
724
750
  pid = getattr(self, "_pid", None)
725
751
  if pid is not None:
726
752
  with RBBaseSDK._lock:
727
- zenoh_client = RBBaseSDK._zenoh_clients.pop(pid, None)
753
+ zenoh_client = RBBaseSDK._zenoh_clients.get(pid)
728
754
  if zenoh_client is not None:
729
755
  with contextlib.suppress(Exception):
730
756
  zenoh_client.close()
@@ -1,3 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: rainbow-rb-sdk
3
+ Version: 0.0.9.dev20
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.11
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: rainbow-rb-utils==0.0.9.dev20
9
+ Requires-Dist: rainbow-rb-zenoh==0.0.9.dev20
10
+ Requires-Dist: rainbow-rb-flat-buffers==0.0.9.dev20
11
+ Requires-Dist: rainbow-rb-schemas==0.0.9.dev20
12
+ Requires-Dist: rainbow-rb-log==0.0.9.dev20
13
+ Requires-Dist: rby1-sdk>=0.9.1
14
+
1
15
  # rb_sdk
2
16
 
3
17
  Rainbow Robotics 통합 Python SDK. AMR · Manipulator · RB-Y1 양팔로봇 제어와 Rainbow Robot Service(common) 연동을 단일 API로 제공합니다.
@@ -53,24 +67,50 @@ manipulate.move.call_move_j(
53
67
  ```python
54
68
  import asyncio
55
69
  from rb_sdk import RBManipulateSDK
70
+ from rb_flat_buffers.IPC.State_Core import State_CoreT
71
+ from rb_zenoh.schema import SubscribeOptions
56
72
 
57
- async def main():
58
- sdk = RBManipulateSDK()
59
-
60
- # 로봇(common 서비스)에 외부 peer로 등록 + 자동 heartbeat 시작
61
- peer_id = await sdk.connect(
62
- token="외부 서비스 Token", # Muscat이 생성한 서비스 Token
63
- host="192.168.1.100", # 로봇 IP
64
- # ttl=30, # 서버 측 세션 TTL(초). heartbeat 끊기면 자동 해제
65
- # zenoh_port=None, # None → OS가 빈 포트 자동 배정 (충돌 없음)
66
- # heartbeat_interval=15.0, # 기본: ttl / 2
67
- )
73
+ sdk = RBManipulateSDK()
68
74
 
69
- sdk.move.call_move_j(robot_model="C500920", target={...})
70
75
 
71
- await sdk.disconnect()
76
+ async def main():
77
+ # ⚠️ subscribe는 반드시 connect() 이후에 등록해야 한다.
78
+ # connect() 내부에서 ZenohClient를 close() 후 재연결하므로
79
+ # connect() 전에 등록한 subscribe는 세션과 함께 모두 사라진다.
80
+ await sdk.connect(
81
+ token="서비스 Token",
82
+ host="192.168.1.100",
83
+ # ttl=30,
84
+ # zenoh_port=None,
85
+ # heartbeat_interval=15.0,
86
+ )
72
87
 
73
- asyncio.run(main())
88
+ @sdk.zenoh_subscribe(
89
+ "C500920/state_core",
90
+ flatbuffer_obj_t=State_CoreT,
91
+ opts=SubscribeOptions(parse_dict_payload=False),
92
+ )
93
+ def on_state_core(*, obj_payload: State_CoreT | None, **kwargs):
94
+ if obj_payload is None:
95
+ return
96
+ print("motion mode:", obj_payload.motionMode)
97
+
98
+ try:
99
+ # heartbeat task는 asyncio.run()이 살아있는 동안만 동작한다.
100
+ # asyncio.run()이 반환되면 event loop가 닫히고 heartbeat가 취소되어
101
+ # TTL 후 서버가 peer를 제거하므로 loop 안에서 대기해야 한다.
102
+ while True:
103
+ await asyncio.sleep(1)
104
+ except asyncio.CancelledError:
105
+ pass
106
+ finally:
107
+ await sdk.disconnect()
108
+
109
+
110
+ try:
111
+ asyncio.run(main())
112
+ except KeyboardInterrupt:
113
+ print("Ctrl+C pressed")
74
114
  ```
75
115
 
76
116
  #### 주요 특징
@@ -324,42 +364,40 @@ from rb_zenoh.schema import SubscribeOptions, OverflowPolicy
324
364
 
325
365
  sdk = RBManipulateSDK()
326
366
 
327
- # dict 페이로드로 수신 (기본)
367
+ # ── 패턴 1: dict 페이로드 수신 (JSON 토픽) ──
328
368
  @sdk.zenoh_subscribe("amr/AMR001/status")
329
369
  def on_status(*, dict_payload: dict | None, **kwargs):
330
370
  print("status:", dict_payload)
331
371
 
332
- # FlatBuffer 오브젝트로 수신
333
- from rb_flat_buffers.IPC.MoveStatus import MoveStatusT
372
+ # ── 패턴 2: Object API (T 클래스) — 권장 ──
373
+ # flatbuffer_obj_t 지정 시 InitFromPackedBuf로 역직렬화된 T 객체가 obj_payload로 전달됨
374
+ # T 클래스 필드는 snake_case 속성으로 직접 접근 가능
375
+ from rb_flat_buffers.IPC.State_Core import State_CoreT
334
376
 
335
377
  @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
- ),
378
+ "C500920/state_core",
379
+ flatbuffer_obj_t=State_CoreT,
380
+ opts=SubscribeOptions(parse_dict_payload=False),
343
381
  )
344
- def on_move_status(*, obj_payload: MoveStatusT, **kwargs):
345
- print("move status:", obj_payload)
382
+ def on_state_core(*, obj_payload: State_CoreT | None, **kwargs):
383
+ if obj_payload is None:
384
+ return
385
+ print("motion mode:", obj_payload.motionMode) # snake_case 속성
346
386
 
347
- # mv 직접 받아 수동으로 파싱하는 패턴 (flatbuffer_obj_t 미지정)
387
+ # ── 패턴 3: Table API (mv + GetRootAs) lazy access, 성능 우선 시 ──
388
+ # flatbuffer_obj_t 미지정 → mv(memoryview)를 직접 받아 수동 파싱
389
+ # GetRootAs는 필요한 필드만 lazy 접근하므로 T 클래스보다 빠름
348
390
  from rb_flat_buffers.IPC.State_Core import State_Core
349
391
 
350
392
  @sdk.zenoh_subscribe(
351
393
  "C500920/state_core",
352
- opts=SubscribeOptions(
353
- dispatch="queue",
354
- overflow=OverflowPolicy.LATEST_ONLY,
355
- parse_dict_payload=False,
356
- ),
394
+ opts=SubscribeOptions(parse_dict_payload=False),
357
395
  )
358
- def on_state_core(*, mv=None, **kwargs):
396
+ def on_state_core_mv(*, mv=None, **kwargs):
359
397
  if mv is None:
360
398
  return
361
399
  obj = State_Core.GetRootAs(mv, 0)
362
- print("motion mode:", obj.MotionMode())
400
+ print("motion mode:", obj.MotionMode()) # 메서드 호출
363
401
  ```
364
402
 
365
403
  #### `zenoh_subscribe` 인자
@@ -0,0 +1,6 @@
1
+ rainbow-rb-utils==0.0.9.dev20
2
+ rainbow-rb-zenoh==0.0.9.dev20
3
+ rainbow-rb-flat-buffers==0.0.9.dev20
4
+ rainbow-rb-schemas==0.0.9.dev20
5
+ rainbow-rb-log==0.0.9.dev20
6
+ rby1-sdk>=0.9.1
@@ -1,6 +0,0 @@
1
- rainbow-rb-utils==0.0.9.dev18
2
- rainbow-rb-zenoh==0.0.9.dev18
3
- rainbow-rb-flat-buffers==0.0.9.dev18
4
- rainbow-rb-schemas==0.0.9.dev18
5
- rainbow-rb-log==0.0.9.dev18
6
- rby1-sdk>=0.9.1