hex-zmq-servers 0.3.9__py3-none-any.whl

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 (110) hide show
  1. hex_zmq_servers/__init__.py +173 -0
  2. hex_zmq_servers/cam/__init__.py +52 -0
  3. hex_zmq_servers/cam/berxel/__init__.py +17 -0
  4. hex_zmq_servers/cam/berxel/cam_berxel.py +282 -0
  5. hex_zmq_servers/cam/berxel/cam_berxel_cli.py +33 -0
  6. hex_zmq_servers/cam/berxel/cam_berxel_srv.py +79 -0
  7. hex_zmq_servers/cam/cam_base.py +189 -0
  8. hex_zmq_servers/cam/dummy/__init__.py +17 -0
  9. hex_zmq_servers/cam/dummy/cam_dummy.py +69 -0
  10. hex_zmq_servers/cam/dummy/cam_dummy_cli.py +29 -0
  11. hex_zmq_servers/cam/dummy/cam_dummy_srv.py +68 -0
  12. hex_zmq_servers/cam/realsense/__init__.py +17 -0
  13. hex_zmq_servers/cam/realsense/cam_realsense.py +159 -0
  14. hex_zmq_servers/cam/realsense/cam_realsense_cli.py +33 -0
  15. hex_zmq_servers/cam/realsense/cam_realsense_srv.py +78 -0
  16. hex_zmq_servers/cam/rgb/__init__.py +17 -0
  17. hex_zmq_servers/cam/rgb/cam_rgb.py +135 -0
  18. hex_zmq_servers/cam/rgb/cam_rgb_cli.py +43 -0
  19. hex_zmq_servers/cam/rgb/cam_rgb_srv.py +78 -0
  20. hex_zmq_servers/config/cam_berxel.json +18 -0
  21. hex_zmq_servers/config/cam_dummy.json +12 -0
  22. hex_zmq_servers/config/cam_realsense.json +17 -0
  23. hex_zmq_servers/config/cam_rgb.json +28 -0
  24. hex_zmq_servers/config/mujoco_archer_y6.json +37 -0
  25. hex_zmq_servers/config/mujoco_e3_desktop.json +41 -0
  26. hex_zmq_servers/config/robot_dummy.json +153 -0
  27. hex_zmq_servers/config/robot_gello.json +66 -0
  28. hex_zmq_servers/config/robot_hexarm.json +37 -0
  29. hex_zmq_servers/config/zmq_dummy.json +12 -0
  30. hex_zmq_servers/device_base.py +44 -0
  31. hex_zmq_servers/hex_launch.py +489 -0
  32. hex_zmq_servers/mujoco/__init__.py +28 -0
  33. hex_zmq_servers/mujoco/archer_y6/__init__.py +17 -0
  34. hex_zmq_servers/mujoco/archer_y6/model/assets/arm_base_link.STL +0 -0
  35. hex_zmq_servers/mujoco/archer_y6/model/assets/arm_link_1.STL +0 -0
  36. hex_zmq_servers/mujoco/archer_y6/model/assets/arm_link_2.STL +0 -0
  37. hex_zmq_servers/mujoco/archer_y6/model/assets/arm_link_3.STL +0 -0
  38. hex_zmq_servers/mujoco/archer_y6/model/assets/arm_link_4.STL +0 -0
  39. hex_zmq_servers/mujoco/archer_y6/model/assets/arm_link_5.STL +0 -0
  40. hex_zmq_servers/mujoco/archer_y6/model/assets/assets.xml +17 -0
  41. hex_zmq_servers/mujoco/archer_y6/model/assets/camera_link.STL +0 -0
  42. hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_base_link.STL +0 -0
  43. hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_left_helper_link.STL +0 -0
  44. hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_left_link_1.STL +0 -0
  45. hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_left_link_2.STL +0 -0
  46. hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_right_helper_link.STL +0 -0
  47. hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_right_link_1.STL +0 -0
  48. hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_right_link_2.STL +0 -0
  49. hex_zmq_servers/mujoco/archer_y6/model/assets/table_link.STL +0 -0
  50. hex_zmq_servers/mujoco/archer_y6/model/robot.xml +95 -0
  51. hex_zmq_servers/mujoco/archer_y6/model/scene.xml +51 -0
  52. hex_zmq_servers/mujoco/archer_y6/model/setting.xml +37 -0
  53. hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6.py +325 -0
  54. hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6_cli.py +71 -0
  55. hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6_srv.py +148 -0
  56. hex_zmq_servers/mujoco/e3_desktop/__init__.py +17 -0
  57. hex_zmq_servers/mujoco/e3_desktop/model/assets/arm_base_link.STL +0 -0
  58. hex_zmq_servers/mujoco/e3_desktop/model/assets/arm_link_1.STL +0 -0
  59. hex_zmq_servers/mujoco/e3_desktop/model/assets/arm_link_2.STL +0 -0
  60. hex_zmq_servers/mujoco/e3_desktop/model/assets/arm_link_3.STL +0 -0
  61. hex_zmq_servers/mujoco/e3_desktop/model/assets/arm_link_4.STL +0 -0
  62. hex_zmq_servers/mujoco/e3_desktop/model/assets/arm_link_5.STL +0 -0
  63. hex_zmq_servers/mujoco/e3_desktop/model/assets/assets.xml +18 -0
  64. hex_zmq_servers/mujoco/e3_desktop/model/assets/camera_link.STL +0 -0
  65. hex_zmq_servers/mujoco/e3_desktop/model/assets/e3_desktop_base_link.STL +0 -0
  66. hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_base_link.STL +0 -0
  67. hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_left_helper_link.STL +0 -0
  68. hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_left_link_1.STL +0 -0
  69. hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_left_link_2.STL +0 -0
  70. hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_right_helper_link.STL +0 -0
  71. hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_right_link_1.STL +0 -0
  72. hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_right_link_2.STL +0 -0
  73. hex_zmq_servers/mujoco/e3_desktop/model/assets/table_link.STL +0 -0
  74. hex_zmq_servers/mujoco/e3_desktop/model/robot.xml +188 -0
  75. hex_zmq_servers/mujoco/e3_desktop/model/scene.xml +53 -0
  76. hex_zmq_servers/mujoco/e3_desktop/model/setting.xml +72 -0
  77. hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop.py +449 -0
  78. hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop_cli.py +289 -0
  79. hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop_srv.py +244 -0
  80. hex_zmq_servers/mujoco/mujoco_base.py +425 -0
  81. hex_zmq_servers/robot/__init__.py +37 -0
  82. hex_zmq_servers/robot/dummy/__init__.py +17 -0
  83. hex_zmq_servers/robot/dummy/robot_dummy.py +94 -0
  84. hex_zmq_servers/robot/dummy/robot_dummy_cli.py +29 -0
  85. hex_zmq_servers/robot/dummy/robot_dummy_srv.py +82 -0
  86. hex_zmq_servers/robot/gello/__init__.py +17 -0
  87. hex_zmq_servers/robot/gello/robot_gello.py +366 -0
  88. hex_zmq_servers/robot/gello/robot_gello_cli.py +29 -0
  89. hex_zmq_servers/robot/gello/robot_gello_srv.py +93 -0
  90. hex_zmq_servers/robot/hexarm/__init__.py +47 -0
  91. hex_zmq_servers/robot/hexarm/robot_hexarm.py +292 -0
  92. hex_zmq_servers/robot/hexarm/robot_hexarm_cli.py +37 -0
  93. hex_zmq_servers/robot/hexarm/robot_hexarm_srv.py +87 -0
  94. hex_zmq_servers/robot/hexarm/urdf/archer_l6y/empty.urdf +206 -0
  95. hex_zmq_servers/robot/hexarm/urdf/archer_l6y/gp100.urdf +206 -0
  96. hex_zmq_servers/robot/hexarm/urdf/archer_l6y/gp100_handle.urdf +206 -0
  97. hex_zmq_servers/robot/hexarm/urdf/archer_l6y/gp100_p050.urdf +206 -0
  98. hex_zmq_servers/robot/hexarm/urdf/archer_l6y/gp100_p050_handle.urdf +206 -0
  99. hex_zmq_servers/robot/hexarm/urdf/archer_y6/empty.urdf +207 -0
  100. hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100.urdf +207 -0
  101. hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100_handle.urdf +207 -0
  102. hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100_p050.urdf +207 -0
  103. hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100_p050_handle.urdf +207 -0
  104. hex_zmq_servers/robot/robot_base.py +276 -0
  105. hex_zmq_servers/zmq_base.py +547 -0
  106. hex_zmq_servers-0.3.9.dist-info/METADATA +147 -0
  107. hex_zmq_servers-0.3.9.dist-info/RECORD +110 -0
  108. hex_zmq_servers-0.3.9.dist-info/WHEEL +5 -0
  109. hex_zmq_servers-0.3.9.dist-info/licenses/LICENSE +201 -0
  110. hex_zmq_servers-0.3.9.dist-info/top_level.txt +1 -0
@@ -0,0 +1,189 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding:utf-8 -*-
3
+ ################################################################
4
+ # Copyright 2025 Dong Zhaorui. All rights reserved.
5
+ # Author: Dong Zhaorui 847235539@qq.com
6
+ # Date : 2025-09-16
7
+ ################################################################
8
+
9
+ import threading
10
+ import numpy as np
11
+ from collections import deque
12
+ from abc import abstractmethod
13
+
14
+ from ..device_base import HexDeviceBase
15
+ from ..zmq_base import HexZMQClientBase, HexZMQServerBase, HexRate
16
+
17
+ NET_CONFIG = {
18
+ "ip": "127.0.0.1",
19
+ "port": 12345,
20
+ "realtime_mode": False,
21
+ "deque_maxlen": 10,
22
+ "client_timeout_ms": 200,
23
+ "server_timeout_ms": 1_000,
24
+ "server_num_workers": 4,
25
+ }
26
+
27
+
28
+ class HexCamBase(HexDeviceBase):
29
+
30
+ def __init__(self, realtime_mode: bool = False):
31
+ HexDeviceBase.__init__(self, realtime_mode)
32
+
33
+ def __del__(self):
34
+ HexDeviceBase.__del__(self)
35
+
36
+ @abstractmethod
37
+ def work_loop(self, hex_queues: list[deque | threading.Event]):
38
+ raise NotImplementedError(
39
+ "`work_loop` should be implemented by the child class")
40
+
41
+ @abstractmethod
42
+ def close(self):
43
+ raise NotImplementedError(
44
+ "`close` should be implemented by the child class")
45
+
46
+
47
+ class HexCamClientBase(HexZMQClientBase):
48
+
49
+ def __init__(self, net_config: dict = NET_CONFIG):
50
+ HexZMQClientBase.__init__(self, net_config)
51
+ self._rgb_seq = 0
52
+ self._used_rgb_seq = 0
53
+ self._depth_seq = 0
54
+ self._used_depth_seq = 0
55
+ self._rgb_queue = deque(maxlen=self._deque_maxlen)
56
+ self._depth_queue = deque(maxlen=self._deque_maxlen)
57
+
58
+ def __del__(self):
59
+ HexZMQClientBase.__del__(self)
60
+
61
+ def get_rgb(self, newest: bool = False):
62
+ try:
63
+ if self._realtime_mode or newest:
64
+ hdr, img = self._rgb_queue[-1]
65
+ if self._used_rgb_seq != hdr["args"]:
66
+ self._used_rgb_seq = hdr["args"]
67
+ return hdr, img
68
+ else:
69
+ return None, None
70
+ else:
71
+ return self._rgb_queue.popleft()
72
+ except IndexError:
73
+ return None, None
74
+
75
+ def get_depth(self, newest: bool = False):
76
+ try:
77
+ if self._realtime_mode or newest:
78
+ hdr, img = self._depth_queue[-1]
79
+ if self._used_depth_seq != hdr["args"]:
80
+ self._used_depth_seq = hdr["args"]
81
+ return hdr, img
82
+ else:
83
+ return None, None
84
+ else:
85
+ return self._depth_queue.popleft()
86
+ except IndexError:
87
+ return None, None
88
+
89
+ def _get_rgb_inner(self):
90
+ return self._process_frame(False)
91
+
92
+ def _get_depth_inner(self):
93
+ return self._process_frame(True)
94
+
95
+ def _process_frame(self, depth_flag: bool):
96
+ req_cmd = f"get_{'depth' if depth_flag else 'rgb'}"
97
+ hdr, img = self.request({
98
+ "cmd":
99
+ req_cmd,
100
+ "args": (1 + (self._depth_seq if depth_flag else self._rgb_seq)) %
101
+ self._max_seq_num,
102
+ })
103
+
104
+ try:
105
+ cmd = hdr["cmd"]
106
+ if cmd == f"{req_cmd}_ok":
107
+ if depth_flag:
108
+ self._depth_seq = hdr["args"]
109
+ else:
110
+ self._rgb_seq = hdr["args"]
111
+ return hdr, img
112
+ else:
113
+ return None, None
114
+ except KeyError:
115
+ print(f"\033[91m{hdr['cmd']} requires `cmd`\033[0m")
116
+ return None, None
117
+ except Exception as e:
118
+ print(f"\033[91m__process_frame failed: {e}\033[0m")
119
+ return None, None
120
+
121
+ def _recv_loop(self):
122
+ rate = HexRate(200)
123
+ while self._recv_flag:
124
+ hdr, img = self._get_rgb_inner()
125
+ if hdr is not None:
126
+ self._rgb_queue.append((hdr, img))
127
+ hdr, img = self._get_depth_inner()
128
+ if hdr is not None:
129
+ self._depth_queue.append((hdr, img))
130
+ rate.sleep()
131
+
132
+
133
+ class HexCamServerBase(HexZMQServerBase):
134
+
135
+ def __init__(self, net_config: dict = NET_CONFIG):
136
+ HexZMQServerBase.__init__(self, net_config)
137
+ self._device: HexDeviceBase = None
138
+ self._rgb_queue = deque(maxlen=self._deque_maxlen)
139
+ self._depth_queue = deque(maxlen=self._deque_maxlen)
140
+
141
+ def __del__(self):
142
+ HexZMQServerBase.__del__(self)
143
+ self._device.close()
144
+
145
+ def work_loop(self):
146
+ try:
147
+ self._device.work_loop([
148
+ self._rgb_queue,
149
+ self._depth_queue,
150
+ self._stop_event,
151
+ ])
152
+ finally:
153
+ self._device.close()
154
+
155
+ def _get_frame(self, recv_hdr: dict, depth_flag: bool):
156
+ try:
157
+ seq = recv_hdr["args"]
158
+ except KeyError:
159
+ print(f"\033[91m{recv_hdr['cmd']} requires `args`\033[0m")
160
+ return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
161
+
162
+ try:
163
+ if depth_flag:
164
+ ts, count, img = self._depth_queue[
165
+ -1] if self._realtime_mode else self._depth_queue.popleft(
166
+ )
167
+ else:
168
+ ts, count, img = self._rgb_queue[
169
+ -1] if self._realtime_mode else self._rgb_queue.popleft()
170
+ except IndexError:
171
+ return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
172
+ except Exception as e:
173
+ print(f"\033[91m{recv_hdr['cmd']} failed: {e}\033[0m")
174
+ return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
175
+
176
+ delta = (count - seq) % self._max_seq_num
177
+ if delta >= 0 and delta < 1e6:
178
+ return {
179
+ "cmd": f"{recv_hdr['cmd']}_ok",
180
+ "ts": ts,
181
+ "args": count
182
+ }, img
183
+ else:
184
+ return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
185
+
186
+ @abstractmethod
187
+ def _process_request(self, recv_hdr: dict, recv_buf: np.ndarray):
188
+ raise NotImplementedError(
189
+ "`_process_request` should be implemented by the child class")
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding:utf-8 -*-
3
+ ################################################################
4
+ # Copyright 2025 Dong Zhaorui. All rights reserved.
5
+ # Author: Dong Zhaorui 847235539@qq.com
6
+ # Date : 2025-09-12
7
+ ################################################################
8
+
9
+ from .cam_dummy import HexCamDummy
10
+ from .cam_dummy_cli import HexCamDummyClient
11
+ from .cam_dummy_srv import HexCamDummyServer
12
+
13
+ __all__ = [
14
+ "HexCamDummy",
15
+ "HexCamDummyClient",
16
+ "HexCamDummyServer",
17
+ ]
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding:utf-8 -*-
3
+ ################################################################
4
+ # Copyright 2025 Dong Zhaorui. All rights reserved.
5
+ # Author: Dong Zhaorui 847235539@qq.com
6
+ # Date : 2025-09-12
7
+ ################################################################
8
+
9
+ import threading
10
+ import numpy as np
11
+ from collections import deque
12
+
13
+ from ..cam_base import HexCamBase
14
+ from ...zmq_base import (
15
+ hex_zmq_ts_now,
16
+ HexRate,
17
+ )
18
+ from ...hex_launch import hex_log, HEX_LOG_LEVEL
19
+
20
+
21
+ class HexCamDummy(HexCamBase):
22
+
23
+ def __init__(self, params_config: dict = {}, realtime_mode: bool = False):
24
+ HexCamBase.__init__(self, realtime_mode)
25
+ self._working.set()
26
+
27
+ def __del__(self):
28
+ HexCamBase.__del__(self)
29
+
30
+ def work_loop(self, hex_queues: list[deque | threading.Event]):
31
+ rgb_queue = hex_queues[0]
32
+ depth_queue = hex_queues[1]
33
+ stop_event = hex_queues[2]
34
+
35
+ rgb_count = 0
36
+ depth_count = 0
37
+ rate = HexRate(60)
38
+ while self._working.is_set() and not stop_event.is_set():
39
+ # rgb
40
+ rgb_img = np.random.randint(
41
+ 0,
42
+ 255,
43
+ (480, 640, 3),
44
+ dtype=np.uint8,
45
+ )
46
+ rgb_queue.append((hex_zmq_ts_now(), rgb_count, rgb_img))
47
+ rgb_count = (rgb_count + 1) % self._max_seq_num
48
+
49
+ # depth
50
+ depth_img = np.random.randint(
51
+ 0,
52
+ 65535,
53
+ (480, 640),
54
+ dtype=np.uint16,
55
+ )
56
+ depth_queue.append((hex_zmq_ts_now(), depth_count, depth_img))
57
+ depth_count = (depth_count + 1) % self._max_seq_num
58
+
59
+ # sleep
60
+ rate.sleep()
61
+
62
+ # close
63
+ self.close()
64
+
65
+ def close(self):
66
+ if not self._working.is_set():
67
+ return
68
+ self._working.clear()
69
+ hex_log(HEX_LOG_LEVEL["info"], "HexCamDummy closed")
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding:utf-8 -*-
3
+ ################################################################
4
+ # Copyright 2025 Dong Zhaorui. All rights reserved.
5
+ # Author: Dong Zhaorui 847235539@qq.com
6
+ # Date : 2025-09-12
7
+ ################################################################
8
+
9
+ from ..cam_base import HexCamClientBase
10
+
11
+ NET_CONFIG = {
12
+ "ip": "127.0.0.1",
13
+ "port": 12345,
14
+ "realtime_mode": False,
15
+ "deque_maxlen": 10,
16
+ "client_timeout_ms": 200,
17
+ "server_timeout_ms": 1_000,
18
+ "server_num_workers": 4,
19
+ }
20
+
21
+
22
+ class HexCamDummyClient(HexCamClientBase):
23
+
24
+ def __init__(
25
+ self,
26
+ net_config: dict = NET_CONFIG,
27
+ ):
28
+ HexCamClientBase.__init__(self, net_config)
29
+ self._wait_for_working()
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding:utf-8 -*-
3
+ ################################################################
4
+ # Copyright 2025 Dong Zhaorui. All rights reserved.
5
+ # Author: Dong Zhaorui 847235539@qq.com
6
+ # Date : 2025-09-12
7
+ ################################################################
8
+
9
+ import numpy as np
10
+
11
+ try:
12
+ from ..cam_base import HexCamServerBase
13
+ from .cam_dummy import HexCamDummy
14
+ except (ImportError, ValueError):
15
+ import sys
16
+ from pathlib import Path
17
+ this_file = Path(__file__).resolve()
18
+ project_root = this_file.parents[3]
19
+ if str(project_root) not in sys.path:
20
+ sys.path.insert(0, str(project_root))
21
+ from hex_zmq_servers.cam.cam_base import HexCamServerBase
22
+ from hex_zmq_servers.cam.dummy.cam_dummy import HexCamDummy
23
+
24
+ NET_CONFIG = {
25
+ "ip": "127.0.0.1",
26
+ "port": 12345,
27
+ "realtime_mode": False,
28
+ "deque_maxlen": 10,
29
+ "client_timeout_ms": 200,
30
+ "server_timeout_ms": 1_000,
31
+ "server_num_workers": 4,
32
+ }
33
+
34
+
35
+ class HexCamDummyServer(HexCamServerBase):
36
+
37
+ def __init__(
38
+ self,
39
+ net_config: dict = NET_CONFIG,
40
+ params_config: dict = {},
41
+ ):
42
+ HexCamServerBase.__init__(self, net_config)
43
+
44
+ # camera
45
+ self._device = HexCamDummy(params_config,
46
+ net_config.get("realtime_mode", False))
47
+
48
+ def _process_request(self, recv_hdr: dict, recv_buf: np.ndarray):
49
+ if recv_hdr["cmd"] == "is_working":
50
+ return self.no_ts_hdr(recv_hdr, self._device.is_working()), None
51
+ elif recv_hdr["cmd"] == "get_rgb":
52
+ return self._get_frame(recv_hdr, False)
53
+ elif recv_hdr["cmd"] == "get_depth":
54
+ return self._get_frame(recv_hdr, True)
55
+ else:
56
+ raise ValueError(f"unknown command: {recv_hdr['cmd']}")
57
+
58
+
59
+ if __name__ == "__main__":
60
+ import argparse, json
61
+ from hex_zmq_servers.zmq_base import hex_server_helper
62
+
63
+ parser = argparse.ArgumentParser()
64
+ parser.add_argument("--cfg", type=str, required=True)
65
+ args = parser.parse_args()
66
+ cfg = json.loads(args.cfg)
67
+
68
+ hex_server_helper(cfg, HexCamDummyServer)
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding:utf-8 -*-
3
+ ################################################################
4
+ # Copyright 2025 Dong Zhaorui. All rights reserved.
5
+ # Author: Dong Zhaorui 847235539@qq.com
6
+ # Date : 2025-09-12
7
+ ################################################################
8
+
9
+ from .cam_realsense import HexCamRealsense
10
+ from .cam_realsense_cli import HexCamRealsenseClient
11
+ from .cam_realsense_srv import HexCamRealsenseServer
12
+
13
+ __all__ = [
14
+ "HexCamRealsense",
15
+ "HexCamRealsenseClient",
16
+ "HexCamRealsenseServer",
17
+ ]
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding:utf-8 -*-
3
+ ################################################################
4
+ # Copyright 2025 Dong Zhaorui. All rights reserved.
5
+ # Author: Dong Zhaorui 847235539@qq.com
6
+ # Date : 2025-09-14
7
+ ################################################################
8
+
9
+ import threading
10
+ import numpy as np
11
+ from collections import deque
12
+
13
+ from ..cam_base import HexCamBase
14
+ from ...zmq_base import (
15
+ hex_ns_now,
16
+ hex_zmq_ts_now,
17
+ hex_zmq_ts_delta_ms,
18
+ )
19
+ from ...hex_launch import hex_log, HEX_LOG_LEVEL
20
+ import pyrealsense2 as rs
21
+
22
+ CAMERA_CONFIG = {
23
+ "serial_number": '243422073194',
24
+ "resolution": [640, 480],
25
+ "frame_rate": 30,
26
+ "sens_ts": True,
27
+ }
28
+
29
+
30
+ class HexCamRealsense(HexCamBase):
31
+
32
+ def __init__(
33
+ self,
34
+ camera_config: dict = CAMERA_CONFIG,
35
+ realtime_mode: bool = False,
36
+ ):
37
+ HexCamBase.__init__(self, realtime_mode)
38
+
39
+ try:
40
+ self.__serial_number = camera_config["serial_number"]
41
+ self.__resolution = camera_config["resolution"]
42
+ self.__frame_rate = camera_config["frame_rate"]
43
+ self.__sens_ts = camera_config["sens_ts"]
44
+ except KeyError as ke:
45
+ missing_key = ke.args[0]
46
+ raise ValueError(
47
+ f"camera_config is not valid, missing key: {missing_key}")
48
+
49
+ # variables
50
+ # realsense variables
51
+ ctx = rs.context()
52
+ serial_numbers = []
53
+ for dev in ctx.query_devices():
54
+ serial = dev.get_info(rs.camera_info.serial_number)
55
+ name = dev.get_info(rs.camera_info.name)
56
+ print(f" - Device: {name}, Serial: {serial}")
57
+ serial_numbers.append(serial)
58
+ if self.__serial_number not in serial_numbers:
59
+ print(
60
+ f"can not find device with serial number: {self.__serial_number}"
61
+ )
62
+ return
63
+
64
+ # camera variables
65
+ self.__intri = np.zeros(4)
66
+
67
+ # open device
68
+ self.__pipeline = rs.pipeline()
69
+ config = rs.config()
70
+ config.enable_device(self.__serial_number)
71
+ config.enable_stream(
72
+ rs.stream.color,
73
+ self.__resolution[0],
74
+ self.__resolution[1],
75
+ rs.format.bgr8,
76
+ self.__frame_rate,
77
+ )
78
+ config.enable_stream(
79
+ rs.stream.depth,
80
+ self.__resolution[0],
81
+ self.__resolution[1],
82
+ rs.format.z16,
83
+ self.__frame_rate,
84
+ )
85
+ profile = self.__pipeline.start(config)
86
+ color_profile = profile.get_stream(rs.stream.color)
87
+ color_intrinsics = color_profile.as_video_stream_profile(
88
+ ).get_intrinsics()
89
+ self.__intri[0] = color_intrinsics.fx
90
+ self.__intri[1] = color_intrinsics.fy
91
+ self.__intri[2] = color_intrinsics.ppx
92
+ self.__intri[3] = color_intrinsics.ppy
93
+ self.__align = rs.align(rs.stream.color)
94
+ self.__bias_ns = None
95
+
96
+ # start work loop
97
+ self._working.set()
98
+
99
+ def get_intri(self) -> np.ndarray:
100
+ self._wait_for_working()
101
+ return self.__intri
102
+
103
+ def get_serial_number(self) -> np.ndarray:
104
+ self._wait_for_working()
105
+ return self.__serial_number
106
+
107
+ def work_loop(self, hex_queues: list[deque | threading.Event]):
108
+ rgb_queue = hex_queues[0]
109
+ depth_queue = hex_queues[1]
110
+ stop_event = hex_queues[2]
111
+
112
+ frames = self.__pipeline.wait_for_frames()
113
+ bias_ns = np.int64(hex_ns_now()) - np.int64(
114
+ frames.get_frame_metadata(rs.frame_metadata_value.sensor_timestamp)
115
+ * 1_000)
116
+
117
+ rgb_count = 0
118
+ depth_count = 0
119
+ while self._working.is_set() and not stop_event.is_set():
120
+ # read frame
121
+ aligned_frames = self.__align.process(
122
+ self.__pipeline.wait_for_frames())
123
+ cur_ns = hex_zmq_ts_now()
124
+ sen_ts_ns = bias_ns + np.int64(
125
+ aligned_frames.get_frame_metadata(
126
+ rs.frame_metadata_value.sensor_timestamp) * 1_000)
127
+ sen_ts = {
128
+ "s": sen_ts_ns // 1_000_000_000,
129
+ "ns": sen_ts_ns % 1_000_000_000,
130
+ }
131
+ if hex_zmq_ts_delta_ms(cur_ns, sen_ts) < 0:
132
+ sen_ts = cur_ns
133
+
134
+ # collect rgb frame
135
+ color_frame = aligned_frames.get_color_frame()
136
+ if color_frame:
137
+
138
+ rgb_queue.append(
139
+ (sen_ts if self.__sens_ts else cur_ns, rgb_count,
140
+ np.asanyarray(color_frame.get_data())))
141
+ rgb_count = (rgb_count + 1) % self._max_seq_num
142
+
143
+ # collect depth frame
144
+ depth_frame = aligned_frames.get_depth_frame()
145
+ if depth_frame:
146
+ depth_queue.append(
147
+ (sen_ts if self.__sens_ts else cur_ns, depth_count,
148
+ np.asanyarray(depth_frame.get_data())))
149
+ depth_count = (depth_count + 1) % self._max_seq_num
150
+
151
+ # close
152
+ self.close()
153
+
154
+ def close(self):
155
+ if not self._working.is_set():
156
+ return
157
+ self._working.clear()
158
+ self.__pipeline.stop()
159
+ hex_log(HEX_LOG_LEVEL["info"], "HexCamRealsense closed")
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding:utf-8 -*-
3
+ ################################################################
4
+ # Copyright 2025 Dong Zhaorui. All rights reserved.
5
+ # Author: Dong Zhaorui 847235539@qq.com
6
+ # Date : 2025-09-12
7
+ ################################################################
8
+
9
+ from ..cam_base import HexCamClientBase
10
+
11
+ NET_CONFIG = {
12
+ "ip": "127.0.0.1",
13
+ "port": 12345,
14
+ "realtime_mode": False,
15
+ "deque_maxlen": 10,
16
+ "client_timeout_ms": 200,
17
+ "server_timeout_ms": 1_000,
18
+ "server_num_workers": 4,
19
+ }
20
+
21
+
22
+ class HexCamRealsenseClient(HexCamClientBase):
23
+
24
+ def __init__(
25
+ self,
26
+ net_config: dict = NET_CONFIG,
27
+ ):
28
+ HexCamClientBase.__init__(self, net_config)
29
+ self._wait_for_working()
30
+
31
+ def get_intri(self):
32
+ intri_hdr, intri = self.request({"cmd": "get_intri"})
33
+ return intri_hdr, intri
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding:utf-8 -*-
3
+ ################################################################
4
+ # Copyright 2025 Dong Zhaorui. All rights reserved.
5
+ # Author: Dong Zhaorui 847235539@qq.com
6
+ # Date : 2025-09-12
7
+ ################################################################
8
+
9
+ import numpy as np
10
+
11
+ try:
12
+ from ..cam_base import HexCamServerBase
13
+ from .cam_realsense import HexCamRealsense
14
+ except (ImportError, ValueError):
15
+ import sys
16
+ from pathlib import Path
17
+ this_file = Path(__file__).resolve()
18
+ project_root = this_file.parents[3]
19
+ if str(project_root) not in sys.path:
20
+ sys.path.insert(0, str(project_root))
21
+ from hex_zmq_servers.cam.cam_base import HexCamServerBase
22
+ from hex_zmq_servers.cam.realsense.cam_realsense import HexCamRealsense
23
+
24
+ NET_CONFIG = {
25
+ "ip": "127.0.0.1",
26
+ "port": 12345,
27
+ "realtime_mode": False,
28
+ "deque_maxlen": 10,
29
+ "client_timeout_ms": 200,
30
+ "server_timeout_ms": 1_000,
31
+ "server_num_workers": 4,
32
+ }
33
+
34
+ CAMERA_CONFIG = {
35
+ "serial_number": '243422073194',
36
+ "resolution": [640, 480],
37
+ "frame_rate": 30,
38
+ "sens_ts": True,
39
+ }
40
+
41
+
42
+ class HexCamRealsenseServer(HexCamServerBase):
43
+
44
+ def __init__(
45
+ self,
46
+ net_config: dict = NET_CONFIG,
47
+ params_config: dict = CAMERA_CONFIG,
48
+ ):
49
+ HexCamServerBase.__init__(self, net_config)
50
+
51
+ # camera
52
+ self._device = HexCamRealsense(params_config,
53
+ net_config.get("realtime_mode", False))
54
+
55
+ def _process_request(self, recv_hdr: dict, recv_buf: np.ndarray):
56
+ if recv_hdr["cmd"] == "is_working":
57
+ return self.no_ts_hdr(recv_hdr, self._device.is_working()), None
58
+ elif recv_hdr["cmd"] == "get_intri":
59
+ intri = self._device.get_intri()
60
+ return self.no_ts_hdr(recv_hdr, intri is not None), intri
61
+ elif recv_hdr["cmd"] == "get_rgb":
62
+ return self._get_frame(recv_hdr, False)
63
+ elif recv_hdr["cmd"] == "get_depth":
64
+ return self._get_frame(recv_hdr, True)
65
+ else:
66
+ raise ValueError(f"unknown command: {recv_hdr['cmd']}")
67
+
68
+
69
+ if __name__ == "__main__":
70
+ import argparse, json
71
+ from hex_zmq_servers.zmq_base import hex_server_helper
72
+
73
+ parser = argparse.ArgumentParser()
74
+ parser.add_argument("--cfg", type=str, required=True)
75
+ args = parser.parse_args()
76
+ cfg = json.loads(args.cfg)
77
+
78
+ hex_server_helper(cfg, HexCamRealsenseServer)
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding:utf-8 -*-
3
+ ################################################################
4
+ # Copyright 2025 Dong Zhaorui. All rights reserved.
5
+ # Author: Dong Zhaorui 847235539@qq.com
6
+ # Date : 2025-09-12
7
+ ################################################################
8
+
9
+ from .cam_rgb import HexCamRGB
10
+ from .cam_rgb_cli import HexCamRGBClient
11
+ from .cam_rgb_srv import HexCamRGBServer
12
+
13
+ __all__ = [
14
+ "HexCamRGB",
15
+ "HexCamRGBClient",
16
+ "HexCamRGBServer",
17
+ ]