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.
- hex_zmq_servers/__init__.py +173 -0
- hex_zmq_servers/cam/__init__.py +52 -0
- hex_zmq_servers/cam/berxel/__init__.py +17 -0
- hex_zmq_servers/cam/berxel/cam_berxel.py +282 -0
- hex_zmq_servers/cam/berxel/cam_berxel_cli.py +33 -0
- hex_zmq_servers/cam/berxel/cam_berxel_srv.py +79 -0
- hex_zmq_servers/cam/cam_base.py +189 -0
- hex_zmq_servers/cam/dummy/__init__.py +17 -0
- hex_zmq_servers/cam/dummy/cam_dummy.py +69 -0
- hex_zmq_servers/cam/dummy/cam_dummy_cli.py +29 -0
- hex_zmq_servers/cam/dummy/cam_dummy_srv.py +68 -0
- hex_zmq_servers/cam/realsense/__init__.py +17 -0
- hex_zmq_servers/cam/realsense/cam_realsense.py +159 -0
- hex_zmq_servers/cam/realsense/cam_realsense_cli.py +33 -0
- hex_zmq_servers/cam/realsense/cam_realsense_srv.py +78 -0
- hex_zmq_servers/cam/rgb/__init__.py +17 -0
- hex_zmq_servers/cam/rgb/cam_rgb.py +135 -0
- hex_zmq_servers/cam/rgb/cam_rgb_cli.py +43 -0
- hex_zmq_servers/cam/rgb/cam_rgb_srv.py +78 -0
- hex_zmq_servers/config/cam_berxel.json +18 -0
- hex_zmq_servers/config/cam_dummy.json +12 -0
- hex_zmq_servers/config/cam_realsense.json +17 -0
- hex_zmq_servers/config/cam_rgb.json +28 -0
- hex_zmq_servers/config/mujoco_archer_y6.json +37 -0
- hex_zmq_servers/config/mujoco_e3_desktop.json +41 -0
- hex_zmq_servers/config/robot_dummy.json +153 -0
- hex_zmq_servers/config/robot_gello.json +66 -0
- hex_zmq_servers/config/robot_hexarm.json +37 -0
- hex_zmq_servers/config/zmq_dummy.json +12 -0
- hex_zmq_servers/device_base.py +44 -0
- hex_zmq_servers/hex_launch.py +489 -0
- hex_zmq_servers/mujoco/__init__.py +28 -0
- hex_zmq_servers/mujoco/archer_y6/__init__.py +17 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/arm_base_link.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/arm_link_1.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/arm_link_2.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/arm_link_3.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/arm_link_4.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/arm_link_5.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/assets.xml +17 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/camera_link.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_base_link.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_left_helper_link.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_left_link_1.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_left_link_2.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_right_helper_link.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_right_link_1.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_right_link_2.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/assets/table_link.STL +0 -0
- hex_zmq_servers/mujoco/archer_y6/model/robot.xml +95 -0
- hex_zmq_servers/mujoco/archer_y6/model/scene.xml +51 -0
- hex_zmq_servers/mujoco/archer_y6/model/setting.xml +37 -0
- hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6.py +325 -0
- hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6_cli.py +71 -0
- hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6_srv.py +148 -0
- hex_zmq_servers/mujoco/e3_desktop/__init__.py +17 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/arm_base_link.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/arm_link_1.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/arm_link_2.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/arm_link_3.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/arm_link_4.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/arm_link_5.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/assets.xml +18 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/camera_link.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/e3_desktop_base_link.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_base_link.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_left_helper_link.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_left_link_1.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_left_link_2.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_right_helper_link.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_right_link_1.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_right_link_2.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/assets/table_link.STL +0 -0
- hex_zmq_servers/mujoco/e3_desktop/model/robot.xml +188 -0
- hex_zmq_servers/mujoco/e3_desktop/model/scene.xml +53 -0
- hex_zmq_servers/mujoco/e3_desktop/model/setting.xml +72 -0
- hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop.py +449 -0
- hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop_cli.py +289 -0
- hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop_srv.py +244 -0
- hex_zmq_servers/mujoco/mujoco_base.py +425 -0
- hex_zmq_servers/robot/__init__.py +37 -0
- hex_zmq_servers/robot/dummy/__init__.py +17 -0
- hex_zmq_servers/robot/dummy/robot_dummy.py +94 -0
- hex_zmq_servers/robot/dummy/robot_dummy_cli.py +29 -0
- hex_zmq_servers/robot/dummy/robot_dummy_srv.py +82 -0
- hex_zmq_servers/robot/gello/__init__.py +17 -0
- hex_zmq_servers/robot/gello/robot_gello.py +366 -0
- hex_zmq_servers/robot/gello/robot_gello_cli.py +29 -0
- hex_zmq_servers/robot/gello/robot_gello_srv.py +93 -0
- hex_zmq_servers/robot/hexarm/__init__.py +47 -0
- hex_zmq_servers/robot/hexarm/robot_hexarm.py +292 -0
- hex_zmq_servers/robot/hexarm/robot_hexarm_cli.py +37 -0
- hex_zmq_servers/robot/hexarm/robot_hexarm_srv.py +87 -0
- hex_zmq_servers/robot/hexarm/urdf/archer_l6y/empty.urdf +206 -0
- hex_zmq_servers/robot/hexarm/urdf/archer_l6y/gp100.urdf +206 -0
- hex_zmq_servers/robot/hexarm/urdf/archer_l6y/gp100_handle.urdf +206 -0
- hex_zmq_servers/robot/hexarm/urdf/archer_l6y/gp100_p050.urdf +206 -0
- hex_zmq_servers/robot/hexarm/urdf/archer_l6y/gp100_p050_handle.urdf +206 -0
- hex_zmq_servers/robot/hexarm/urdf/archer_y6/empty.urdf +207 -0
- hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100.urdf +207 -0
- hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100_handle.urdf +207 -0
- hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100_p050.urdf +207 -0
- hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100_p050_handle.urdf +207 -0
- hex_zmq_servers/robot/robot_base.py +276 -0
- hex_zmq_servers/zmq_base.py +547 -0
- hex_zmq_servers-0.3.9.dist-info/METADATA +147 -0
- hex_zmq_servers-0.3.9.dist-info/RECORD +110 -0
- hex_zmq_servers-0.3.9.dist-info/WHEEL +5 -0
- hex_zmq_servers-0.3.9.dist-info/licenses/LICENSE +201 -0
- hex_zmq_servers-0.3.9.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,425 @@
|
|
|
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 (
|
|
16
|
+
hex_zmq_ts_now,
|
|
17
|
+
HexZMQClientBase,
|
|
18
|
+
HexZMQServerBase,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
NET_CONFIG = {
|
|
22
|
+
"ip": "127.0.0.1",
|
|
23
|
+
"port": 12345,
|
|
24
|
+
"realtime_mode": False,
|
|
25
|
+
"deque_maxlen": 10,
|
|
26
|
+
"client_timeout_ms": 200,
|
|
27
|
+
"server_timeout_ms": 1_000,
|
|
28
|
+
"server_num_workers": 4,
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
TAU = 2 * np.pi
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class HexMujocoBase(HexDeviceBase):
|
|
35
|
+
|
|
36
|
+
def __init__(self, realtime_mode: bool = False):
|
|
37
|
+
HexDeviceBase.__init__(self, realtime_mode)
|
|
38
|
+
self._dofs = None
|
|
39
|
+
self._limits = None
|
|
40
|
+
self._intri = None
|
|
41
|
+
|
|
42
|
+
def __del__(self):
|
|
43
|
+
HexDeviceBase.__del__(self)
|
|
44
|
+
|
|
45
|
+
def is_working(self) -> bool:
|
|
46
|
+
return self._working.is_set()
|
|
47
|
+
|
|
48
|
+
def get_dofs(self) -> np.ndarray:
|
|
49
|
+
self._wait_for_working()
|
|
50
|
+
return np.array(self._dofs, dtype=np.uint8)
|
|
51
|
+
|
|
52
|
+
def get_limits(self) -> np.ndarray:
|
|
53
|
+
self._wait_for_working()
|
|
54
|
+
return self._limits
|
|
55
|
+
|
|
56
|
+
def get_intri(self) -> np.ndarray:
|
|
57
|
+
self._wait_for_working()
|
|
58
|
+
return self._intri
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def _rads_normalize(rads: np.ndarray) -> np.ndarray:
|
|
62
|
+
return (rads + np.pi) % TAU - np.pi
|
|
63
|
+
|
|
64
|
+
@staticmethod
|
|
65
|
+
def _apply_pos_limits(
|
|
66
|
+
rads: np.ndarray,
|
|
67
|
+
lower_bound: np.ndarray,
|
|
68
|
+
upper_bound: np.ndarray,
|
|
69
|
+
) -> np.ndarray:
|
|
70
|
+
normed_rads = HexMujocoBase._rads_normalize(rads)
|
|
71
|
+
outside = (normed_rads < lower_bound) | (normed_rads > upper_bound)
|
|
72
|
+
if not np.any(outside):
|
|
73
|
+
return normed_rads
|
|
74
|
+
|
|
75
|
+
lower_dist = np.fabs(
|
|
76
|
+
HexMujocoBase._rads_normalize(
|
|
77
|
+
(normed_rads - lower_bound)[outside]))
|
|
78
|
+
upper_dist = np.fabs(
|
|
79
|
+
HexMujocoBase._rads_normalize(
|
|
80
|
+
(normed_rads - upper_bound)[outside]))
|
|
81
|
+
choose_lower = lower_dist < upper_dist
|
|
82
|
+
choose_upper = ~choose_lower
|
|
83
|
+
|
|
84
|
+
outside_full = np.flatnonzero(outside)
|
|
85
|
+
outside_lower = outside_full[choose_lower]
|
|
86
|
+
outside_upper = outside_full[choose_upper]
|
|
87
|
+
normed_rads[outside_lower] = lower_bound[outside_lower]
|
|
88
|
+
normed_rads[outside_upper] = upper_bound[outside_upper]
|
|
89
|
+
|
|
90
|
+
return normed_rads
|
|
91
|
+
|
|
92
|
+
@abstractmethod
|
|
93
|
+
def work_loop(self, hex_queues: list[deque | threading.Event]):
|
|
94
|
+
raise NotImplementedError(
|
|
95
|
+
"`work_loop` should be implemented by the child class")
|
|
96
|
+
|
|
97
|
+
@abstractmethod
|
|
98
|
+
def close(self):
|
|
99
|
+
raise NotImplementedError(
|
|
100
|
+
"`close` should be implemented by the child class")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class HexMujocoClientBase(HexZMQClientBase):
|
|
104
|
+
|
|
105
|
+
def __init__(self, net_config: dict = NET_CONFIG):
|
|
106
|
+
HexZMQClientBase.__init__(self, net_config)
|
|
107
|
+
self._states_seq = {
|
|
108
|
+
"robot": 0,
|
|
109
|
+
"obj": 0,
|
|
110
|
+
}
|
|
111
|
+
self._used_states_queue = {
|
|
112
|
+
"robot": 0,
|
|
113
|
+
"obj": 0,
|
|
114
|
+
}
|
|
115
|
+
self._states_queue = {
|
|
116
|
+
"robot": deque(maxlen=self._max_seq_num),
|
|
117
|
+
"obj": deque(maxlen=self._max_seq_num),
|
|
118
|
+
}
|
|
119
|
+
self._camera_seq = {
|
|
120
|
+
"rgb": 0,
|
|
121
|
+
"depth": 0,
|
|
122
|
+
}
|
|
123
|
+
self._used_camera_seq = {
|
|
124
|
+
"rgb": 0,
|
|
125
|
+
"depth": 0,
|
|
126
|
+
}
|
|
127
|
+
self._camera_queue = {
|
|
128
|
+
"rgb": deque(maxlen=self._deque_maxlen),
|
|
129
|
+
"depth": deque(maxlen=self._deque_maxlen),
|
|
130
|
+
}
|
|
131
|
+
self._cmds_seq = 0
|
|
132
|
+
self._cmds_queue = deque(maxlen=self._deque_maxlen)
|
|
133
|
+
|
|
134
|
+
def __del__(self):
|
|
135
|
+
HexZMQClientBase.__del__(self)
|
|
136
|
+
|
|
137
|
+
def reset(self):
|
|
138
|
+
self._states_seq = {
|
|
139
|
+
"robot": 0,
|
|
140
|
+
"obj": 0,
|
|
141
|
+
}
|
|
142
|
+
self._used_states_queue = {
|
|
143
|
+
"robot": 0,
|
|
144
|
+
"obj": 0,
|
|
145
|
+
}
|
|
146
|
+
self._camera_seq = {
|
|
147
|
+
"rgb": 0,
|
|
148
|
+
"depth": 0,
|
|
149
|
+
}
|
|
150
|
+
self._used_camera_seq = {
|
|
151
|
+
"rgb": 0,
|
|
152
|
+
"depth": 0,
|
|
153
|
+
}
|
|
154
|
+
self._cmds_seq = 0
|
|
155
|
+
|
|
156
|
+
hdr, _ = self.request({"cmd": "reset"})
|
|
157
|
+
return hdr
|
|
158
|
+
|
|
159
|
+
def seq_clear(self):
|
|
160
|
+
clear_hdr, _ = self.request({"cmd": "seq_clear"})
|
|
161
|
+
return clear_hdr
|
|
162
|
+
|
|
163
|
+
def get_dofs(self):
|
|
164
|
+
_, dofs = self.request({"cmd": "get_dofs"})
|
|
165
|
+
return dofs
|
|
166
|
+
|
|
167
|
+
def get_limits(self):
|
|
168
|
+
_, limits = self.request({"cmd": "get_limits"})
|
|
169
|
+
return limits
|
|
170
|
+
|
|
171
|
+
def get_states(self, robot_name: str | None = None, newest: bool = False):
|
|
172
|
+
try:
|
|
173
|
+
if self._realtime_mode or newest:
|
|
174
|
+
hdr, states = self._states_queue[robot_name][-1]
|
|
175
|
+
if self._used_states_queue[robot_name] != hdr["args"]:
|
|
176
|
+
self._used_states_queue[robot_name] = hdr["args"]
|
|
177
|
+
return hdr, states
|
|
178
|
+
else:
|
|
179
|
+
return None, None
|
|
180
|
+
else:
|
|
181
|
+
return self._states_queue[robot_name].popleft()
|
|
182
|
+
except IndexError:
|
|
183
|
+
return None, None
|
|
184
|
+
except KeyError:
|
|
185
|
+
print(f"\033[91munknown robot name: {robot_name}\033[0m")
|
|
186
|
+
return None, None
|
|
187
|
+
|
|
188
|
+
def get_rgb(self, camera_name: str | None = None, newest: bool = False):
|
|
189
|
+
try:
|
|
190
|
+
if self._realtime_mode or newest:
|
|
191
|
+
hdr, img = self._camera_queue["rgb"][-1]
|
|
192
|
+
if self._used_camera_seq["rgb"] != hdr["args"]:
|
|
193
|
+
self._used_camera_seq["rgb"] = hdr["args"]
|
|
194
|
+
return hdr, img
|
|
195
|
+
else:
|
|
196
|
+
return None, None
|
|
197
|
+
else:
|
|
198
|
+
return self._camera_queue["rgb"].popleft()
|
|
199
|
+
except IndexError:
|
|
200
|
+
return None, None
|
|
201
|
+
|
|
202
|
+
def get_depth(self, camera_name: str | None = None, newest: bool = False):
|
|
203
|
+
try:
|
|
204
|
+
if self._realtime_mode or newest:
|
|
205
|
+
hdr, img = self._camera_queue["depth"][-1]
|
|
206
|
+
if self._used_camera_seq["depth"] != hdr["args"]:
|
|
207
|
+
self._used_camera_seq["depth"] = hdr["args"]
|
|
208
|
+
return hdr, img
|
|
209
|
+
else:
|
|
210
|
+
return None, None
|
|
211
|
+
else:
|
|
212
|
+
return self._camera_queue["depth"].popleft()
|
|
213
|
+
except IndexError:
|
|
214
|
+
return None, None
|
|
215
|
+
|
|
216
|
+
def set_cmds(self, cmds: np.ndarray):
|
|
217
|
+
self._cmds_queue.append(cmds)
|
|
218
|
+
|
|
219
|
+
def get_intri(self):
|
|
220
|
+
intri_hdr, intri = self.request({"cmd": "get_intri"})
|
|
221
|
+
return intri_hdr, intri
|
|
222
|
+
|
|
223
|
+
def _get_rgb_inner(self, camera_name: str | None = None):
|
|
224
|
+
return self._process_frame(camera_name, False)
|
|
225
|
+
|
|
226
|
+
def _get_depth_inner(self, camera_name: str | None = None):
|
|
227
|
+
return self._process_frame(camera_name, True)
|
|
228
|
+
|
|
229
|
+
def _process_frame(
|
|
230
|
+
self,
|
|
231
|
+
camera_name: str | None = None,
|
|
232
|
+
depth_flag: bool = False,
|
|
233
|
+
):
|
|
234
|
+
req_cmd = f"get_{'depth' if depth_flag else 'rgb'}"
|
|
235
|
+
if camera_name is not None:
|
|
236
|
+
req_cmd += f"_{camera_name}"
|
|
237
|
+
|
|
238
|
+
hdr, img = self.request({
|
|
239
|
+
"cmd":
|
|
240
|
+
req_cmd,
|
|
241
|
+
"args": (1 + self._camera_seq['depth' if depth_flag else 'rgb']) %
|
|
242
|
+
self._max_seq_num,
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
cmd = hdr["cmd"]
|
|
247
|
+
if cmd == f"{req_cmd}_ok":
|
|
248
|
+
if depth_flag:
|
|
249
|
+
self._depth_seq = hdr["args"]
|
|
250
|
+
else:
|
|
251
|
+
self._rgb_seq = hdr["args"]
|
|
252
|
+
return hdr, img
|
|
253
|
+
else:
|
|
254
|
+
return None, None
|
|
255
|
+
except KeyError:
|
|
256
|
+
print(f"\033[91m{hdr['cmd']} requires `cmd`\033[0m")
|
|
257
|
+
return None, None
|
|
258
|
+
except Exception as e:
|
|
259
|
+
print(f"\033[91m__process_frame failed: {e}\033[0m")
|
|
260
|
+
return None, None
|
|
261
|
+
|
|
262
|
+
def _get_states_inner(self, robot_name: str | None = None):
|
|
263
|
+
req_cmd = "get_states"
|
|
264
|
+
if robot_name is not None:
|
|
265
|
+
req_cmd += f"_{robot_name}"
|
|
266
|
+
hdr, states = self.request({
|
|
267
|
+
"cmd":
|
|
268
|
+
req_cmd,
|
|
269
|
+
"args": (1 + self._states_seq[robot_name]) % self._max_seq_num,
|
|
270
|
+
})
|
|
271
|
+
try:
|
|
272
|
+
if hdr["cmd"] == f"{req_cmd}_ok":
|
|
273
|
+
self._states_seq[robot_name] = hdr["args"]
|
|
274
|
+
return hdr, states
|
|
275
|
+
else:
|
|
276
|
+
return None, None
|
|
277
|
+
except KeyError:
|
|
278
|
+
print(f"\033[91m{hdr['cmd']} requires `cmd`\033[0m")
|
|
279
|
+
return None, None
|
|
280
|
+
except Exception as e:
|
|
281
|
+
print(f"\033[91m{req_cmd} failed: {e}\033[0m")
|
|
282
|
+
return None, None
|
|
283
|
+
|
|
284
|
+
def _set_cmds_inner(
|
|
285
|
+
self,
|
|
286
|
+
cmds: np.ndarray,
|
|
287
|
+
) -> bool:
|
|
288
|
+
req_cmd = "set_cmds"
|
|
289
|
+
hdr, _ = self.request(
|
|
290
|
+
{
|
|
291
|
+
"cmd": req_cmd,
|
|
292
|
+
"ts": hex_zmq_ts_now(),
|
|
293
|
+
"args": self._cmds_seq,
|
|
294
|
+
},
|
|
295
|
+
cmds,
|
|
296
|
+
)
|
|
297
|
+
# print(f"{req_cmd} seq: {self._cmds_seq}")
|
|
298
|
+
try:
|
|
299
|
+
cmd = hdr["cmd"]
|
|
300
|
+
if cmd == f"{req_cmd}_ok":
|
|
301
|
+
self._cmds_seq = (self._cmds_seq + 1) % self._max_seq_num
|
|
302
|
+
return True
|
|
303
|
+
else:
|
|
304
|
+
return False
|
|
305
|
+
except KeyError:
|
|
306
|
+
print(f"\033[91m{hdr['cmd']} requires `cmd`\033[0m")
|
|
307
|
+
return False
|
|
308
|
+
except Exception as e:
|
|
309
|
+
print(f"\033[91m{req_cmd} failed: {e}\033[0m")
|
|
310
|
+
return False
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
class HexMujocoServerBase(HexZMQServerBase):
|
|
314
|
+
|
|
315
|
+
def __init__(self, net_config: dict = NET_CONFIG):
|
|
316
|
+
HexZMQServerBase.__init__(self, net_config)
|
|
317
|
+
self._device: HexDeviceBase = None
|
|
318
|
+
self._states_queue = deque(maxlen=self._deque_maxlen)
|
|
319
|
+
self._obj_pose_queue = deque(maxlen=self._deque_maxlen)
|
|
320
|
+
self._cmds_queue = deque(maxlen=self._deque_maxlen)
|
|
321
|
+
self._cmds_seq = -1
|
|
322
|
+
self._rgb_queue = deque(maxlen=self._deque_maxlen)
|
|
323
|
+
self._depth_queue = deque(maxlen=self._deque_maxlen)
|
|
324
|
+
self._seq_clear_flag = False
|
|
325
|
+
|
|
326
|
+
def work_loop(self):
|
|
327
|
+
try:
|
|
328
|
+
self._device.work_loop([
|
|
329
|
+
self._states_queue,
|
|
330
|
+
self._obj_pose_queue,
|
|
331
|
+
self._cmds_queue,
|
|
332
|
+
self._rgb_queue,
|
|
333
|
+
self._depth_queue,
|
|
334
|
+
self._stop_event,
|
|
335
|
+
])
|
|
336
|
+
finally:
|
|
337
|
+
self._device.close()
|
|
338
|
+
|
|
339
|
+
def _seq_clear(self):
|
|
340
|
+
self._seq_clear_flag = True
|
|
341
|
+
return True
|
|
342
|
+
|
|
343
|
+
def _get_states(self, recv_hdr: dict):
|
|
344
|
+
try:
|
|
345
|
+
seq = recv_hdr["args"]
|
|
346
|
+
except KeyError:
|
|
347
|
+
print(f"\033[91m{recv_hdr['cmd']} requires `args`\033[0m")
|
|
348
|
+
return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
|
|
349
|
+
|
|
350
|
+
try:
|
|
351
|
+
ts, count, states = self._states_queue[
|
|
352
|
+
-1] if self._realtime_mode else self._states_queue.popleft()
|
|
353
|
+
except IndexError:
|
|
354
|
+
return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
|
|
355
|
+
except Exception as e:
|
|
356
|
+
print(f"\033[91m{recv_hdr['cmd']} failed: {e}\033[0m")
|
|
357
|
+
return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
|
|
358
|
+
|
|
359
|
+
delta = (count - seq) % self._max_seq_num
|
|
360
|
+
if delta >= 0 and delta < 1e6:
|
|
361
|
+
return {
|
|
362
|
+
"cmd": f"{recv_hdr['cmd']}_ok",
|
|
363
|
+
"ts": ts,
|
|
364
|
+
"args": count
|
|
365
|
+
}, states
|
|
366
|
+
else:
|
|
367
|
+
return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
|
|
368
|
+
|
|
369
|
+
def _set_cmds(self, recv_hdr: dict, recv_buf: np.ndarray):
|
|
370
|
+
seq = recv_hdr.get("args", None)
|
|
371
|
+
if self._seq_clear_flag:
|
|
372
|
+
self._seq_clear_flag = False
|
|
373
|
+
self._cmds_seq = -1
|
|
374
|
+
return self.no_ts_hdr(recv_hdr, False), None
|
|
375
|
+
|
|
376
|
+
if seq is not None and seq > self._cmds_seq:
|
|
377
|
+
delta = (seq - self._cmds_seq) % self._max_seq_num
|
|
378
|
+
if delta >= 0 and delta < 1e6:
|
|
379
|
+
self._cmds_seq = seq
|
|
380
|
+
self._cmds_queue.append((recv_hdr["ts"], seq, recv_buf))
|
|
381
|
+
return self.no_ts_hdr(recv_hdr, True), None
|
|
382
|
+
else:
|
|
383
|
+
return self.no_ts_hdr(recv_hdr, False), None
|
|
384
|
+
else:
|
|
385
|
+
return self.no_ts_hdr(recv_hdr, False), None
|
|
386
|
+
|
|
387
|
+
def _get_frame(self, recv_hdr: dict):
|
|
388
|
+
try:
|
|
389
|
+
seq = recv_hdr["args"]
|
|
390
|
+
except KeyError:
|
|
391
|
+
print(f"\033[91m{recv_hdr['cmd']} requires `args`\033[0m")
|
|
392
|
+
return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
|
|
393
|
+
|
|
394
|
+
# get camera config
|
|
395
|
+
split_cmd = recv_hdr["cmd"].split("_")
|
|
396
|
+
depth_flag = split_cmd[1] == "depth"
|
|
397
|
+
|
|
398
|
+
try:
|
|
399
|
+
if depth_flag:
|
|
400
|
+
ts, count, img = self._depth_queue[
|
|
401
|
+
-1] if self._realtime_mode else self._depth_queue.popleft(
|
|
402
|
+
)
|
|
403
|
+
else:
|
|
404
|
+
ts, count, img = self._rgb_queue[
|
|
405
|
+
-1] if self._realtime_mode else self._rgb_queue.popleft()
|
|
406
|
+
except IndexError:
|
|
407
|
+
return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
|
|
408
|
+
except Exception as e:
|
|
409
|
+
print(f"\033[91m{recv_hdr['cmd']} failed: {e}\033[0m")
|
|
410
|
+
return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
|
|
411
|
+
|
|
412
|
+
delta = (count - seq) % self._max_seq_num
|
|
413
|
+
if delta >= 0 and delta < 1e6:
|
|
414
|
+
return {
|
|
415
|
+
"cmd": f"{recv_hdr['cmd']}_ok",
|
|
416
|
+
"ts": ts,
|
|
417
|
+
"args": count
|
|
418
|
+
}, img
|
|
419
|
+
else:
|
|
420
|
+
return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
|
|
421
|
+
|
|
422
|
+
@abstractmethod
|
|
423
|
+
def _process_request(self, recv_hdr: dict, recv_buf: np.ndarray):
|
|
424
|
+
raise NotImplementedError(
|
|
425
|
+
"`_process_request` should be implemented by the child class")
|
|
@@ -0,0 +1,37 @@
|
|
|
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 .robot_base import HexRobotBase, HexRobotClientBase, HexRobotServerBase
|
|
10
|
+
from .dummy import HexRobotDummy, HexRobotDummyClient, HexRobotDummyServer
|
|
11
|
+
from .gello import HexRobotGello, HexRobotGelloClient, HexRobotGelloServer
|
|
12
|
+
from .hexarm import HexRobotHexarm, HexRobotHexarmClient, HexRobotHexarmServer, HEXARM_URDF_PATH_DICT
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
# path
|
|
16
|
+
"HEXARM_URDF_PATH_DICT",
|
|
17
|
+
|
|
18
|
+
# base
|
|
19
|
+
"HexRobotBase",
|
|
20
|
+
"HexRobotClientBase",
|
|
21
|
+
"HexRobotServerBase",
|
|
22
|
+
|
|
23
|
+
# dummy
|
|
24
|
+
"HexRobotDummy",
|
|
25
|
+
"HexRobotDummyClient",
|
|
26
|
+
"HexRobotDummyServer",
|
|
27
|
+
|
|
28
|
+
# gello
|
|
29
|
+
"HexRobotGello",
|
|
30
|
+
"HexRobotGelloClient",
|
|
31
|
+
"HexRobotGelloServer",
|
|
32
|
+
|
|
33
|
+
# hexarm
|
|
34
|
+
"HexRobotHexarm",
|
|
35
|
+
"HexRobotHexarmClient",
|
|
36
|
+
"HexRobotHexarmServer",
|
|
37
|
+
]
|
|
@@ -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 .robot_dummy import HexRobotDummy
|
|
10
|
+
from .robot_dummy_cli import HexRobotDummyClient
|
|
11
|
+
from .robot_dummy_srv import HexRobotDummyServer
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"HexRobotDummy",
|
|
15
|
+
"HexRobotDummyClient",
|
|
16
|
+
"HexRobotDummyServer",
|
|
17
|
+
]
|
|
@@ -0,0 +1,94 @@
|
|
|
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 ..robot_base import HexRobotBase
|
|
14
|
+
from ...zmq_base import (
|
|
15
|
+
hex_zmq_ts_now,
|
|
16
|
+
hex_zmq_ts_delta_ms,
|
|
17
|
+
HexRate,
|
|
18
|
+
)
|
|
19
|
+
from ...hex_launch import hex_log, HEX_LOG_LEVEL
|
|
20
|
+
|
|
21
|
+
ROBOT_CONFIG = {
|
|
22
|
+
"dofs": [7],
|
|
23
|
+
"limits": [[[-1.0, 1.0]] * 3] * 7,
|
|
24
|
+
"states_init": [[0.0, 0.0, 0.0]] * 7,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class HexRobotDummy(HexRobotBase):
|
|
29
|
+
|
|
30
|
+
def __init__(
|
|
31
|
+
self,
|
|
32
|
+
robot_config: dict = ROBOT_CONFIG,
|
|
33
|
+
realtime_mode: bool = False,
|
|
34
|
+
):
|
|
35
|
+
HexRobotBase.__init__(self, realtime_mode)
|
|
36
|
+
|
|
37
|
+
try:
|
|
38
|
+
self._dofs = robot_config["dofs"]
|
|
39
|
+
self._limits = np.array(robot_config["limits"])
|
|
40
|
+
except KeyError as ke:
|
|
41
|
+
missing_key = ke.args[0]
|
|
42
|
+
raise ValueError(
|
|
43
|
+
f"robot_config is not valid, missing key: {missing_key}")
|
|
44
|
+
|
|
45
|
+
# start work loop
|
|
46
|
+
self._working.set()
|
|
47
|
+
|
|
48
|
+
def __del__(self):
|
|
49
|
+
HexRobotBase.__del__(self)
|
|
50
|
+
|
|
51
|
+
def work_loop(self, hex_queues: list[deque | threading.Event]):
|
|
52
|
+
states_queue = hex_queues[0]
|
|
53
|
+
cmds_queue = hex_queues[1]
|
|
54
|
+
stop_event = hex_queues[2]
|
|
55
|
+
|
|
56
|
+
dummy_states = np.zeros((self._dofs[0], 3))
|
|
57
|
+
states_count = 0
|
|
58
|
+
last_cmds_seq = -1
|
|
59
|
+
rate = HexRate(1000)
|
|
60
|
+
while self._working.is_set() and not stop_event.is_set():
|
|
61
|
+
# states
|
|
62
|
+
states_queue.append((hex_zmq_ts_now(), states_count, dummy_states))
|
|
63
|
+
states_count = (states_count + 1) % self._max_seq_num
|
|
64
|
+
|
|
65
|
+
# cmds
|
|
66
|
+
cmds_pack = None
|
|
67
|
+
try:
|
|
68
|
+
cmds_pack = cmds_queue[
|
|
69
|
+
-1] if self._realtime_mode else cmds_queue.popleft()
|
|
70
|
+
except IndexError:
|
|
71
|
+
pass
|
|
72
|
+
if cmds_pack is not None:
|
|
73
|
+
ts, seq, cmds = cmds_pack
|
|
74
|
+
if seq != last_cmds_seq:
|
|
75
|
+
last_cmds_seq = seq
|
|
76
|
+
if hex_zmq_ts_delta_ms(hex_zmq_ts_now(), ts) < 200.0:
|
|
77
|
+
cmds = np.clip(
|
|
78
|
+
cmds,
|
|
79
|
+
self._limits[:, :, 0],
|
|
80
|
+
self._limits[:, :, 1],
|
|
81
|
+
)
|
|
82
|
+
dummy_states = cmds.copy()
|
|
83
|
+
|
|
84
|
+
# sleep
|
|
85
|
+
rate.sleep()
|
|
86
|
+
|
|
87
|
+
# close
|
|
88
|
+
self.close()
|
|
89
|
+
|
|
90
|
+
def close(self):
|
|
91
|
+
if not self._working.is_set():
|
|
92
|
+
return
|
|
93
|
+
self._working.clear()
|
|
94
|
+
hex_log(HEX_LOG_LEVEL["info"], "HexRobotDummy 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-16
|
|
7
|
+
################################################################
|
|
8
|
+
|
|
9
|
+
from ..robot_base import HexRobotClientBase
|
|
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 HexRobotDummyClient(HexRobotClientBase):
|
|
23
|
+
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
net_config: dict = NET_CONFIG,
|
|
27
|
+
):
|
|
28
|
+
HexRobotClientBase.__init__(self, net_config)
|
|
29
|
+
self._wait_for_working()
|
|
@@ -0,0 +1,82 @@
|
|
|
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 ..robot_base import HexRobotServerBase
|
|
13
|
+
from .robot_dummy import HexRobotDummy
|
|
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.robot.robot_base import HexRobotServerBase
|
|
22
|
+
from hex_zmq_servers.robot.dummy.robot_dummy import HexRobotDummy
|
|
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
|
+
ROBOT_CONFIG = {
|
|
35
|
+
"dofs": [7],
|
|
36
|
+
"limits": [[[-1.0, 1.0]] * 3] * 7,
|
|
37
|
+
"states_init": [[0.0, 0.0, 0.0]] * 7,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class HexRobotDummyServer(HexRobotServerBase):
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
net_config: dict = NET_CONFIG,
|
|
46
|
+
params_config: dict = ROBOT_CONFIG,
|
|
47
|
+
):
|
|
48
|
+
HexRobotServerBase.__init__(self, net_config)
|
|
49
|
+
|
|
50
|
+
# robot
|
|
51
|
+
self._device = HexRobotDummy(params_config,
|
|
52
|
+
net_config.get("realtime_mode", False))
|
|
53
|
+
|
|
54
|
+
def _process_request(self, recv_hdr: dict, recv_buf: np.ndarray):
|
|
55
|
+
if recv_hdr["cmd"] == "is_working":
|
|
56
|
+
return self.no_ts_hdr(recv_hdr, self._device.is_working()), None
|
|
57
|
+
elif recv_hdr["cmd"] == "seq_clear":
|
|
58
|
+
return self.no_ts_hdr(recv_hdr, self._seq_clear()), None
|
|
59
|
+
elif recv_hdr["cmd"] == "get_dofs":
|
|
60
|
+
dofs = self._device.get_dofs()
|
|
61
|
+
return self.no_ts_hdr(recv_hdr, dofs is not None), dofs
|
|
62
|
+
elif recv_hdr["cmd"] == "get_limits":
|
|
63
|
+
limits = self._device.get_limits()
|
|
64
|
+
return self.no_ts_hdr(recv_hdr, limits is not None), limits
|
|
65
|
+
elif recv_hdr["cmd"] == "get_states":
|
|
66
|
+
return self._get_states(recv_hdr)
|
|
67
|
+
elif recv_hdr["cmd"] == "set_cmds":
|
|
68
|
+
return self._set_cmds(recv_hdr, recv_buf)
|
|
69
|
+
else:
|
|
70
|
+
raise ValueError(f"unknown command: {recv_hdr['cmd']}")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
if __name__ == "__main__":
|
|
74
|
+
import argparse, json
|
|
75
|
+
from hex_zmq_servers.zmq_base import hex_server_helper
|
|
76
|
+
|
|
77
|
+
parser = argparse.ArgumentParser()
|
|
78
|
+
parser.add_argument("--cfg", type=str, required=True)
|
|
79
|
+
args = parser.parse_args()
|
|
80
|
+
cfg = json.loads(args.cfg)
|
|
81
|
+
|
|
82
|
+
hex_server_helper(cfg, HexRobotDummyServer)
|
|
@@ -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 .robot_gello import HexRobotGello
|
|
10
|
+
from .robot_gello_cli import HexRobotGelloClient
|
|
11
|
+
from .robot_gello_srv import HexRobotGelloServer
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"HexRobotGello",
|
|
15
|
+
"HexRobotGelloClient",
|
|
16
|
+
"HexRobotGelloServer",
|
|
17
|
+
]
|