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,449 @@
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-17
7
+ ################################################################
8
+
9
+ import os
10
+ import copy
11
+ import threading
12
+ import cv2
13
+ import numpy as np
14
+ from collections import deque
15
+
16
+ import mujoco
17
+ from mujoco import viewer
18
+
19
+ from ..mujoco_base import HexMujocoBase
20
+ from ...zmq_base import (
21
+ hex_ns_now,
22
+ hex_zmq_ts_now,
23
+ ns_to_hex_zmq_ts,
24
+ hex_zmq_ts_delta_ms,
25
+ HexRate,
26
+ )
27
+ from ...hex_launch import hex_log, HEX_LOG_LEVEL
28
+ from hex_robo_utils import HexCtrlUtilMitJoint as CtrlUtil
29
+
30
+ MUJOCO_CONFIG = {
31
+ "states_rate": 1000,
32
+ "img_rate": 30,
33
+ "tau_ctrl": False,
34
+ "mit_kp": [200.0, 200.0, 200.0, 75.0, 15.0, 15.0, 20.0],
35
+ "mit_kd": [12.5, 12.5, 12.5, 6.0, 0.31, 0.31, 1.0],
36
+ "cam_type": ["empty", "empty", "empty"],
37
+ "headless": False,
38
+ "sens_ts": True,
39
+ }
40
+ CAMERA_CONFIG = {
41
+ "empty": (False, False),
42
+ "rgb": (True, False),
43
+ "berxel": (True, True),
44
+ "realsense": (True, True),
45
+ }
46
+
47
+
48
+ class HexMujocoE3Desktop(HexMujocoBase):
49
+
50
+ def __init__(
51
+ self,
52
+ mujoco_config: dict = MUJOCO_CONFIG,
53
+ realtime_mode: bool = False,
54
+ ):
55
+ HexMujocoBase.__init__(self, realtime_mode)
56
+
57
+ try:
58
+ states_rate = mujoco_config["states_rate"]
59
+ img_rate = mujoco_config["img_rate"]
60
+ self.__tau_ctrl = mujoco_config["tau_ctrl"]
61
+ self.__mit_kp = mujoco_config["mit_kp"]
62
+ self.__mit_kd = mujoco_config["mit_kd"]
63
+ self.__cam_type = mujoco_config["cam_type"]
64
+ self.__headless = mujoco_config["headless"]
65
+ self.__sens_ts = mujoco_config["sens_ts"]
66
+ except KeyError as ke:
67
+ missing_key = ke.args[0]
68
+ raise ValueError(
69
+ f"mujoco_config is not valid, missing key: {missing_key}")
70
+
71
+ # mujoco init
72
+ model_path = os.path.join(os.path.dirname(__file__), "model/scene.xml")
73
+ self.__model = mujoco.MjModel.from_xml_path(model_path)
74
+ self.__data = mujoco.MjData(self.__model)
75
+ self.__sim_rate = int(1.0 / self.__model.opt.timestep)
76
+
77
+ # state init
78
+ self.__state_left_idx = [0, 1, 2, 3, 4, 5, 6]
79
+ self.__state_right_idx = [12, 13, 14, 15, 16, 17, 18]
80
+ self.__obj_pose_idx = [24, 25, 26, 27, 28, 29, 30]
81
+ self.__ctrl_left_idx = [0, 1, 2, 3, 4, 5, 6]
82
+ self.__ctrl_right_idx = [7, 8, 9, 10, 11, 12, 13]
83
+ self._limits = np.stack(
84
+ [
85
+ self.__model.jnt_range[self.__state_left_idx, :],
86
+ self.__model.jnt_range[self.__state_right_idx, :]
87
+ ],
88
+ axis=0,
89
+ )
90
+ if not self.__tau_ctrl:
91
+ self.__mit_kp = np.ascontiguousarray(np.asarray(self.__mit_kp))
92
+ self.__mit_kd = np.ascontiguousarray(np.asarray(self.__mit_kd))
93
+ self.__mit_ctrl = CtrlUtil()
94
+ self.__gripper_ratio = 1.33 / 1.52
95
+ self._limits[0, -1] *= self.__gripper_ratio
96
+ self._limits[1, -1] *= self.__gripper_ratio
97
+ self._dofs = np.array([
98
+ len(self.__state_left_idx),
99
+ len(self.__state_right_idx),
100
+ ])
101
+ keyframe_id = mujoco.mj_name2id(
102
+ self.__model,
103
+ mujoco.mjtObj.mjOBJ_KEY,
104
+ "home",
105
+ )
106
+ self.__state_init = {
107
+ "qpos": self.__model.key_qpos[keyframe_id],
108
+ "qvel": np.zeros_like(self.__data.qvel),
109
+ "ctrl": np.zeros_like(self.__data.ctrl),
110
+ }
111
+ self.__data.qpos = self.__state_init["qpos"]
112
+ self.__data.qvel = self.__state_init["qvel"]
113
+ self.__data.ctrl = self.__state_init["ctrl"]
114
+ self.__states_trig_thresh = int(self.__sim_rate / states_rate)
115
+
116
+ # camera init
117
+ self.__img_trig_thresh = int(self.__sim_rate / img_rate)
118
+ self.__width, self.__height = (640, 480)
119
+ head_fovy_rad = self.__model.cam_fovy[0] * np.pi / 180.0
120
+ left_fovy_rad = self.__model.cam_fovy[1] * np.pi / 180.0
121
+ right_fovy_rad = self.__model.cam_fovy[2] * np.pi / 180.0
122
+ head_focal = 0.5 * self.__height / np.tan(head_fovy_rad / 2.0)
123
+ left_focal = 0.5 * self.__height / np.tan(left_fovy_rad / 2.0)
124
+ right_focal = 0.5 * self.__height / np.tan(right_fovy_rad / 2.0)
125
+ self._intri = np.array([
126
+ [head_focal, head_focal, self.__height / 2, self.__height / 2],
127
+ [left_focal, left_focal, self.__height / 2, self.__height / 2],
128
+ [right_focal, right_focal, self.__height / 2, self.__height / 2],
129
+ ])
130
+ self.__head_rgb, self.__head_depth = CAMERA_CONFIG.get(
131
+ self.__cam_type[0], (False, False))
132
+ self.__left_rgb, self.__left_depth = CAMERA_CONFIG.get(
133
+ self.__cam_type[1], (False, False))
134
+ self.__right_rgb, self.__right_depth = CAMERA_CONFIG.get(
135
+ self.__cam_type[2], (False, False))
136
+ self.__rgb_cam, self.__depth_cam = None, None
137
+ has_rgb = self.__left_rgb or self.__right_rgb or self.__head_rgb
138
+ has_depth = self.__left_depth or self.__right_depth or self.__head_depth
139
+ if has_rgb:
140
+ self.__rgb_cam = mujoco.Renderer(self.__model, self.__height,
141
+ self.__width)
142
+ if has_depth:
143
+ self.__depth_cam = mujoco.Renderer(self.__model, self.__height,
144
+ self.__width)
145
+ self.__depth_cam.enable_depth_rendering()
146
+
147
+ # viewer init
148
+ mujoco.mj_forward(self.__model, self.__data)
149
+ if not self.__headless:
150
+ self.__viewer = viewer.launch_passive(self.__model, self.__data)
151
+
152
+ # start work loop
153
+ self._working.set()
154
+
155
+ def __del__(self):
156
+ HexMujocoBase.__del__(self)
157
+
158
+ def reset(self) -> bool:
159
+ self.__data.qpos = self.__state_init["qpos"]
160
+ self.__data.qvel = self.__state_init["qvel"]
161
+ self.__data.ctrl = self.__state_init["ctrl"]
162
+ mujoco.mj_forward(self.__model, self.__data)
163
+ if not self.__headless:
164
+ self.__viewer.sync()
165
+ return True
166
+
167
+ def work_loop(self, hex_queues: list[deque | threading.Event]):
168
+ states_left_queue = hex_queues[0]
169
+ states_right_queue = hex_queues[1]
170
+ states_obj_queue = hex_queues[2]
171
+ cmds_left_queue = hex_queues[3]
172
+ cmds_right_queue = hex_queues[4]
173
+ head_rgb_queue = hex_queues[5]
174
+ head_depth_queue = hex_queues[6]
175
+ left_rgb_queue = hex_queues[7]
176
+ left_depth_queue = hex_queues[8]
177
+ right_rgb_queue = hex_queues[9]
178
+ right_depth_queue = hex_queues[10]
179
+ stop_event = hex_queues[11]
180
+
181
+ last_states_ts = {"s": 0, "ns": 0}
182
+ states_left_count = 0
183
+ states_right_count = 0
184
+ states_obj_count = 0
185
+ last_cmds_left_seq = -1
186
+ last_cmds_right_seq = -1
187
+ head_rgb_count = 0
188
+ head_depth_count = 0
189
+ left_rgb_count = 0
190
+ left_depth_count = 0
191
+ right_rgb_count = 0
192
+ right_depth_count = 0
193
+ cmds_left = None
194
+ cmds_right = None
195
+
196
+ rate = HexRate(self.__sim_rate)
197
+ states_trig_count = 0
198
+ img_trig_count = 0
199
+ self.__bias_ns = hex_ns_now() - self.__data.time * 1_000_000_000
200
+ init_ts = self.__mujoco_ts() if self.__sens_ts else hex_zmq_ts_now()
201
+ head_rgb_queue.append((init_ts, 0,
202
+ np.zeros((self.__height, self.__width, 3),
203
+ dtype=np.uint8)))
204
+ head_depth_queue.append((init_ts, 0,
205
+ np.zeros((self.__height, self.__width),
206
+ dtype=np.uint16)))
207
+ left_rgb_queue.append((init_ts, 0,
208
+ np.zeros((self.__height, self.__width, 3),
209
+ dtype=np.uint8)))
210
+ left_depth_queue.append((init_ts, 0,
211
+ np.zeros((self.__height, self.__width),
212
+ dtype=np.uint16)))
213
+ right_rgb_queue.append((init_ts, 0,
214
+ np.zeros((self.__height, self.__width, 3),
215
+ dtype=np.uint8)))
216
+ right_depth_queue.append((init_ts, 0,
217
+ np.zeros((self.__height, self.__width),
218
+ dtype=np.uint16)))
219
+ while self._working.is_set() and not stop_event.is_set():
220
+ states_trig_count += 1
221
+ if states_trig_count >= self.__states_trig_thresh:
222
+ states_trig_count = 0
223
+
224
+ # states
225
+ ts, states_left, states_right, states_obj = self.__get_states()
226
+ if states_left is not None:
227
+ if hex_zmq_ts_delta_ms(ts, last_states_ts) > 1e-6:
228
+ last_states_ts = ts
229
+ # states left
230
+ states_left_queue.append(
231
+ (ts, states_left_count, states_left))
232
+ states_left_count = (states_left_count +
233
+ 1) % self._max_seq_num
234
+ # states right
235
+ states_right_queue.append(
236
+ (ts, states_right_count, states_right))
237
+ states_right_count = (states_right_count +
238
+ 1) % self._max_seq_num
239
+ # states obj
240
+ states_obj_queue.append(
241
+ (ts, states_obj_count, states_obj))
242
+ states_obj_count = (states_obj_count +
243
+ 1) % self._max_seq_num
244
+
245
+ # cmds
246
+ cmds_left_pack = None
247
+ try:
248
+ cmds_left_pack = cmds_left_queue[
249
+ -1] if self._realtime_mode else cmds_left_queue.popleft(
250
+ )
251
+ except IndexError:
252
+ pass
253
+ if cmds_left_pack is not None:
254
+ ts, seq, cmds_left = cmds_left_pack
255
+ if seq != last_cmds_left_seq:
256
+ last_cmds_left_seq = seq
257
+ if hex_zmq_ts_delta_ms(hex_zmq_ts_now(), ts) < 200.0:
258
+ cmds_left = cmds_left.copy()
259
+ if cmds_left is not None:
260
+ self.__set_cmds(cmds_left, "left")
261
+
262
+ cmds_right_pack = None
263
+ try:
264
+ cmds_right_pack = cmds_right_queue[
265
+ -1] if self._realtime_mode else cmds_right_queue.popleft(
266
+ )
267
+ except IndexError:
268
+ pass
269
+ if cmds_right_pack is not None:
270
+ ts, seq, cmds_right_get = cmds_right_pack
271
+ if seq != last_cmds_right_seq:
272
+ last_cmds_right_seq = seq
273
+ if hex_zmq_ts_delta_ms(hex_zmq_ts_now(), ts) < 200.0:
274
+ cmds_right = cmds_right_get.copy()
275
+ if cmds_right is not None:
276
+ self.__set_cmds(cmds_right, "right")
277
+
278
+ img_trig_count += 1
279
+ if img_trig_count >= self.__img_trig_thresh:
280
+ img_trig_count = 0
281
+
282
+ # head rgb
283
+ if self.__head_rgb:
284
+ ts, rgb_img = self.__get_rgb("head_camera")
285
+ if rgb_img is not None:
286
+ head_rgb_queue.append((ts, head_rgb_count, rgb_img))
287
+ head_rgb_count = (head_rgb_count +
288
+ 1) % self._max_seq_num
289
+
290
+ # head depth
291
+ if self.__head_depth:
292
+ ts, depth_img = self.__get_depth("head_camera")
293
+ if depth_img is not None:
294
+ head_depth_queue.append(
295
+ (ts, head_depth_count, depth_img))
296
+ head_depth_count = (head_depth_count +
297
+ 1) % self._max_seq_num
298
+
299
+ # left rgb
300
+ if self.__left_rgb:
301
+ ts, rgb_img = self.__get_rgb("left_camera")
302
+ if rgb_img is not None:
303
+ left_rgb_queue.append((ts, left_rgb_count, rgb_img))
304
+ left_rgb_count = (left_rgb_count +
305
+ 1) % self._max_seq_num
306
+
307
+ # left depth
308
+ if self.__left_depth:
309
+ ts, depth_img = self.__get_depth("left_camera")
310
+ if depth_img is not None:
311
+ left_depth_queue.append(
312
+ (ts, left_depth_count, depth_img))
313
+ left_depth_count = (left_depth_count +
314
+ 1) % self._max_seq_num
315
+
316
+ # right rgb
317
+ if self.__right_rgb:
318
+ ts, rgb_img = self.__get_rgb("right_camera")
319
+ if rgb_img is not None:
320
+ right_rgb_queue.append((ts, right_rgb_count, rgb_img))
321
+ right_rgb_count = (right_rgb_count +
322
+ 1) % self._max_seq_num
323
+
324
+ # right depth
325
+ if self.__right_depth:
326
+ ts, depth_img = self.__get_depth("right_camera")
327
+ if depth_img is not None:
328
+ right_depth_queue.append(
329
+ (ts, right_depth_count, depth_img))
330
+ right_depth_count = (right_depth_count +
331
+ 1) % self._max_seq_num
332
+
333
+ # mujoco step
334
+ mujoco.mj_step(self.__model, self.__data)
335
+ if not self.__headless:
336
+ self.__viewer.sync()
337
+
338
+ # sleep
339
+ rate.sleep()
340
+
341
+ # close
342
+ self.close()
343
+
344
+ def __get_states(self):
345
+ pos = copy.deepcopy(self.__data.qpos)
346
+ vel = copy.deepcopy(self.__data.qvel)
347
+ eff = copy.deepcopy(self.__data.qfrc_actuator)
348
+ pos[self.__state_left_idx[-1]] = pos[
349
+ self.__state_left_idx[-1]] * self.__gripper_ratio
350
+ pos[self.__state_right_idx[-1]] = pos[
351
+ self.__state_right_idx[-1]] * self.__gripper_ratio
352
+ return self.__mujoco_ts() if self.__sens_ts else hex_zmq_ts_now(
353
+ ), np.array([
354
+ pos[self.__state_left_idx],
355
+ vel[self.__state_left_idx],
356
+ eff[self.__state_left_idx],
357
+ ]).T, np.array([
358
+ pos[self.__state_right_idx],
359
+ vel[self.__state_right_idx],
360
+ eff[self.__state_right_idx],
361
+ ]).T, self.__data.qpos[self.__obj_pose_idx].copy()
362
+
363
+ def __set_cmds(self, cmds: np.ndarray, robot_name: str):
364
+ ctrl_idx = []
365
+ state_idx = []
366
+ limit_idx = None
367
+ if robot_name == "left":
368
+ ctrl_idx = self.__ctrl_left_idx
369
+ if not self.__tau_ctrl:
370
+ state_idx = self.__state_left_idx
371
+ limit_idx = 0
372
+ elif robot_name == "right":
373
+ ctrl_idx = self.__ctrl_right_idx
374
+ if not self.__tau_ctrl:
375
+ state_idx = self.__state_right_idx
376
+ limit_idx = 1
377
+ else:
378
+ raise ValueError(f"unknown robot name: {robot_name}")
379
+ tau_cmds = None
380
+ if not self.__tau_ctrl:
381
+ cmd_pos = None
382
+ tar_vel = np.zeros(cmds.shape[0])
383
+ cmd_tor = np.zeros(cmds.shape[0])
384
+ cmd_kp = self.__mit_kp.copy()
385
+ cmd_kd = self.__mit_kd.copy()
386
+ if len(cmds.shape) == 1:
387
+ cmd_pos = cmds.copy()
388
+ elif len(cmds.shape) == 2:
389
+ if cmds.shape[1] == 2:
390
+ cmd_pos = cmds[:, 0].copy()
391
+ cmd_tor = cmds[:, 1].copy()
392
+ elif cmds.shape[1] == 5:
393
+ cmd_pos = cmds[:, 0].copy()
394
+ tar_vel = cmds[:, 1].copy()
395
+ cmd_tor = cmds[:, 2].copy()
396
+ cmd_kp = cmds[:, 3].copy()
397
+ cmd_kd = cmds[:, 4].copy()
398
+ else:
399
+ raise ValueError(
400
+ f"The shape of cmds is invalid: {cmds.shape}")
401
+ else:
402
+ raise ValueError(f"The shape of cmds is invalid: {cmds.shape}")
403
+ tar_pos = self._apply_pos_limits(
404
+ cmd_pos,
405
+ self._limits[limit_idx, :, 0],
406
+ self._limits[limit_idx, :, 1],
407
+ )
408
+ tar_pos[-1] /= self.__gripper_ratio
409
+ tau_cmds = self.__mit_ctrl(
410
+ cmd_kp,
411
+ cmd_kd,
412
+ tar_pos,
413
+ tar_vel,
414
+ self.__data.qpos[state_idx],
415
+ self.__data.qvel[state_idx],
416
+ cmd_tor,
417
+ )
418
+ else:
419
+ tau_cmds = cmds.copy()
420
+ self.__data.ctrl[ctrl_idx] = tau_cmds
421
+
422
+ def __get_rgb(self, camera_name: str):
423
+ self.__rgb_cam.update_scene(self.__data, camera_name)
424
+ rgb_img = self.__rgb_cam.render()
425
+ return self.__mujoco_ts() if self.__sens_ts else hex_zmq_ts_now(
426
+ ), cv2.cvtColor(rgb_img, cv2.COLOR_RGB2BGR)
427
+
428
+ def __get_depth(self, camera_name: str):
429
+ self.__depth_cam.update_scene(self.__data, camera_name)
430
+ depth_m = self.__depth_cam.render().astype(np.float32)
431
+ depth_img = np.clip(depth_m * 1000.0, 0, 65535).astype(np.uint16)
432
+ return self.__mujoco_ts() if self.__sens_ts else hex_zmq_ts_now(
433
+ ), depth_img
434
+
435
+ def __mujoco_ts(self):
436
+ mujoco_ts = self.__data.time * 1_000_000_000 + self.__bias_ns
437
+ return ns_to_hex_zmq_ts(mujoco_ts)
438
+
439
+ def close(self):
440
+ if not self._working.is_set():
441
+ return
442
+ self._working.clear()
443
+ if self.__rgb_cam is not None:
444
+ self.__rgb_cam.close()
445
+ if self.__depth_cam is not None:
446
+ self.__depth_cam.close()
447
+ if not self.__headless:
448
+ self.__viewer.close()
449
+ hex_log(HEX_LOG_LEVEL["info"], "HexMujocoE3Desktop closed")