hex-zmq-servers 0.3.2__py3-none-any.whl → 0.3.4__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.
- hex_zmq_servers/__init__.py +45 -20
- hex_zmq_servers/cam/__init__.py +29 -5
- hex_zmq_servers/cam/berxel/cam_berxel.py +8 -10
- hex_zmq_servers/cam/berxel/cam_berxel_cli.py +1 -0
- hex_zmq_servers/cam/cam_base.py +40 -10
- hex_zmq_servers/cam/dummy/cam_dummy.py +7 -7
- hex_zmq_servers/cam/dummy/cam_dummy_cli.py +1 -0
- hex_zmq_servers/cam/realsense/__init__.py +17 -0
- hex_zmq_servers/cam/realsense/cam_realsense.py +157 -0
- hex_zmq_servers/cam/realsense/cam_realsense_cli.py +31 -0
- hex_zmq_servers/cam/realsense/cam_realsense_srv.py +75 -0
- hex_zmq_servers/cam/rgb/__init__.py +17 -0
- hex_zmq_servers/cam/rgb/cam_rgb.py +133 -0
- hex_zmq_servers/cam/rgb/cam_rgb_cli.py +41 -0
- hex_zmq_servers/cam/rgb/cam_rgb_srv.py +75 -0
- hex_zmq_servers/config/cam_realsense.json +15 -0
- hex_zmq_servers/config/cam_rgb.json +26 -0
- hex_zmq_servers/config/mujoco_archer_y6.json +2 -1
- hex_zmq_servers/config/mujoco_e3_desktop.json +6 -1
- hex_zmq_servers/config/robot_hexarm.json +1 -1
- hex_zmq_servers/device_base.py +3 -2
- hex_zmq_servers/mujoco/archer_y6/model/robot.xml +6 -6
- hex_zmq_servers/mujoco/archer_y6/model/scene.xml +1 -1
- hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6.py +74 -39
- hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6_cli.py +42 -0
- hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6_srv.py +16 -14
- hex_zmq_servers/mujoco/e3_desktop/model/robot.xml +12 -12
- hex_zmq_servers/mujoco/e3_desktop/model/scene.xml +1 -1
- hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop.py +138 -70
- hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop_cli.py +148 -33
- hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop_srv.py +39 -35
- hex_zmq_servers/mujoco/mujoco_base.py +101 -64
- hex_zmq_servers/robot/dummy/robot_dummy.py +11 -7
- hex_zmq_servers/robot/dummy/robot_dummy_cli.py +1 -0
- hex_zmq_servers/robot/gello/robot_gello.py +11 -7
- hex_zmq_servers/robot/gello/robot_gello_cli.py +1 -0
- hex_zmq_servers/robot/hexarm/robot_hexarm.py +56 -22
- hex_zmq_servers/robot/hexarm/robot_hexarm_cli.py +1 -0
- hex_zmq_servers/robot/robot_base.py +40 -10
- hex_zmq_servers/zmq_base.py +97 -33
- {hex_zmq_servers-0.3.2.dist-info → hex_zmq_servers-0.3.4.dist-info}/METADATA +7 -6
- {hex_zmq_servers-0.3.2.dist-info → hex_zmq_servers-0.3.4.dist-info}/RECORD +45 -35
- {hex_zmq_servers-0.3.2.dist-info → hex_zmq_servers-0.3.4.dist-info}/WHEEL +0 -0
- {hex_zmq_servers-0.3.2.dist-info → hex_zmq_servers-0.3.4.dist-info}/licenses/LICENSE +0 -0
- {hex_zmq_servers-0.3.2.dist-info → hex_zmq_servers-0.3.4.dist-info}/top_level.txt +0 -0
hex_zmq_servers/__init__.py
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
from .hex_launch import HexLaunch, HexNodeConfig, HEX_LOG_LEVEL, hex_dict_str, hex_log, hex_err
|
|
10
10
|
|
|
11
11
|
from .device_base import HexDeviceBase
|
|
12
|
-
from .zmq_base import
|
|
13
|
-
from .zmq_base import
|
|
12
|
+
from .zmq_base import hex_zmq_ts_to_ns, ns_to_hex_zmq_ts, hex_ns_now, hex_zmq_ts_now, hex_zmq_ts_delta_ms
|
|
13
|
+
from .zmq_base import HexRate, HexZMQClientBase, HexZMQServerBase, hex_server_helper
|
|
14
14
|
from .zmq_base import HexZMQDummyClient, HexZMQDummyServer
|
|
15
15
|
|
|
16
16
|
from .robot import HexRobotBase, HexRobotClientBase, HexRobotServerBase
|
|
@@ -18,6 +18,10 @@ from .robot import HexRobotDummy, HexRobotDummyClient, HexRobotDummyServer
|
|
|
18
18
|
from .robot import HexRobotGello, HexRobotGelloClient, HexRobotGelloServer
|
|
19
19
|
from .robot import HexRobotHexarm, HexRobotHexarmClient, HexRobotHexarmServer, HEXARM_URDF_PATH_DICT
|
|
20
20
|
|
|
21
|
+
from .cam import HexCamBase, HexCamClientBase, HexCamServerBase
|
|
22
|
+
from .cam import HexCamDummy, HexCamDummyClient, HexCamDummyServer
|
|
23
|
+
from .cam import HexCamRGB, HexCamRGBClient, HexCamRGBServer
|
|
24
|
+
|
|
21
25
|
import os
|
|
22
26
|
|
|
23
27
|
file_dir = os.path.dirname(os.path.abspath(__file__))
|
|
@@ -26,12 +30,16 @@ HEX_ZMQ_SERVERS_PATH_DICT = {
|
|
|
26
30
|
"robot_dummy": f"{file_dir}/robot/dummy/robot_dummy_srv.py",
|
|
27
31
|
"robot_gello": f"{file_dir}/robot/gello/robot_gello_srv.py",
|
|
28
32
|
"robot_hexarm": f"{file_dir}/robot/hexarm/robot_hexarm_srv.py",
|
|
33
|
+
"cam_dummy": f"{file_dir}/cam/dummy/cam_dummy_srv.py",
|
|
34
|
+
"cam_rgb": f"{file_dir}/cam/rgb/cam_rgb_srv.py",
|
|
29
35
|
}
|
|
30
36
|
HEX_ZMQ_CONFIGS_PATH_DICT = {
|
|
31
37
|
"zmq_dummy": f"{file_dir}/config/zmq_dummy.json",
|
|
32
38
|
"robot_dummy": f"{file_dir}/config/robot_dummy.json",
|
|
33
39
|
"robot_gello": f"{file_dir}/config/robot_gello.json",
|
|
34
40
|
"robot_hexarm": f"{file_dir}/config/robot_hexarm.json",
|
|
41
|
+
"cam_dummy": f"{file_dir}/config/cam_dummy.json",
|
|
42
|
+
"cam_rgb": f"{file_dir}/config/cam_rgb.json",
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
__all__ = [
|
|
@@ -54,9 +62,11 @@ __all__ = [
|
|
|
54
62
|
# base
|
|
55
63
|
"HexDeviceBase",
|
|
56
64
|
"HexRate",
|
|
65
|
+
"hex_zmq_ts_to_ns",
|
|
66
|
+
"ns_to_hex_zmq_ts",
|
|
67
|
+
"hex_ns_now",
|
|
57
68
|
"hex_zmq_ts_now",
|
|
58
69
|
"hex_zmq_ts_delta_ms",
|
|
59
|
-
"HexSafeValue",
|
|
60
70
|
"HexZMQClientBase",
|
|
61
71
|
"HexZMQServerBase",
|
|
62
72
|
"hex_server_helper",
|
|
@@ -76,47 +86,62 @@ __all__ = [
|
|
|
76
86
|
"HexRobotHexarm",
|
|
77
87
|
"HexRobotHexarmClient",
|
|
78
88
|
"HexRobotHexarmServer",
|
|
89
|
+
|
|
90
|
+
# camera
|
|
91
|
+
"HexCamBase",
|
|
92
|
+
"HexCamClientBase",
|
|
93
|
+
"HexCamServerBase",
|
|
94
|
+
"HexCamDummy",
|
|
95
|
+
"HexCamDummyClient",
|
|
96
|
+
"HexCamDummyServer",
|
|
97
|
+
"HexCamRGB",
|
|
98
|
+
"HexCamRGBClient",
|
|
99
|
+
"HexCamRGBServer",
|
|
79
100
|
]
|
|
80
101
|
|
|
81
102
|
# Check optional dependencies availability
|
|
82
103
|
from importlib.util import find_spec
|
|
83
104
|
|
|
84
|
-
_HAS_OPENCV = find_spec("cv2") is not None
|
|
85
105
|
_HAS_BERXEL = find_spec("berxel_py_wrapper") is not None
|
|
106
|
+
_HAS_REALSENSE = find_spec("pyrealsense2") is not None
|
|
86
107
|
_HAS_MUJOCO = find_spec("mujoco") is not None
|
|
87
108
|
|
|
88
|
-
# Optional:
|
|
89
|
-
if
|
|
90
|
-
from .cam import HexCamBase, HexCamClientBase, HexCamServerBase
|
|
91
|
-
from .cam import HexCamDummy, HexCamDummyClient, HexCamDummyServer
|
|
109
|
+
# Optional: berxel
|
|
110
|
+
if _HAS_BERXEL:
|
|
92
111
|
from .cam import HexCamBerxel, HexCamBerxelClient, HexCamBerxelServer
|
|
93
112
|
HEX_ZMQ_SERVERS_PATH_DICT.update({
|
|
94
|
-
"cam_dummy":
|
|
95
|
-
f"{file_dir}/cam/dummy/cam_dummy_srv.py",
|
|
96
113
|
"cam_berxel":
|
|
97
114
|
f"{file_dir}/cam/berxel/cam_berxel_srv.py",
|
|
98
115
|
})
|
|
99
116
|
HEX_ZMQ_CONFIGS_PATH_DICT.update({
|
|
100
|
-
"cam_dummy":
|
|
101
|
-
f"{file_dir}/config/cam_dummy.json",
|
|
102
117
|
"cam_berxel":
|
|
103
118
|
f"{file_dir}/config/cam_berxel.json",
|
|
104
119
|
})
|
|
105
120
|
__all__.extend([
|
|
106
|
-
# camera
|
|
107
|
-
"HexCamBase",
|
|
108
|
-
"HexCamClientBase",
|
|
109
|
-
"HexCamServerBase",
|
|
110
|
-
"HexCamDummy",
|
|
111
|
-
"HexCamDummyClient",
|
|
112
|
-
"HexCamDummyServer",
|
|
113
121
|
"HexCamBerxel",
|
|
114
122
|
"HexCamBerxelClient",
|
|
115
123
|
"HexCamBerxelServer",
|
|
116
124
|
])
|
|
117
125
|
|
|
126
|
+
# Optional: realsense
|
|
127
|
+
if _HAS_REALSENSE:
|
|
128
|
+
from .cam import HexCamRealsense, HexCamRealsenseClient, HexCamRealsenseServer
|
|
129
|
+
HEX_ZMQ_SERVERS_PATH_DICT.update({
|
|
130
|
+
"cam_realsense":
|
|
131
|
+
f"{file_dir}/cam/realsense/cam_realsense_srv.py",
|
|
132
|
+
})
|
|
133
|
+
HEX_ZMQ_CONFIGS_PATH_DICT.update({
|
|
134
|
+
"cam_realsense":
|
|
135
|
+
f"{file_dir}/config/cam_realsense.json",
|
|
136
|
+
})
|
|
137
|
+
__all__.extend([
|
|
138
|
+
"HexCamRealsense",
|
|
139
|
+
"HexCamRealsenseClient",
|
|
140
|
+
"HexCamRealsenseServer",
|
|
141
|
+
])
|
|
142
|
+
|
|
118
143
|
# Optional: mujoco
|
|
119
|
-
if
|
|
144
|
+
if _HAS_MUJOCO:
|
|
120
145
|
from .mujoco import HexMujocoBase, HexMujocoClientBase, HexMujocoServerBase
|
|
121
146
|
from .mujoco import HexMujocoArcherY6, HexMujocoArcherY6Client, HexMujocoArcherY6Server
|
|
122
147
|
from .mujoco import HexMujocoE3Desktop, HexMujocoE3DesktopClient, HexMujocoE3DesktopServer
|
hex_zmq_servers/cam/__init__.py
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
from .cam_base import HexCamBase, HexCamClientBase, HexCamServerBase
|
|
10
10
|
from .dummy import HexCamDummy, HexCamDummyClient, HexCamDummyServer
|
|
11
|
-
from .
|
|
11
|
+
from .rgb import HexCamRGB, HexCamRGBClient, HexCamRGBServer
|
|
12
12
|
|
|
13
13
|
__all__ = [
|
|
14
14
|
# base
|
|
@@ -21,8 +21,32 @@ __all__ = [
|
|
|
21
21
|
"HexCamDummyClient",
|
|
22
22
|
"HexCamDummyServer",
|
|
23
23
|
|
|
24
|
-
#
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
24
|
+
# rgb
|
|
25
|
+
"HexCamRGB",
|
|
26
|
+
"HexCamRGBClient",
|
|
27
|
+
"HexCamRGBServer",
|
|
28
28
|
]
|
|
29
|
+
|
|
30
|
+
# Check optional dependencies availability
|
|
31
|
+
from importlib.util import find_spec
|
|
32
|
+
|
|
33
|
+
_HAS_BERXEL = find_spec("berxel_py_wrapper") is not None
|
|
34
|
+
_HAS_REALSENSE = find_spec("pyrealsense2") is not None
|
|
35
|
+
|
|
36
|
+
# Optional: berxel
|
|
37
|
+
if _HAS_BERXEL:
|
|
38
|
+
from .berxel import HexCamBerxel, HexCamBerxelClient, HexCamBerxelServer
|
|
39
|
+
__all__.extend([
|
|
40
|
+
"HexCamBerxel",
|
|
41
|
+
"HexCamBerxelClient",
|
|
42
|
+
"HexCamBerxelServer",
|
|
43
|
+
])
|
|
44
|
+
|
|
45
|
+
# Optional: realsense
|
|
46
|
+
if _HAS_REALSENSE:
|
|
47
|
+
from .realsense import HexCamRealsense, HexCamRealsenseClient, HexCamRealsenseServer
|
|
48
|
+
__all__.extend([
|
|
49
|
+
"HexCamRealsense",
|
|
50
|
+
"HexCamRealsenseClient",
|
|
51
|
+
"HexCamRealsenseServer",
|
|
52
|
+
])
|
|
@@ -9,12 +9,10 @@
|
|
|
9
9
|
import cv2
|
|
10
10
|
import threading
|
|
11
11
|
import numpy as np
|
|
12
|
+
from collections import deque
|
|
12
13
|
|
|
13
14
|
from ..cam_base import HexCamBase
|
|
14
|
-
from ...zmq_base import
|
|
15
|
-
hex_zmq_ts_now,
|
|
16
|
-
HexSafeValue,
|
|
17
|
-
)
|
|
15
|
+
from ...zmq_base import hex_zmq_ts_now
|
|
18
16
|
from ...hex_launch import hex_log, HEX_LOG_LEVEL
|
|
19
17
|
from berxel_py_wrapper import *
|
|
20
18
|
|
|
@@ -74,10 +72,10 @@ class HexCamBerxel(HexCamBase):
|
|
|
74
72
|
self._wait_for_working()
|
|
75
73
|
return self.__serial_number
|
|
76
74
|
|
|
77
|
-
def work_loop(self,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
stop_event =
|
|
75
|
+
def work_loop(self, hex_queues: list[deque | threading.Event]):
|
|
76
|
+
rgb_queue = hex_queues[0]
|
|
77
|
+
depth_queue = hex_queues[1]
|
|
78
|
+
stop_event = hex_queues[2]
|
|
81
79
|
|
|
82
80
|
rgb_count = 0
|
|
83
81
|
depth_count = 0
|
|
@@ -89,13 +87,13 @@ class HexCamBerxel(HexCamBase):
|
|
|
89
87
|
# collect rgb frame
|
|
90
88
|
if hawk_rgb_frame is not None:
|
|
91
89
|
ts, frame = self.__unpack_frame(hawk_rgb_frame, False)
|
|
92
|
-
|
|
90
|
+
rgb_queue.append((ts, rgb_count, frame))
|
|
93
91
|
rgb_count = (rgb_count + 1) % self._max_seq_num
|
|
94
92
|
|
|
95
93
|
# collect depth frame
|
|
96
94
|
if hawk_depth_frame is not None:
|
|
97
95
|
ts, frame = self.__unpack_frame(hawk_depth_frame, True)
|
|
98
|
-
|
|
96
|
+
depth_queue.append((ts, depth_count, frame))
|
|
99
97
|
depth_count = (depth_count + 1) % self._max_seq_num
|
|
100
98
|
|
|
101
99
|
self.__device.releaseFrame(hawk_rgb_frame)
|
hex_zmq_servers/cam/cam_base.py
CHANGED
|
@@ -8,10 +8,11 @@
|
|
|
8
8
|
|
|
9
9
|
import threading
|
|
10
10
|
import numpy as np
|
|
11
|
+
from collections import deque
|
|
11
12
|
from abc import abstractmethod
|
|
12
13
|
|
|
13
14
|
from ..device_base import HexDeviceBase
|
|
14
|
-
from ..zmq_base import
|
|
15
|
+
from ..zmq_base import HexZMQClientBase, HexZMQServerBase, HexRate
|
|
15
16
|
|
|
16
17
|
NET_CONFIG = {
|
|
17
18
|
"ip": "127.0.0.1",
|
|
@@ -31,7 +32,7 @@ class HexCamBase(HexDeviceBase):
|
|
|
31
32
|
HexDeviceBase.__del__(self)
|
|
32
33
|
|
|
33
34
|
@abstractmethod
|
|
34
|
-
def work_loop(self,
|
|
35
|
+
def work_loop(self, hex_queues: list[deque | threading.Event]):
|
|
35
36
|
raise NotImplementedError(
|
|
36
37
|
"`work_loop` should be implemented by the child class")
|
|
37
38
|
|
|
@@ -47,14 +48,30 @@ class HexCamClientBase(HexZMQClientBase):
|
|
|
47
48
|
HexZMQClientBase.__init__(self, net_config)
|
|
48
49
|
self._rgb_seq = 0
|
|
49
50
|
self._depth_seq = 0
|
|
51
|
+
self._rgb_queue = deque(maxlen=10)
|
|
52
|
+
self._depth_queue = deque(maxlen=10)
|
|
50
53
|
|
|
51
54
|
def __del__(self):
|
|
52
55
|
HexZMQClientBase.__del__(self)
|
|
53
56
|
|
|
54
|
-
def get_rgb(self):
|
|
57
|
+
def get_rgb(self, newest: bool = False):
|
|
58
|
+
try:
|
|
59
|
+
return self._rgb_queue.popleft(
|
|
60
|
+
) if not newest else self._rgb_queue[-1]
|
|
61
|
+
except IndexError:
|
|
62
|
+
return None, None
|
|
63
|
+
|
|
64
|
+
def get_depth(self, newest: bool = False):
|
|
65
|
+
try:
|
|
66
|
+
return self._depth_queue.popleft(
|
|
67
|
+
) if not newest else self._depth_queue[-1]
|
|
68
|
+
except IndexError:
|
|
69
|
+
return None, None
|
|
70
|
+
|
|
71
|
+
def _get_rgb_inner(self):
|
|
55
72
|
return self._process_frame(False)
|
|
56
73
|
|
|
57
|
-
def
|
|
74
|
+
def _get_depth_inner(self):
|
|
58
75
|
return self._process_frame(True)
|
|
59
76
|
|
|
60
77
|
def _process_frame(self, depth_flag: bool):
|
|
@@ -83,14 +100,25 @@ class HexCamClientBase(HexZMQClientBase):
|
|
|
83
100
|
print(f"\033[91m__process_frame failed: {e}\033[0m")
|
|
84
101
|
return None, None
|
|
85
102
|
|
|
103
|
+
def _recv_loop(self):
|
|
104
|
+
rate = HexRate(200)
|
|
105
|
+
while self._recv_flag:
|
|
106
|
+
hdr, img = self._get_rgb_inner()
|
|
107
|
+
if hdr is not None:
|
|
108
|
+
self._rgb_queue.append((hdr, img))
|
|
109
|
+
hdr, img = self._get_depth_inner()
|
|
110
|
+
if hdr is not None:
|
|
111
|
+
self._depth_queue.append((hdr, img))
|
|
112
|
+
rate.sleep()
|
|
113
|
+
|
|
86
114
|
|
|
87
115
|
class HexCamServerBase(HexZMQServerBase):
|
|
88
116
|
|
|
89
117
|
def __init__(self, net_config: dict = NET_CONFIG):
|
|
90
118
|
HexZMQServerBase.__init__(self, net_config)
|
|
91
119
|
self._device: HexDeviceBase = None
|
|
92
|
-
self.
|
|
93
|
-
self.
|
|
120
|
+
self._rgb_queue = deque(maxlen=10)
|
|
121
|
+
self._depth_queue = deque(maxlen=10)
|
|
94
122
|
|
|
95
123
|
def __del__(self):
|
|
96
124
|
HexZMQServerBase.__del__(self)
|
|
@@ -99,8 +127,8 @@ class HexCamServerBase(HexZMQServerBase):
|
|
|
99
127
|
def work_loop(self):
|
|
100
128
|
try:
|
|
101
129
|
self._device.work_loop([
|
|
102
|
-
self.
|
|
103
|
-
self.
|
|
130
|
+
self._rgb_queue,
|
|
131
|
+
self._depth_queue,
|
|
104
132
|
self._stop_event,
|
|
105
133
|
])
|
|
106
134
|
finally:
|
|
@@ -115,9 +143,11 @@ class HexCamServerBase(HexZMQServerBase):
|
|
|
115
143
|
|
|
116
144
|
try:
|
|
117
145
|
if depth_flag:
|
|
118
|
-
ts, count, img = self.
|
|
146
|
+
ts, count, img = self._depth_queue.popleft()
|
|
119
147
|
else:
|
|
120
|
-
ts, count, img = self.
|
|
148
|
+
ts, count, img = self._rgb_queue.popleft()
|
|
149
|
+
except IndexError:
|
|
150
|
+
return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
|
|
121
151
|
except Exception as e:
|
|
122
152
|
print(f"\033[91m{recv_hdr['cmd']} failed: {e}\033[0m")
|
|
123
153
|
return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
|
|
9
9
|
import threading
|
|
10
10
|
import numpy as np
|
|
11
|
+
from collections import deque
|
|
11
12
|
|
|
12
13
|
from ..cam_base import HexCamBase
|
|
13
14
|
from ...zmq_base import (
|
|
14
15
|
hex_zmq_ts_now,
|
|
15
16
|
HexRate,
|
|
16
|
-
HexSafeValue,
|
|
17
17
|
)
|
|
18
18
|
from ...hex_launch import hex_log, HEX_LOG_LEVEL
|
|
19
19
|
|
|
@@ -27,10 +27,10 @@ class HexCamDummy(HexCamBase):
|
|
|
27
27
|
def __del__(self):
|
|
28
28
|
HexCamBase.__del__(self)
|
|
29
29
|
|
|
30
|
-
def work_loop(self,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
stop_event =
|
|
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
34
|
|
|
35
35
|
rgb_count = 0
|
|
36
36
|
depth_count = 0
|
|
@@ -43,7 +43,7 @@ class HexCamDummy(HexCamBase):
|
|
|
43
43
|
(480, 640, 3),
|
|
44
44
|
dtype=np.uint8,
|
|
45
45
|
)
|
|
46
|
-
|
|
46
|
+
rgb_queue.append((hex_zmq_ts_now(), rgb_count, rgb_img))
|
|
47
47
|
rgb_count = (rgb_count + 1) % self._max_seq_num
|
|
48
48
|
|
|
49
49
|
# depth
|
|
@@ -53,7 +53,7 @@ class HexCamDummy(HexCamBase):
|
|
|
53
53
|
(480, 640),
|
|
54
54
|
dtype=np.uint16,
|
|
55
55
|
)
|
|
56
|
-
|
|
56
|
+
depth_queue.append((hex_zmq_ts_now(), depth_count, depth_img))
|
|
57
57
|
depth_count = (depth_count + 1) % self._max_seq_num
|
|
58
58
|
|
|
59
59
|
# sleep
|
|
@@ -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,157 @@
|
|
|
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
|
+
):
|
|
36
|
+
HexCamBase.__init__(self)
|
|
37
|
+
|
|
38
|
+
try:
|
|
39
|
+
self.__serial_number = camera_config["serial_number"]
|
|
40
|
+
self.__resolution = camera_config["resolution"]
|
|
41
|
+
self.__frame_rate = camera_config["frame_rate"]
|
|
42
|
+
self.__sens_ts = camera_config["sens_ts"]
|
|
43
|
+
except KeyError as ke:
|
|
44
|
+
missing_key = ke.args[0]
|
|
45
|
+
raise ValueError(
|
|
46
|
+
f"camera_config is not valid, missing key: {missing_key}")
|
|
47
|
+
|
|
48
|
+
# variables
|
|
49
|
+
# realsense variables
|
|
50
|
+
ctx = rs.context()
|
|
51
|
+
serial_numbers = []
|
|
52
|
+
for dev in ctx.query_devices():
|
|
53
|
+
serial = dev.get_info(rs.camera_info.serial_number)
|
|
54
|
+
name = dev.get_info(rs.camera_info.name)
|
|
55
|
+
print(f" - Device: {name}, Serial: {serial}")
|
|
56
|
+
serial_numbers.append(serial)
|
|
57
|
+
if self.__serial_number not in serial_numbers:
|
|
58
|
+
print(
|
|
59
|
+
f"can not find device with serial number: {self.__serial_number}"
|
|
60
|
+
)
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
# camera variables
|
|
64
|
+
self.__intri = np.zeros(4)
|
|
65
|
+
|
|
66
|
+
# open device
|
|
67
|
+
self.__pipeline = rs.pipeline()
|
|
68
|
+
config = rs.config()
|
|
69
|
+
config.enable_device(self.__serial_number)
|
|
70
|
+
config.enable_stream(
|
|
71
|
+
rs.stream.color,
|
|
72
|
+
self.__resolution[0],
|
|
73
|
+
self.__resolution[1],
|
|
74
|
+
rs.format.bgr8,
|
|
75
|
+
self.__frame_rate,
|
|
76
|
+
)
|
|
77
|
+
config.enable_stream(
|
|
78
|
+
rs.stream.depth,
|
|
79
|
+
self.__resolution[0],
|
|
80
|
+
self.__resolution[1],
|
|
81
|
+
rs.format.z16,
|
|
82
|
+
self.__frame_rate,
|
|
83
|
+
)
|
|
84
|
+
profile = self.__pipeline.start(config)
|
|
85
|
+
color_profile = profile.get_stream(rs.stream.color)
|
|
86
|
+
color_intrinsics = color_profile.as_video_stream_profile(
|
|
87
|
+
).get_intrinsics()
|
|
88
|
+
self.__intri[0] = color_intrinsics.fx
|
|
89
|
+
self.__intri[1] = color_intrinsics.fy
|
|
90
|
+
self.__intri[2] = color_intrinsics.ppx
|
|
91
|
+
self.__intri[3] = color_intrinsics.ppy
|
|
92
|
+
self.__align = rs.align(rs.stream.color)
|
|
93
|
+
self.__bias_ns = None
|
|
94
|
+
|
|
95
|
+
# start work loop
|
|
96
|
+
self._working.set()
|
|
97
|
+
|
|
98
|
+
def get_intri(self) -> np.ndarray:
|
|
99
|
+
self._wait_for_working()
|
|
100
|
+
return self.__intri
|
|
101
|
+
|
|
102
|
+
def get_serial_number(self) -> np.ndarray:
|
|
103
|
+
self._wait_for_working()
|
|
104
|
+
return self.__serial_number
|
|
105
|
+
|
|
106
|
+
def work_loop(self, hex_queues: list[deque | threading.Event]):
|
|
107
|
+
rgb_queue = hex_queues[0]
|
|
108
|
+
depth_queue = hex_queues[1]
|
|
109
|
+
stop_event = hex_queues[2]
|
|
110
|
+
|
|
111
|
+
frames = self.__pipeline.wait_for_frames()
|
|
112
|
+
bias_ns = np.int64(hex_ns_now()) - np.int64(
|
|
113
|
+
frames.get_frame_metadata(rs.frame_metadata_value.sensor_timestamp)
|
|
114
|
+
* 1_000)
|
|
115
|
+
|
|
116
|
+
rgb_count = 0
|
|
117
|
+
depth_count = 0
|
|
118
|
+
while self._working.is_set() and not stop_event.is_set():
|
|
119
|
+
# read frame
|
|
120
|
+
aligned_frames = self.__align.process(
|
|
121
|
+
self.__pipeline.wait_for_frames())
|
|
122
|
+
cur_ns = hex_zmq_ts_now()
|
|
123
|
+
sen_ts_ns = bias_ns + np.int64(
|
|
124
|
+
aligned_frames.get_frame_metadata(
|
|
125
|
+
rs.frame_metadata_value.sensor_timestamp) * 1_000)
|
|
126
|
+
sen_ts = {
|
|
127
|
+
"s": sen_ts_ns // 1_000_000_000,
|
|
128
|
+
"ns": sen_ts_ns % 1_000_000_000,
|
|
129
|
+
}
|
|
130
|
+
if hex_zmq_ts_delta_ms(cur_ns, sen_ts) < 0:
|
|
131
|
+
sen_ts = cur_ns
|
|
132
|
+
|
|
133
|
+
# collect rgb frame
|
|
134
|
+
color_frame = aligned_frames.get_color_frame()
|
|
135
|
+
if color_frame:
|
|
136
|
+
|
|
137
|
+
rgb_queue.append((sen_ts if self.__sens_ts else cur_ns, rgb_count,
|
|
138
|
+
np.asanyarray(color_frame.get_data())))
|
|
139
|
+
rgb_count = (rgb_count + 1) % self._max_seq_num
|
|
140
|
+
|
|
141
|
+
# collect depth frame
|
|
142
|
+
depth_frame = aligned_frames.get_depth_frame()
|
|
143
|
+
if depth_frame:
|
|
144
|
+
depth_queue.append(
|
|
145
|
+
(sen_ts if self.__sens_ts else cur_ns, depth_count,
|
|
146
|
+
np.asanyarray(depth_frame.get_data())))
|
|
147
|
+
depth_count = (depth_count + 1) % self._max_seq_num
|
|
148
|
+
|
|
149
|
+
# close
|
|
150
|
+
self.close()
|
|
151
|
+
|
|
152
|
+
def close(self):
|
|
153
|
+
if not self._working.is_set():
|
|
154
|
+
return
|
|
155
|
+
self._working.clear()
|
|
156
|
+
self.__pipeline.stop()
|
|
157
|
+
hex_log(HEX_LOG_LEVEL["info"], "HexCamRealsense closed")
|
|
@@ -0,0 +1,31 @@
|
|
|
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
|
+
"client_timeout_ms": 200,
|
|
15
|
+
"server_timeout_ms": 1_000,
|
|
16
|
+
"server_num_workers": 4,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class HexCamRealsenseClient(HexCamClientBase):
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
net_config: dict = NET_CONFIG,
|
|
25
|
+
):
|
|
26
|
+
HexCamClientBase.__init__(self, net_config)
|
|
27
|
+
self._wait_for_working()
|
|
28
|
+
|
|
29
|
+
def get_intri(self):
|
|
30
|
+
intri_hdr, intri = self.request({"cmd": "get_intri"})
|
|
31
|
+
return intri_hdr, intri
|
|
@@ -0,0 +1,75 @@
|
|
|
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
|
+
"client_timeout_ms": 200,
|
|
28
|
+
"server_timeout_ms": 1_000,
|
|
29
|
+
"server_num_workers": 4,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
CAMERA_CONFIG = {
|
|
33
|
+
"serial_number": '243422073194',
|
|
34
|
+
"resolution": [640, 480],
|
|
35
|
+
"frame_rate": 30,
|
|
36
|
+
"sens_ts": True,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class HexCamRealsenseServer(HexCamServerBase):
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
net_config: dict = NET_CONFIG,
|
|
45
|
+
params_config: dict = CAMERA_CONFIG,
|
|
46
|
+
):
|
|
47
|
+
HexCamServerBase.__init__(self, net_config)
|
|
48
|
+
|
|
49
|
+
# camera
|
|
50
|
+
self._device = HexCamRealsense(params_config)
|
|
51
|
+
|
|
52
|
+
def _process_request(self, recv_hdr: dict, recv_buf: np.ndarray):
|
|
53
|
+
if recv_hdr["cmd"] == "is_working":
|
|
54
|
+
return self.no_ts_hdr(recv_hdr, self._device.is_working()), None
|
|
55
|
+
elif recv_hdr["cmd"] == "get_intri":
|
|
56
|
+
intri = self._device.get_intri()
|
|
57
|
+
return self.no_ts_hdr(recv_hdr, intri is not None), intri
|
|
58
|
+
elif recv_hdr["cmd"] == "get_rgb":
|
|
59
|
+
return self._get_frame(recv_hdr, False)
|
|
60
|
+
elif recv_hdr["cmd"] == "get_depth":
|
|
61
|
+
return self._get_frame(recv_hdr, True)
|
|
62
|
+
else:
|
|
63
|
+
raise ValueError(f"unknown command: {recv_hdr['cmd']}")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if __name__ == "__main__":
|
|
67
|
+
import argparse, json
|
|
68
|
+
from hex_zmq_servers.zmq_base import hex_server_helper
|
|
69
|
+
|
|
70
|
+
parser = argparse.ArgumentParser()
|
|
71
|
+
parser.add_argument("--cfg", type=str, required=True)
|
|
72
|
+
args = parser.parse_args()
|
|
73
|
+
cfg = json.loads(args.cfg)
|
|
74
|
+
|
|
75
|
+
hex_server_helper(cfg, HexCamRealsenseServer)
|