hex-zmq-servers 0.3.16__py3-none-any.whl → 1.0.0__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.
@@ -15,7 +15,6 @@ from .zmq_base import HexZMQDummyClient, HexZMQDummyServer
15
15
 
16
16
  from .robot import HexRobotBase, HexRobotClientBase, HexRobotServerBase
17
17
  from .robot import HexRobotDummy, HexRobotDummyClient, HexRobotDummyServer
18
- from .robot import HexRobotGello, HexRobotGelloClient, HexRobotGelloServer
19
18
  from .robot import HexRobotHexarm, HexRobotHexarmClient, HexRobotHexarmServer, HEXARM_URDF_PATH_DICT
20
19
 
21
20
  from .cam import HexCamBase, HexCamClientBase, HexCamServerBase
@@ -28,7 +27,6 @@ file_dir = os.path.dirname(os.path.abspath(__file__))
28
27
  HEX_ZMQ_SERVERS_PATH_DICT = {
29
28
  "zmq_dummy": f"{file_dir}/zmq_base.py",
30
29
  "robot_dummy": f"{file_dir}/robot/dummy/robot_dummy_srv.py",
31
- "robot_gello": f"{file_dir}/robot/gello/robot_gello_srv.py",
32
30
  "robot_hexarm": f"{file_dir}/robot/hexarm/robot_hexarm_srv.py",
33
31
  "cam_dummy": f"{file_dir}/cam/dummy/cam_dummy_srv.py",
34
32
  "cam_rgb": f"{file_dir}/cam/rgb/cam_rgb_srv.py",
@@ -36,7 +34,6 @@ HEX_ZMQ_SERVERS_PATH_DICT = {
36
34
  HEX_ZMQ_CONFIGS_PATH_DICT = {
37
35
  "zmq_dummy": f"{file_dir}/config/zmq_dummy.json",
38
36
  "robot_dummy": f"{file_dir}/config/robot_dummy.json",
39
- "robot_gello": f"{file_dir}/config/robot_gello.json",
40
37
  "robot_hexarm": f"{file_dir}/config/robot_hexarm.json",
41
38
  "cam_dummy": f"{file_dir}/config/cam_dummy.json",
42
39
  "cam_rgb": f"{file_dir}/config/cam_rgb.json",
@@ -80,9 +77,6 @@ __all__ = [
80
77
  "HexRobotDummy",
81
78
  "HexRobotDummyClient",
82
79
  "HexRobotDummyServer",
83
- "HexRobotGello",
84
- "HexRobotGelloClient",
85
- "HexRobotGelloServer",
86
80
  "HexRobotHexarm",
87
81
  "HexRobotHexarmClient",
88
82
  "HexRobotHexarmServer",
@@ -104,6 +98,7 @@ from importlib.util import find_spec
104
98
 
105
99
  _HAS_BERXEL = find_spec("berxel_py_wrapper") is not None
106
100
  _HAS_REALSENSE = find_spec("pyrealsense2") is not None
101
+ _HAS_DYNAMIXEL = find_spec("dynamixel-sdk") is not None
107
102
  _HAS_MUJOCO = find_spec("mujoco") is not None
108
103
 
109
104
  # Optional: berxel
@@ -140,6 +135,23 @@ if _HAS_REALSENSE:
140
135
  "HexCamRealsenseServer",
141
136
  ])
142
137
 
138
+ # Optional: dynamixel
139
+ if _HAS_DYNAMIXEL:
140
+ from .robot import HexRobotGello, HexRobotGelloClient, HexRobotGelloServer
141
+ HEX_ZMQ_SERVERS_PATH_DICT.update({
142
+ "robot_gello":
143
+ f"{file_dir}/robot/gello/robot_gello_srv.py",
144
+ })
145
+ HEX_ZMQ_CONFIGS_PATH_DICT.update({
146
+ "robot_gello":
147
+ f"{file_dir}/config/robot_gello.json",
148
+ })
149
+ __all__.extend([
150
+ "HexRobotGello",
151
+ "HexRobotGelloClient",
152
+ "HexRobotGelloServer",
153
+ ])
154
+
143
155
  # Optional: mujoco
144
156
  if _HAS_MUJOCO:
145
157
  from .mujoco import HexMujocoBase, HexMujocoClientBase, HexMujocoServerBase
@@ -47,8 +47,8 @@ class HexCamBerxel(HexCamBase):
47
47
 
48
48
  # variables
49
49
  # berxel variables
50
- self.__context = None
51
- self.__device = None
50
+ self.__context: BerxelHawkContext | None = None
51
+ self.__device: BerxelHawkDevice | None = None
52
52
  # camera variables
53
53
  self.__intri = np.zeros(4)
54
54
 
@@ -214,7 +214,15 @@ class HexCamBerxel(HexCamBase):
214
214
  return True
215
215
 
216
216
  def __start_stream(self):
217
- self.__device.setColorExposureGain(self.__exposure, self.__gain)
217
+ if self.__serial_number.startswith('P008'):
218
+ self.__device.setSonixAEStatus(False)
219
+ self.__device.setSonixExposureTime(int(self.__exposure // 100))
220
+ else:
221
+ self.__device.setColorExposureGain(self.__exposure, self.__gain)
222
+ self.__device.setDepthElectricCurrent(700)
223
+ self.__device.setDepthAE(False)
224
+ self.__device.setDepthExposure(43)
225
+ self.__device.setDepthGain(1)
218
226
  self.__device.setRegistrationEnable(True)
219
227
  self.__device.setFrameSync(True)
220
228
  while self.__device.setSystemClock() != 0:
@@ -13,7 +13,6 @@
13
13
  "device_port": 8439,
14
14
  "control_hz": 1000,
15
15
  "arm_type": "archer_l6y",
16
- "use_gripper": true,
17
16
  "mit_kp": [
18
17
  200.0,
19
18
  200.0,
@@ -21,7 +20,13 @@
21
20
  75.0,
22
21
  15.0,
23
22
  15.0,
24
- 20.0
23
+ 20.0,
24
+ 0.0,
25
+ 0.0,
26
+ 0.0,
27
+ 0.0,
28
+ 0.0,
29
+ 0.0
25
30
  ],
26
31
  "mit_kd": [
27
32
  12.5,
@@ -30,7 +35,13 @@
30
35
  6.0,
31
36
  0.31,
32
37
  0.31,
33
- 1.0
38
+ 1.0,
39
+ 0.0,
40
+ 0.0,
41
+ 0.0,
42
+ 0.0,
43
+ 0.0,
44
+ 0.0
34
45
  ],
35
46
  "sens_ts": true
36
47
  }
@@ -76,21 +76,36 @@ class HexMujocoArcherY6(HexMujocoBase):
76
76
  mujoco.mj_resetData(self.__model, self.__data)
77
77
 
78
78
  # state init
79
- self.__state_robot_idx = [0, 1, 2, 3, 4, 5, 6]
80
- self.__state_obj_idx = [12, 13, 14, 15, 16, 17, 18]
81
- self.__ctrl_robot_idx = [0, 1, 2, 3, 4, 5, 6]
82
- self.__ctrl_obj_idx = [0, 1, 2, 3, 4, 5, 6]
83
- self._limits = np.stack(
84
- [self.__model.jnt_range[self.__state_robot_idx, :]],
85
- axis=0,
86
- )
79
+ self.__state_idx = {
80
+ "robot_arm": ([0, 1, 2, 3, 4, 5]),
81
+ "robot_gripper": [6],
82
+ "obj": [12, 13, 14, 15, 16, 17, 18],
83
+ }
84
+ self.__ctrl_idx = {
85
+ "robot_arm": [0, 1, 2, 3, 4, 5],
86
+ "robot_gripper": [6],
87
+ }
88
+ self.__limit_idx = {
89
+ "robot_arm":
90
+ np.arange(len(self.__state_idx["robot_arm"])).tolist(),
91
+ "robot_gripper":
92
+ (np.arange(len(self.__state_idx["robot_gripper"])) +
93
+ len(self.__state_idx["robot_arm"])).tolist(),
94
+ }
95
+ print(f"self.__limit_idx: {self.__limit_idx}")
96
+ self._limits = self.__model.jnt_range[np.concatenate(
97
+ [self.__state_idx["robot_arm"], self.
98
+ __state_idx["robot_gripper"]]), :].copy().reshape(-1, 1, 2)
87
99
  if not self.__tau_ctrl:
88
100
  self.__mit_kp = np.ascontiguousarray(np.asarray(self.__mit_kp))
89
101
  self.__mit_kd = np.ascontiguousarray(np.asarray(self.__mit_kd))
90
102
  self.__mit_ctrl = CtrlUtil()
91
103
  self.__gripper_ratio = 1.33 / 1.52
92
104
  self._limits[0, -1] *= self.__gripper_ratio
93
- self._dofs = np.array([len(self.__state_robot_idx)])
105
+ self._dofs = np.array([
106
+ len(self.__state_idx["robot_arm"]),
107
+ len(self.__state_idx["robot_gripper"])
108
+ ])
94
109
  keyframe_id = mujoco.mj_name2id(
95
110
  self.__model,
96
111
  mujoco.mjtObj.mjOBJ_KEY,
@@ -242,16 +257,25 @@ class HexMujocoArcherY6(HexMujocoBase):
242
257
  pos = copy.deepcopy(self.__data.qpos)
243
258
  vel = copy.deepcopy(self.__data.qvel)
244
259
  eff = copy.deepcopy(self.__data.qfrc_actuator)
245
- pos[self.__state_robot_idx[-1]] = pos[
246
- self.__state_robot_idx[-1]] * self.__gripper_ratio
260
+ pos[self.__state_idx["robot_gripper"]] = pos[
261
+ self.__state_idx["robot_gripper"]] * self.__gripper_ratio
247
262
  return self.__mujoco_ts() if self.__sens_ts else hex_zmq_ts_now(
248
263
  ), np.array([
249
- pos[self.__state_robot_idx],
250
- vel[self.__state_robot_idx],
251
- eff[self.__state_robot_idx],
252
- ]).T, self.__data.qpos[self.__state_obj_idx].copy()
264
+ pos[self.__state_idx["robot_arm"] +
265
+ self.__state_idx["robot_gripper"]],
266
+ vel[self.__state_idx["robot_arm"] +
267
+ self.__state_idx["robot_gripper"]],
268
+ eff[self.__state_idx["robot_arm"] +
269
+ self.__state_idx["robot_gripper"]],
270
+ ]).T, self.__data.qpos[self.__state_idx["obj"]].copy()
253
271
 
254
272
  def __set_cmds(self, cmds: np.ndarray):
273
+ state_idx = self.__state_idx["robot_arm"] + self.__state_idx[
274
+ "robot_gripper"]
275
+ ctrl_idx = self.__ctrl_idx["robot_arm"] + self.__ctrl_idx[
276
+ "robot_gripper"]
277
+ limit_idx = self.__limit_idx["robot_arm"] + self.__limit_idx[
278
+ "robot_gripper"]
255
279
  tau_cmds = None
256
280
  if not self.__tau_ctrl:
257
281
  cmd_pos = None
@@ -278,8 +302,8 @@ class HexMujocoArcherY6(HexMujocoBase):
278
302
  raise ValueError(f"The shape of cmds is invalid: {cmds.shape}")
279
303
  tar_pos = self._apply_pos_limits(
280
304
  cmd_pos,
281
- self._limits[0, :, 0],
282
- self._limits[0, :, 1],
305
+ self._limits[limit_idx, 0, 0],
306
+ self._limits[limit_idx, 0, 1],
283
307
  )
284
308
  tar_pos[-1] /= self.__gripper_ratio
285
309
  tau_cmds = self.__mit_ctrl(
@@ -287,13 +311,13 @@ class HexMujocoArcherY6(HexMujocoBase):
287
311
  cmd_kd,
288
312
  tar_pos,
289
313
  tar_vel,
290
- self.__data.qpos[self.__state_robot_idx],
291
- self.__data.qvel[self.__state_robot_idx],
314
+ self.__data.qpos[state_idx],
315
+ self.__data.qvel[state_idx],
292
316
  cmd_tor,
293
317
  )
294
318
  else:
295
319
  tau_cmds = cmds.copy()
296
- self.__data.ctrl[self.__ctrl_robot_idx] = tau_cmds
320
+ self.__data.ctrl[ctrl_idx] = tau_cmds
297
321
 
298
322
  def __get_rgb(self):
299
323
  self.__rgb_cam.update_scene(self.__data, "end_camera")
@@ -77,18 +77,37 @@ class HexMujocoE3Desktop(HexMujocoBase):
77
77
  mujoco.mj_resetData(self.__model, self.__data)
78
78
 
79
79
  # state init
80
- self.__state_left_idx = [0, 1, 2, 3, 4, 5, 6]
81
- self.__state_right_idx = [12, 13, 14, 15, 16, 17, 18]
82
- self.__obj_pose_idx = [24, 25, 26, 27, 28, 29, 30]
83
- self.__ctrl_left_idx = [0, 1, 2, 3, 4, 5, 6]
84
- self.__ctrl_right_idx = [7, 8, 9, 10, 11, 12, 13]
85
- self._limits = np.stack(
86
- [
87
- self.__model.jnt_range[self.__state_left_idx, :],
88
- self.__model.jnt_range[self.__state_right_idx, :]
89
- ],
90
- axis=0,
91
- )
80
+ self.__state_idx = {
81
+ "left_arm": [0, 1, 2, 3, 4, 5],
82
+ "left_gripper": [6],
83
+ "right_arm": [12, 13, 14, 15, 16, 17],
84
+ "right_gripper": [18],
85
+ "obj": [24, 25, 26, 27, 28, 29, 30],
86
+ }
87
+ self.__ctrl_idx = {
88
+ "left_arm": [0, 1, 2, 3, 4, 5],
89
+ "left_gripper": [6],
90
+ "right_arm": [7, 8, 9, 10, 11, 12],
91
+ "right_gripper": [13],
92
+ }
93
+ self.__limit_idx = {
94
+ "left_arm":
95
+ np.arange(len(self.__state_idx["left_arm"])).tolist(),
96
+ "left_gripper": (np.arange(len(self.__state_idx["left_gripper"])) +
97
+ len(self.__state_idx["left_arm"])).tolist(),
98
+ "right_arm": (np.arange(len(self.__state_idx["right_arm"])) +
99
+ len(self.__state_idx["left_arm"]) +
100
+ len(self.__state_idx["left_gripper"])).tolist(),
101
+ "right_gripper":
102
+ (np.arange(len(self.__state_idx["right_gripper"])) +
103
+ len(self.__state_idx["left_arm"]) +
104
+ len(self.__state_idx["left_gripper"]) +
105
+ len(self.__state_idx["right_arm"])).tolist(),
106
+ }
107
+ self._limits = self.__model.jnt_range[np.concatenate([
108
+ self.__state_idx["left_arm"], self.__state_idx["left_gripper"],
109
+ self.__state_idx["right_arm"], self.__state_idx["right_gripper"]
110
+ ]), :].copy().reshape(-1, 1, 2)
92
111
  if not self.__tau_ctrl:
93
112
  self.__mit_kp = np.ascontiguousarray(np.asarray(self.__mit_kp))
94
113
  self.__mit_kd = np.ascontiguousarray(np.asarray(self.__mit_kd))
@@ -97,8 +116,10 @@ class HexMujocoE3Desktop(HexMujocoBase):
97
116
  self._limits[0, -1] *= self.__gripper_ratio
98
117
  self._limits[1, -1] *= self.__gripper_ratio
99
118
  self._dofs = np.array([
100
- len(self.__state_left_idx),
101
- len(self.__state_right_idx),
119
+ len(self.__state_idx["left_arm"]),
120
+ len(self.__state_idx["left_gripper"]),
121
+ len(self.__state_idx["right_arm"]),
122
+ len(self.__state_idx["right_gripper"]),
102
123
  ])
103
124
  keyframe_id = mujoco.mj_name2id(
104
125
  self.__model,
@@ -347,35 +368,47 @@ class HexMujocoE3Desktop(HexMujocoBase):
347
368
  pos = copy.deepcopy(self.__data.qpos)
348
369
  vel = copy.deepcopy(self.__data.qvel)
349
370
  eff = copy.deepcopy(self.__data.qfrc_actuator)
350
- pos[self.__state_left_idx[-1]] = pos[
351
- self.__state_left_idx[-1]] * self.__gripper_ratio
352
- pos[self.__state_right_idx[-1]] = pos[
353
- self.__state_right_idx[-1]] * self.__gripper_ratio
371
+ pos[self.__state_idx["left_gripper"]] = pos[
372
+ self.__state_idx["left_gripper"]] * self.__gripper_ratio
373
+ pos[self.__state_idx["right_gripper"]] = pos[
374
+ self.__state_idx["right_gripper"]] * self.__gripper_ratio
354
375
  return self.__mujoco_ts() if self.__sens_ts else hex_zmq_ts_now(
355
376
  ), np.array([
356
- pos[self.__state_left_idx],
357
- vel[self.__state_left_idx],
358
- eff[self.__state_left_idx],
377
+ pos[self.__state_idx["left_arm"] +
378
+ self.__state_idx["left_gripper"]],
379
+ vel[self.__state_idx["left_arm"] +
380
+ self.__state_idx["left_gripper"]],
381
+ eff[self.__state_idx["left_arm"] +
382
+ self.__state_idx["left_gripper"]],
359
383
  ]).T, np.array([
360
- pos[self.__state_right_idx],
361
- vel[self.__state_right_idx],
362
- eff[self.__state_right_idx],
363
- ]).T, self.__data.qpos[self.__obj_pose_idx].copy()
384
+ pos[self.__state_idx["right_arm"] +
385
+ self.__state_idx["right_gripper"]],
386
+ vel[self.__state_idx["right_arm"] +
387
+ self.__state_idx["right_gripper"]],
388
+ eff[self.__state_idx["right_arm"] +
389
+ self.__state_idx["right_gripper"]],
390
+ ]).T, self.__data.qpos[self.__state_idx["obj"]].copy()
364
391
 
365
392
  def __set_cmds(self, cmds: np.ndarray, robot_name: str):
366
- ctrl_idx = []
367
- state_idx = []
393
+ state_idx = None
394
+ ctrl_idx = None
368
395
  limit_idx = None
369
396
  if robot_name == "left":
370
- ctrl_idx = self.__ctrl_left_idx
397
+ ctrl_idx = self.__ctrl_idx["left_arm"] + self.__ctrl_idx[
398
+ "left_gripper"]
371
399
  if not self.__tau_ctrl:
372
- state_idx = self.__state_left_idx
373
- limit_idx = 0
400
+ state_idx = self.__state_idx["left_arm"] + self.__state_idx[
401
+ "left_gripper"]
402
+ limit_idx = self.__limit_idx["left_arm"] + self.__limit_idx[
403
+ "left_gripper"]
374
404
  elif robot_name == "right":
375
- ctrl_idx = self.__ctrl_right_idx
405
+ ctrl_idx = self.__ctrl_idx["right_arm"] + self.__ctrl_idx[
406
+ "right_gripper"]
376
407
  if not self.__tau_ctrl:
377
- state_idx = self.__state_right_idx
378
- limit_idx = 1
408
+ state_idx = self.__state_idx["right_arm"] + self.__state_idx[
409
+ "right_gripper"]
410
+ limit_idx = self.__limit_idx["right_arm"] + self.__limit_idx[
411
+ "right_gripper"]
379
412
  else:
380
413
  raise ValueError(f"unknown robot name: {robot_name}")
381
414
  tau_cmds = None
@@ -404,8 +437,8 @@ class HexMujocoE3Desktop(HexMujocoBase):
404
437
  raise ValueError(f"The shape of cmds is invalid: {cmds.shape}")
405
438
  tar_pos = self._apply_pos_limits(
406
439
  cmd_pos,
407
- self._limits[limit_idx, :, 0],
408
- self._limits[limit_idx, :, 1],
440
+ self._limits[limit_idx, 0, 0],
441
+ self._limits[limit_idx, 0, 1],
409
442
  )
410
443
  tar_pos[-1] /= self.__gripper_ratio
411
444
  tau_cmds = self.__mit_ctrl(
@@ -8,7 +8,6 @@
8
8
 
9
9
  from .robot_base import HexRobotBase, HexRobotClientBase, HexRobotServerBase
10
10
  from .dummy import HexRobotDummy, HexRobotDummyClient, HexRobotDummyServer
11
- from .gello import HexRobotGello, HexRobotGelloClient, HexRobotGelloServer
12
11
  from .hexarm import HexRobotHexarm, HexRobotHexarmClient, HexRobotHexarmServer, HEXARM_URDF_PATH_DICT
13
12
 
14
13
  __all__ = [
@@ -25,13 +24,22 @@ __all__ = [
25
24
  "HexRobotDummyClient",
26
25
  "HexRobotDummyServer",
27
26
 
28
- # gello
29
- "HexRobotGello",
30
- "HexRobotGelloClient",
31
- "HexRobotGelloServer",
32
-
33
27
  # hexarm
34
28
  "HexRobotHexarm",
35
29
  "HexRobotHexarmClient",
36
30
  "HexRobotHexarmServer",
37
31
  ]
32
+
33
+ # Check optional dependencies availability
34
+ from importlib.util import find_spec
35
+
36
+ _HAS_DYNAMIXEL = find_spec("dynamixel-sdk") is not None
37
+
38
+ # Optional: dynamixel
39
+ if _HAS_DYNAMIXEL:
40
+ from .gello import HexRobotGello, HexRobotGelloClient, HexRobotGelloServer
41
+ __all__.extend([
42
+ "HexRobotGello",
43
+ "HexRobotGelloClient",
44
+ "HexRobotGelloServer",
45
+ ])
@@ -18,7 +18,7 @@ from ...zmq_base import (
18
18
  HexRate,
19
19
  )
20
20
  from ...hex_launch import hex_log, HEX_LOG_LEVEL
21
- from hex_device import HexDeviceApi, MotorBase
21
+ from hex_device import HexDeviceApi, Arm, Hands
22
22
  from hex_device.motor_base import CommandType
23
23
 
24
24
  ROBOT_CONFIG = {
@@ -26,7 +26,6 @@ ROBOT_CONFIG = {
26
26
  "device_port": 8439,
27
27
  "control_hz": 250,
28
28
  "arm_type": "archer_y6",
29
- "use_gripper": True,
30
29
  "mit_kp": [200.0, 200.0, 200.0, 75.0, 15.0, 15.0, 20.0],
31
30
  "mit_kd": [12.5, 12.5, 12.5, 6.0, 0.31, 0.31, 1.0],
32
31
  "sens_ts": True,
@@ -37,6 +36,7 @@ HEX_DEVICE_TYPE_DICT = {
37
36
  "archer_d6y": 16,
38
37
  "archer_l6y": 17,
39
38
  "firefly_y6": 27,
39
+ "hello": 26,
40
40
  }
41
41
 
42
42
 
@@ -54,7 +54,6 @@ class HexRobotHexarm(HexRobotBase):
54
54
  device_port = robot_config["device_port"]
55
55
  control_hz = robot_config["control_hz"]
56
56
  arm_type = HEX_DEVICE_TYPE_DICT[robot_config["arm_type"]]
57
- use_gripper = robot_config["use_gripper"]
58
57
  self.__sens_ts = robot_config["sens_ts"]
59
58
  except KeyError as ke:
60
59
  missing_key = ke.args[0]
@@ -73,8 +72,8 @@ class HexRobotHexarm(HexRobotBase):
73
72
  # variables
74
73
  # hex_arm variables
75
74
  self.__hex_api: HexDeviceApi | None = None
76
- self.__arm_archer: MotorBase | None = None
77
- self.__gripper: MotorBase | None = None
75
+ self.__arm: Arm | None = None
76
+ self.__gripper: Hands | None = None
78
77
 
79
78
  # buffer
80
79
  self.__arm_state_buffer: dict | None = None
@@ -90,40 +89,46 @@ class HexRobotHexarm(HexRobotBase):
90
89
  while self.__hex_api.find_device_by_robot_type(arm_type) is None:
91
90
  print("\033[33mArm not found\033[0m")
92
91
  time.sleep(1)
93
- self.__arm_archer = self.__hex_api.find_device_by_robot_type(arm_type)
94
- self.__arm_archer.start()
95
- self.__arm_dofs = len(self.__arm_archer)
96
- self._limits = self.__arm_archer.get_joint_limits()
92
+ self.__arm = self.__hex_api.find_device_by_robot_type(arm_type)
93
+ self.__arm.start()
97
94
 
98
95
  # try to open gripper
99
- self.__gripper_dofs = 0
100
- self.__gripper = None
101
- if use_gripper:
102
- self.__gripper = self.__hex_api.find_optional_device_by_id(1)
103
- if self.__gripper is not None:
104
- self.__gripper_dofs = len(self.__gripper)
105
- self._limits += [self.__gripper.get_joint_limits()]
106
- else:
107
- print("\033[33mGripper not found\033[0m")
96
+ self.__gripper = self.__hex_api.find_optional_device_by_id(1)
97
+ if self.__gripper is None:
98
+ print("\033[33mGripper not found\033[0m")
99
+
100
+ # variables init
101
+ arm_dofs = len(self.__arm)
102
+ self._dofs = [arm_dofs]
103
+ self._limits = np.array(self.__arm.get_joint_limits()).reshape(-1, 3, 2)
104
+ self.__motor_idx = {"robot_arm": np.arange(arm_dofs).tolist()}
105
+ if self.__gripper is not None:
106
+ gripper_dofs = len(self.__gripper)
107
+ self._dofs.append(gripper_dofs)
108
+ gripper_limits = np.array(self.__gripper.get_joint_limits()).reshape(-1, 3, 2)
109
+ self._limits = np.concatenate([self._limits, gripper_limits], axis=0)
110
+ self.__motor_idx["robot_gripper"] = (np.arange(gripper_dofs) +
111
+ arm_dofs).tolist()
108
112
 
109
113
  # modify variables
110
- self._dofs = [self.__arm_dofs + self.__gripper_dofs]
114
+ self._dofs = np.array(self._dofs)
115
+ self._dofs_sum = self._dofs.sum()
111
116
  self._limits = np.ascontiguousarray(np.asarray(self._limits)).reshape(
112
- self._dofs[0], 3, 2)
117
+ self._dofs_sum, 3, 2)
113
118
  self.__mit_kp = np.ascontiguousarray(np.asarray(self.__mit_kp))
114
119
  self.__mit_kd = np.ascontiguousarray(np.asarray(self.__mit_kd))
115
- if self.__mit_kp.shape[0] < self._dofs[0] or self.__mit_kd.shape[
116
- 0] < self._dofs[0]:
120
+ if self.__mit_kp.shape[0] < self._dofs_sum or self.__mit_kd.shape[
121
+ 0] < self._dofs_sum:
117
122
  raise ValueError(
118
123
  "The length of mit_kp and mit_kd must be greater than or equal to the number of motors"
119
124
  )
120
- elif self.__mit_kp.shape[0] > self._dofs[0] or self.__mit_kd.shape[
121
- 0] > self._dofs[0]:
125
+ elif self.__mit_kp.shape[0] > self._dofs_sum or self.__mit_kd.shape[
126
+ 0] > self._dofs_sum:
122
127
  print(
123
128
  f"\033[33mThe length of mit_kp and mit_kd is greater than the number of motors\033[0m"
124
129
  )
125
- self.__mit_kp = self.__mit_kp[:self._dofs[0]]
126
- self.__mit_kd = self.__mit_kd[:self._dofs[0]]
130
+ self.__mit_kp = self.__mit_kp[:self._dofs_sum]
131
+ self.__mit_kd = self.__mit_kd[:self._dofs_sum]
127
132
 
128
133
  # start work loop
129
134
  self._working.set()
@@ -167,13 +172,12 @@ class HexRobotHexarm(HexRobotBase):
167
172
  self.close()
168
173
 
169
174
  def __get_states(self) -> tuple[np.ndarray | None, dict | None]:
170
- if self.__arm_archer is None:
175
+ if self.__arm is None:
171
176
  return None, None
172
177
 
173
178
  # (arm_dofs, 3) # pos vel eff
174
179
  if self.__arm_state_buffer is None:
175
- self.__arm_state_buffer = self.__arm_archer.get_simple_motor_status(
176
- )
180
+ self.__arm_state_buffer = self.__arm.get_simple_motor_status()
177
181
 
178
182
  # (gripper_dofs, 3) # pos vel eff
179
183
  if self.__gripper is not None and self.__gripper_state_buffer is None:
@@ -220,24 +224,24 @@ class HexRobotHexarm(HexRobotBase):
220
224
  # [[pos_0, tor_0], ..., [pos_n, tor_n]]
221
225
  # cmds: (n, 5)
222
226
  # [[pos_0, vel_0, tor_0, kp_0, kd_0], ..., [pos_n, vel_n, tor_n, kp_n, kd_n]]
223
- if self.__arm_archer is None:
227
+ if self.__arm is None:
224
228
  print("\033[91mArm not found\033[0m")
225
229
  return False
226
230
 
227
- if cmds.shape[0] < self._dofs[0]:
231
+ if cmds.shape[0] < self._dofs_sum:
228
232
  print(
229
233
  "\033[91mThe length of joint_angles must be greater than or equal to the number of motors\033[0m"
230
234
  )
231
235
  return False
232
- elif cmds.shape[0] > self._dofs[0]:
236
+ elif cmds.shape[0] > self._dofs_sum:
233
237
  print(
234
238
  f"\033[33mThe length of joint_angles is greater than the number of motors\033[0m"
235
239
  )
236
- cmds = cmds[:self._dofs[0]]
240
+ cmds = cmds[:self._dofs_sum]
237
241
 
238
242
  cmd_pos = None
239
- tar_vel = np.zeros(self._dofs[0])
240
- cmd_tor = np.zeros(self._dofs[0])
243
+ tar_vel = np.zeros(self._dofs_sum)
244
+ cmd_tor = np.zeros(self._dofs_sum)
241
245
  cmd_kp = self.__mit_kp.copy()
242
246
  cmd_kd = self.__mit_kd.copy()
243
247
  if len(cmds.shape) == 1:
@@ -263,25 +267,25 @@ class HexRobotHexarm(HexRobotBase):
263
267
  )
264
268
 
265
269
  # arm
266
- mit_cmd = self.__arm_archer.construct_mit_command(
267
- tar_pos[:self.__arm_dofs],
268
- tar_vel[:self.__arm_dofs],
269
- cmd_tor[:self.__arm_dofs],
270
- cmd_kp[:self.__arm_dofs],
271
- cmd_kd[:self.__arm_dofs],
270
+ arm_cmd = self.__arm.construct_mit_command(
271
+ tar_pos[self.__motor_idx["robot_arm"]],
272
+ tar_vel[self.__motor_idx["robot_arm"]],
273
+ cmd_tor[self.__motor_idx["robot_arm"]],
274
+ cmd_kp[self.__motor_idx["robot_arm"]],
275
+ cmd_kd[self.__motor_idx["robot_arm"]],
272
276
  )
273
- self.__arm_archer.motor_command(CommandType.MIT, mit_cmd)
277
+ self.__arm.motor_command(CommandType.MIT, arm_cmd)
274
278
 
275
279
  # gripper
276
280
  if self.__gripper is not None:
277
- mit_cmd = self.__gripper.construct_mit_command(
278
- tar_pos[self.__arm_dofs:],
279
- tar_vel[self.__arm_dofs:],
280
- cmd_tor[self.__arm_dofs:],
281
- cmd_kp[self.__arm_dofs:],
282
- cmd_kd[self.__arm_dofs:],
281
+ gripper_cmd = self.__gripper.construct_mit_command(
282
+ tar_pos[self.__motor_idx["robot_gripper"]],
283
+ tar_vel[self.__motor_idx["robot_gripper"]],
284
+ cmd_tor[self.__motor_idx["robot_gripper"]],
285
+ cmd_kp[self.__motor_idx["robot_gripper"]],
286
+ cmd_kd[self.__motor_idx["robot_gripper"]],
283
287
  )
284
- self.__gripper.motor_command(CommandType.MIT, mit_cmd)
288
+ self.__gripper.motor_command(CommandType.MIT, gripper_cmd)
285
289
 
286
290
  return True
287
291
 
@@ -289,6 +293,6 @@ class HexRobotHexarm(HexRobotBase):
289
293
  if not self._working.is_set():
290
294
  return
291
295
  self._working.clear()
292
- self.__arm_archer.stop()
296
+ self.__arm.stop()
293
297
  self.__hex_api.close()
294
298
  hex_log(HEX_LOG_LEVEL["info"], "HexRobotHexarm closed")
@@ -36,9 +36,8 @@ ROBOT_CONFIG = {
36
36
  "device_port": 8439,
37
37
  "control_hz": 250,
38
38
  "arm_type": "archer_l6y",
39
- "use_gripper": True,
40
- "mit_kp": [200.0, 200.0, 200.0, 75.0, 15.0, 15.0, 0.0],
41
- "mit_kd": [12.5, 12.5, 12.5, 6.0, 0.31, 0.31, 0.0],
39
+ "mit_kp": [200.0, 200.0, 200.0, 75.0, 15.0, 15.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
40
+ "mit_kd": [12.5, 12.5, 12.5, 6.0, 0.31, 0.31, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
42
41
  "sens_ts": True,
43
42
  }
44
43
 
@@ -500,11 +500,16 @@ class HexZMQDummyClient(HexZMQClientBase):
500
500
  net_config: dict = NET_CONFIG,
501
501
  ):
502
502
  HexZMQClientBase.__init__(self, net_config)
503
-
503
+ self._wait_for_working()
504
+
504
505
  def single_test(self):
505
506
  resp_hdr, resp_buf = self.request({"cmd": "test"})
506
- print(f"resp_hdr: {resp_hdr}")
507
- print(f"resp_buf: {resp_buf}")
507
+ return resp_hdr, resp_buf
508
+
509
+ def _recv_loop(self):
510
+ rate = HexRate(500)
511
+ while self._recv_flag:
512
+ rate.sleep()
508
513
 
509
514
 
510
515
  class HexZMQDummyServer(HexZMQServerBase):
@@ -524,6 +529,8 @@ class HexZMQDummyServer(HexZMQServerBase):
524
529
  self.close()
525
530
 
526
531
  def _process_request(self, recv_hdr: dict, recv_buf: np.ndarray):
532
+ if recv_hdr["cmd"] == "is_working":
533
+ return self.no_ts_hdr(recv_hdr, True), None
527
534
  if recv_hdr["cmd"] == "test":
528
535
  print("test received")
529
536
  print(f"recv_hdr: {recv_hdr}")
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.4
2
+ Name: hex_zmq_servers
3
+ Version: 1.0.0
4
+ Summary: HEXFELLOW ZMQ Servers
5
+ Author-email: Dong Zhaorui <joray.dong@hexfellow.com>
6
+ Maintainer-email: jecjune <zejun.chen@hexfellow.com>, Dong Zhaorui <joray.dong@hexfellow.com>
7
+ License-Expression: Apache-2.0
8
+ Project-URL: Homepage, https://github.com/hexfellow/hex_zmq_servers
9
+ Project-URL: Repository, https://github.com/hexfellow/hex_zmq_servers.git
10
+ Project-URL: Bug Tracker, https://github.com/hexfellow/hex_zmq_servers/issues
11
+ Project-URL: Documentation, https://github.com/hexfellow/hex_zmq_servers/wiki
12
+ Keywords: hex_zmq_servers
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Operating System :: POSIX :: Linux
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: pyzmq>=27.0.1
26
+ Requires-Dist: hex_device<1.4.0,>=1.3.14
27
+ Requires-Dist: hex_robo_utils<0.3.0,>=0.2.0
28
+ Requires-Dist: opencv-python>=4.2
29
+ Provides-Extra: berxel
30
+ Requires-Dist: berxel_py_wrapper>=2.0.182; extra == "berxel"
31
+ Provides-Extra: realsense
32
+ Requires-Dist: pyrealsense2>=2.56.5.9235; extra == "realsense"
33
+ Provides-Extra: dynamixel
34
+ Requires-Dist: dynamixel-sdk==3.8.4; extra == "dynamixel"
35
+ Provides-Extra: mujoco
36
+ Requires-Dist: mujoco>=3.3.3; extra == "mujoco"
37
+ Provides-Extra: all
38
+ Requires-Dist: berxel_py_wrapper>=2.0.182; extra == "all"
39
+ Requires-Dist: pyrealsense2>=2.56.5.9235; extra == "all"
40
+ Requires-Dist: dynamixel-sdk==3.8.4; extra == "all"
41
+ Requires-Dist: mujoco>=3.3.3; extra == "all"
42
+ Dynamic: license-file
43
+
44
+ <h1 align="center">HEXFELLOW ZMQ SERVERS</h1>
45
+
46
+ <p align="center">
47
+ <a href="https://github.com/hexfellow/hex_zmq_servers/stargazers">
48
+ <img src="https://img.shields.io/github/stars/hexfellow/hex_zmq_servers?style=flat-square&logo=github" />
49
+ </a>
50
+ <a href="https://github.com/hexfellow/hex_zmq_servers/forks">
51
+ <img src="https://img.shields.io/github/forks/hexfellow/hex_zmq_servers?style=flat-square&logo=github" />
52
+ </a>
53
+ <a href="https://doi.org/10.5281/zenodo.18309954">
54
+ <img src="https://zenodo.org/badge/1088506315.svg" alt="DOI">
55
+ </a>
56
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
57
+ <a href="https://github.com/hexfellow/hex_zmq_servers/issues">
58
+ <img src="https://img.shields.io/github/issues/hexfellow/hex_zmq_servers?style=flat-square&logo=github" />
59
+ </a>
60
+ </p>
61
+
62
+ ---
63
+
64
+ # 📖 Overview
65
+
66
+ ## What is `hex_zmq_servers`
67
+
68
+ `hex_zmq_servers` provides a client–server layer on top of ZeroMQ to control and stream data from HEXFELLOW hardware (robots, RGB/RGB-D cameras) and MuJoCo-based simulators. Servers run device logic and command loops; clients send requests (e.g. `get_rgb`, `get_state`, `set_target`) and receive headers plus optional binary buffers (e.g. images, joint state).
69
+
70
+ ## What problem it solves
71
+
72
+ - **Decoupled control**: Run device drivers and control loops in separate processes; clients connect over TCP.
73
+ - **Unified transport**: All devices use the same ZMQ request/response pattern (JSON header + NumPy buffer).
74
+ - **Multi-node management**: `HexLaunch` and `HexNodeConfig` start and monitor multiple server/client nodes from one process.
75
+
76
+ ## Target users
77
+
78
+ - Engineers integrating HEXFELLOW robots into their systems.
79
+ - Researchers running experiments with HEXFELLOW robots.
80
+
81
+ ---
82
+
83
+ # 📦 Installation
84
+
85
+ ## Requirements
86
+
87
+ - **Python**
88
+ - **OS**: `Linux` / `macOS`
89
+ - **Core dependencies**:
90
+ - `pyzmq`
91
+ - `hex_device`
92
+ - `hex_robo_utils`
93
+ - `opencv-python`
94
+
95
+ Optional device support (install via extras):
96
+
97
+ | Extra | Purpose |
98
+ | ----------- | ----------------------------------------------- |
99
+ | `berxel` | Berxel RGB-D: `berxel_py_wrapper` |
100
+ | `realsense` | RealSense RGB-D: `pyrealsense2` |
101
+ | `dynamixel` | Dynamixel: `dynamixel-sdk` |
102
+ | `mujoco` | MuJoCo sims: `mujoco` |
103
+ | `all` | `berxel` + `dynamixel` + `realsense` + `mujoco` |
104
+
105
+ ## Install from PyPI
106
+
107
+ For those who don't need examples, you can install the package from PyPI.
108
+
109
+ - **Full install**: includes all optional devices (Berxel, RealSense, Dynamixel, MuJoCo)
110
+
111
+ ```bash
112
+ pip install hex_zmq_servers[all]
113
+ ```
114
+
115
+ - **Core install**: only the core package (no optional devices)
116
+
117
+ ```bash
118
+ pip install hex_zmq_servers
119
+ ```
120
+
121
+ ## Install from Source
122
+
123
+ For those who need examples, you can install the package from source code with examples.
124
+
125
+ **Noet**: We use [**uv**](https://github.com/astral-sh/uv) to manage the Python environment. Please install it first.
126
+
127
+ 1. Clone and install in editable mode. The `venv.sh` script expects [uv](https://github.com/astral-sh/uv).
128
+
129
+ ```bash
130
+ git clone https://github.com/hexfellow/hex_zmq_servers.git
131
+ cd hex_zmq_servers
132
+ ./venv.sh
133
+ ```
134
+
135
+ - `./venv.sh` — creates `.venv`, installs `hex_zmq_servers` with `[all]` and `examples/adv/requirements.txt` (e.g. `pygame` for some examples).
136
+ - `./venv.sh --min` — installs the core package only (no optional device extras). Some examples will not run.
137
+ - `./venv.sh --pkg-only` — installs the package only, skips example-related dependencies.
138
+
139
+ 2. Activate before running examples:
140
+
141
+ ```bash
142
+ source .venv/bin/activate
143
+ ```
144
+
145
+ ---
146
+
147
+ # 📚 Tutorial
148
+
149
+ See [**Tutorial**](docs/tutorial.md) for details of all tutorials.
150
+
151
+ # 📑 API
152
+
153
+ See [**API**](docs/api.md) for details of all APIs.
154
+
155
+ # 💡 Example
156
+
157
+ See [**Example**](docs/example.md) for details of all examples.
158
+
159
+ ---
160
+
161
+ # 🏷️ Citation
162
+
163
+ If you want to cite this project in your work, you can use the following BibTeX entry:
164
+
165
+ ```bibtex
166
+ @software{hex_zmq_servers,
167
+ author = {Dong, Zhaorui},
168
+ title = {Hex ZMQ Servers: A ZeroMQ-Based Embodied AI Communication Framework},
169
+ year = {2025},
170
+ publisher = {Zenodo},
171
+ version = {v1.0.0},
172
+ doi = {10.5281/zenodo.18309960},
173
+ url = {https://doi.org/10.5281/zenodo.18309960}
174
+ }
175
+ ```
176
+
177
+ ---
178
+
179
+ # 📄 License
180
+
181
+ Apache License 2.0. See [LICENSE](LICENSE).
182
+
183
+ ---
184
+
185
+ # 🌟 Star History
186
+
187
+ [![Star History Chart](https://api.star-history.com/svg?repos=hexfellow/hex_zmq_servers&type=Date)](https://star-history.com/#hexfellow/hex_zmq_servers&Date)
188
+
@@ -1,11 +1,11 @@
1
- hex_zmq_servers/__init__.py,sha256=1dnB9YTRq5uAFHo_3dMp1t1UxS4ZrcuZ_7CzBwqAfEM,5426
1
+ hex_zmq_servers/__init__.py,sha256=YZzC3MnGlyafcB6CShZRG-Jai86rMJ4buZKQ7k6Ap6k,5684
2
2
  hex_zmq_servers/device_base.py,sha256=SdRfM4VdJQ_gK-SKjt6ut4fWOR9eYpzmTQb6N6Lx7UI,1264
3
3
  hex_zmq_servers/hex_launch.py,sha256=x-xCBhpjgK6yWHGk5o5kYsb5ef2GsdeLr8rX59EJR-0,17700
4
- hex_zmq_servers/zmq_base.py,sha256=1sJTxzQionZE1aJXPVAPf--PtILivD4S3x8AZ8xx17M,16822
4
+ hex_zmq_servers/zmq_base.py,sha256=DXLBSCT2VJQG8Y4aXCZEuKrawupOx3sk7H4crz9uXtc,17030
5
5
  hex_zmq_servers/cam/__init__.py,sha256=hZ4NTEaO9uxcBua-nyJTpXxmk_GiIAcK2uWz3QQbwvE,1408
6
6
  hex_zmq_servers/cam/cam_base.py,sha256=YQ_uwH-ej7qGRr5RqQBDnaS7jCWV66lxAAkWD5c0gLc,6055
7
7
  hex_zmq_servers/cam/berxel/__init__.py,sha256=3fK06RWAS_q8a_3z-RxFTv32e99og-4dMZTxH08TOcY,508
8
- hex_zmq_servers/cam/berxel/cam_berxel.py,sha256=rAkqZz8a48d_aUFwVP8B2NeH8Zzl7dHqpOaDRxfleVQ,9872
8
+ hex_zmq_servers/cam/berxel/cam_berxel.py,sha256=TXbG2k3ZrpeuBLk1oqBxihn1FNHegUEuchQ_yIMuSm4,10291
9
9
  hex_zmq_servers/cam/berxel/cam_berxel_cli.py,sha256=eoeMWoDZziX3V23v2G76KWhfXSf2jpj4DH2Yo74HvuQ,863
10
10
  hex_zmq_servers/cam/berxel/cam_berxel_srv.py,sha256=-Ut2GzAH0-5hFQDDIRcGzYz5On7YiXZ9KfOZrK2w53o,2439
11
11
  hex_zmq_servers/cam/dummy/__init__.py,sha256=EziQ8H8d9Vm1AYw4YryIumTXpx-lwEnlfzTl7VAnKHM,499
@@ -28,12 +28,12 @@ hex_zmq_servers/config/mujoco_archer_y6.json,sha256=cZFUjppqfqxWYrJPYcxqRk7i6DZD
28
28
  hex_zmq_servers/config/mujoco_e3_desktop.json,sha256=pSh-X4tMPrw5iNk39D9PC5l8xjCs5IB2AvRgOZszDQE,823
29
29
  hex_zmq_servers/config/robot_dummy.json,sha256=8dQPI2A0NjC1d6oj_TMoHduoyhynA-cwZ_-7J-QWz-g,3023
30
30
  hex_zmq_servers/config/robot_gello.json,sha256=DDICCpSvjUR1yqQFQEmFZ9mrmPt05Zre6Gu28ZMyu5Y,1217
31
- hex_zmq_servers/config/robot_hexarm.json,sha256=0YD1Vgsc3C6EfYCSopAFmef2rSAwG9I196eWTOrTGxk,750
31
+ hex_zmq_servers/config/robot_hexarm.json,sha256=01QovR0ibsDypVUKL4h_6EVeHG3I8QqfCc-jztH7Mm4,925
32
32
  hex_zmq_servers/config/zmq_dummy.json,sha256=yuWindzdHoXv2-nlMEXY1e7W-_vWLYKwe-w8m7eBxWQ,251
33
33
  hex_zmq_servers/mujoco/__init__.py,sha256=OKG7aJ2BACpob_DuAvikLiRo4M_3DO9Ffapwen87k_0,870
34
34
  hex_zmq_servers/mujoco/mujoco_base.py,sha256=1NXyUn3gBfkww9CKEuvVuzXXJQ-dpYoN_04r4bzZHoU,13632
35
35
  hex_zmq_servers/mujoco/archer_y6/__init__.py,sha256=v1vApZ-qBLEcqFjDN0eff5kvkzO3s8QHBO4AitBODfc,559
36
- hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6.py,sha256=DDw7hI7unCr7aMb6QOXz4Wdep8L3Ui_7e20iSUsAZMg,12328
36
+ hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6.py,sha256=9lqQuV8Q43iMlPq1-bKlFaExz77WlTDCiKumyClvKLA,13336
37
37
  hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6_cli.py,sha256=O2BfGf80G-K0CWxjsLrzA_HxqFbe9ED8USjG6OqNNII,2140
38
38
  hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6_srv.py,sha256=nHMaHuauakfaNBy-Y7mYmjYtpWOFCEe8LE93smMhuqk,5211
39
39
  hex_zmq_servers/mujoco/archer_y6/model/joint_class.xml,sha256=2VPHALLFrf2PLAiF6KLohigtx8sa757RmYHLgJ-QYFc,995
@@ -57,7 +57,7 @@ hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_right_link_1.STL,sha256=fj
57
57
  hex_zmq_servers/mujoco/archer_y6/model/assets/gripper_right_link_2.STL,sha256=ucyn656VxBpRx3sshxLxMPJIUZfNfEQ90P-9b8sR0xg,80284
58
58
  hex_zmq_servers/mujoco/archer_y6/model/assets/table_link.STL,sha256=dqFXHRqjZSDyvYHCaJkbmYFsKngZRk1xjg_Zl2_jDc4,684
59
59
  hex_zmq_servers/mujoco/e3_desktop/__init__.py,sha256=pMLKpJGBHgc9IU142NcM7ubwdXq9E422k6Giui1A8i4,565
60
- hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop.py,sha256=8Og4sHDh1q3s-bLLfNW-Mqsxc_0zXhYrMZrmiE9PoaY,18353
60
+ hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop.py,sha256=uZT5qSzrHO_g5WzhKhAt1t7yLCKGxzDmD5AixTNSyNc,20214
61
61
  hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop_cli.py,sha256=_TJAtGNc7Ka6Sm3xiIJeqJ9fiHRecNpwjCxTNzRPbBI,9414
62
62
  hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop_srv.py,sha256=uHd0nE8igamBZHC9ouLKKSrg4NWusvk8dQ0HkTpe_OQ,9344
63
63
  hex_zmq_servers/mujoco/e3_desktop/model/joint_class.xml,sha256=2VPHALLFrf2PLAiF6KLohigtx8sa757RmYHLgJ-QYFc,995
@@ -81,7 +81,7 @@ hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_right_helper_link.STL,sha
81
81
  hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_right_link_1.STL,sha256=fjz04vqaBZGOb9GL6N4CVdIR1kOWrsdwh-jo7CRp9pg,28384
82
82
  hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_right_link_2.STL,sha256=ucyn656VxBpRx3sshxLxMPJIUZfNfEQ90P-9b8sR0xg,80284
83
83
  hex_zmq_servers/mujoco/e3_desktop/model/assets/table_link.STL,sha256=dqFXHRqjZSDyvYHCaJkbmYFsKngZRk1xjg_Zl2_jDc4,684
84
- hex_zmq_servers/robot/__init__.py,sha256=PqzGhsdbaeyYa7EZpAYMvT9myYhCO3OTbSPXVp1uiUM,1026
84
+ hex_zmq_servers/robot/__init__.py,sha256=rgAiVl_aSMarD-lqgLznG1bBQvo8xSPjXev1tk3mKsg,1237
85
85
  hex_zmq_servers/robot/robot_base.py,sha256=iau5aCLBKuPkRT3E1PTUfHxM2ji41pohVjO1T4Sdd8k,8564
86
86
  hex_zmq_servers/robot/dummy/__init__.py,sha256=_lDtPH-JQ1ltPB8JzD7wLu77iwNOgEZ3fJkz8MNKXrw,517
87
87
  hex_zmq_servers/robot/dummy/robot_dummy.py,sha256=_dTLajZCO5gjyw0KWedr8VsOTrtSkikcrJ8L2YpEwwQ,2781
@@ -92,9 +92,9 @@ hex_zmq_servers/robot/gello/robot_gello.py,sha256=AwgMZcADtJR0NPjEYV4_p6v70RCFCw
92
92
  hex_zmq_servers/robot/gello/robot_gello_cli.py,sha256=1Ik9sDT8Xh2sXtqR46wbJCt7QhnhTKzJeCEzUiiFLtA,751
93
93
  hex_zmq_servers/robot/gello/robot_gello_srv.py,sha256=5w95Rgt0p0vxaH2olX40V3h0CwVH8eEtx2U0iTO8cxM,2970
94
94
  hex_zmq_servers/robot/hexarm/__init__.py,sha256=-smiJ_bEpmR6kH7GfqDXQzcmaGCpgyuskdl9Hm_trlI,1852
95
- hex_zmq_servers/robot/hexarm/robot_hexarm.py,sha256=2mMBXWzMUHrUOqq2iYGbs5xszFx5uNuHkvLAspZ5Ues,10445
95
+ hex_zmq_servers/robot/hexarm/robot_hexarm.py,sha256=ciCD2x2_uREJwBavXLe1r_9JOXYd3VzdB4KPb9TI8os,10827
96
96
  hex_zmq_servers/robot/hexarm/robot_hexarm_cli.py,sha256=QbFiZFHnmyu5Wfwzj2fMRGqLdXBrS2HcpTGnG-BH_D8,904
97
- hex_zmq_servers/robot/hexarm/robot_hexarm_srv.py,sha256=nSB-SuVmBT6v24xajtSyQ9APU9-a0HqiYxSLel9KOs0,2889
97
+ hex_zmq_servers/robot/hexarm/robot_hexarm_srv.py,sha256=ANmqwl532d0cV9XCA29_55E-HGwrSmvSzQEDG-r-a2Y,2924
98
98
  hex_zmq_servers/robot/hexarm/urdf/archer_d6y/empty.urdf,sha256=3qrJq2dQ77k2iz_N2hZQwudvqPsLR_-JUAeCE3M7twQ,7451
99
99
  hex_zmq_servers/robot/hexarm/urdf/archer_d6y/gp100.urdf,sha256=VcZw5HNS4DCcD5mI5VvouS-72qrOr7-yzNmch6H2TRo,7468
100
100
  hex_zmq_servers/robot/hexarm/urdf/archer_d6y/gp100_handle.urdf,sha256=_5KBK-vHuPZASAsp9EkAFjcY4wsmTS6AioR5iHISuK4,7473
@@ -111,8 +111,8 @@ hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100_handle.urdf,sha256=sKZRz97fnz0
111
111
  hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100_p050.urdf,sha256=Ayq0xhf8euYWD83hv-Wa2-D0LyOqFrVj-N6W1X1GEHo,7448
112
112
  hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100_p050_handle.urdf,sha256=UjeDE7bZgUMPGJlHOJMJofcEjQ2BRkShCUomxhKUPk0,7445
113
113
  hex_zmq_servers/robot/hexarm/urdf/firefly_y6/empty.urdf,sha256=OWNmNHVNP0PvYY8s3jvrNBFAiMEYs3Zxr9NnV1APd8g,7601
114
- hex_zmq_servers-0.3.16.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
115
- hex_zmq_servers-0.3.16.dist-info/METADATA,sha256=yDUcFn5IzzUmcoSUR-BHxRrzvQdy6gejXP4r-TacO_s,4751
116
- hex_zmq_servers-0.3.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
117
- hex_zmq_servers-0.3.16.dist-info/top_level.txt,sha256=lPH1DfgMrQOe0Grh8zSZopf6LmnLvb_aStVmZ41PyAg,16
118
- hex_zmq_servers-0.3.16.dist-info/RECORD,,
114
+ hex_zmq_servers-1.0.0.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
115
+ hex_zmq_servers-1.0.0.dist-info/METADATA,sha256=Fun1vJg3YNVw8e30_cH73wk22Slyc7cW_516TTYwyqk,6506
116
+ hex_zmq_servers-1.0.0.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
117
+ hex_zmq_servers-1.0.0.dist-info/top_level.txt,sha256=lPH1DfgMrQOe0Grh8zSZopf6LmnLvb_aStVmZ41PyAg,16
118
+ hex_zmq_servers-1.0.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,147 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: hex_zmq_servers
3
- Version: 0.3.16
4
- Summary: HEXFELLOW ZMQ Servers
5
- Author-email: Dong Zhaorui <joray.dong@hexfellow.com>
6
- Maintainer-email: jecjune <zejun.chen@hexfellow.com>, Dong Zhaorui <joray.dong@hexfellow.com>
7
- License-Expression: Apache-2.0
8
- Project-URL: Homepage, https://github.com/hexfellow/hex_zmq_servers
9
- Project-URL: Repository, https://github.com/hexfellow/hex_zmq_servers.git
10
- Project-URL: Bug Tracker, https://github.com/hexfellow/hex_zmq_servers/issues
11
- Project-URL: Documentation, https://github.com/hexfellow/hex_zmq_servers/wiki
12
- Keywords: hex_zmq_servers
13
- Classifier: Development Status :: 4 - Beta
14
- Classifier: Intended Audience :: Developers
15
- Classifier: Intended Audience :: Science/Research
16
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
17
- Classifier: Programming Language :: Python :: 3
18
- Classifier: Programming Language :: Python :: 3.10
19
- Classifier: Programming Language :: Python :: 3.11
20
- Classifier: Programming Language :: Python :: 3.12
21
- Classifier: Operating System :: POSIX :: Linux
22
- Requires-Python: >=3.10
23
- Description-Content-Type: text/markdown
24
- License-File: LICENSE
25
- Requires-Dist: pyzmq>=27.0.1
26
- Requires-Dist: hex_device<1.4.0,>=1.3.1
27
- Requires-Dist: hex_robo_utils<0.3.0,>=0.2.0
28
- Requires-Dist: dynamixel-sdk==3.8.4
29
- Requires-Dist: opencv-python>=4.2
30
- Provides-Extra: berxel
31
- Requires-Dist: berxel_py_wrapper>=2.0.182; extra == "berxel"
32
- Provides-Extra: realsense
33
- Requires-Dist: pyrealsense2>=2.56.5.9235; extra == "realsense"
34
- Provides-Extra: mujoco
35
- Requires-Dist: mujoco>=3.3.3; extra == "mujoco"
36
- Provides-Extra: all
37
- Requires-Dist: berxel_py_wrapper>=2.0.182; extra == "all"
38
- Requires-Dist: mujoco>=3.3.3; extra == "all"
39
- Requires-Dist: pyrealsense2>=2.56.5.9235; extra == "all"
40
- Dynamic: license-file
41
-
42
- # hex_zmq_servers
43
-
44
- ## Introduction
45
-
46
- **`hex_zmq_servers`** is a comprehensive distributed device control framework based on ZeroMQ, providing efficient client-server communication for HEXFELLOW devices.
47
-
48
- ## Project Structure
49
-
50
- ```bash
51
- hex_zmq_servers/
52
- ├── hex_zmq_servers/ # Core library
53
- │ ├── robot/ # Robot devices
54
- │ ├── cam/ # Camera devices
55
- │ ├── mujoco/ # Mujoco simulation devices
56
- │ └── config/ # Default configuration files
57
- ├── examples/ # Example code
58
- │ ├── basic/ # Basic examples (single device)
59
- │ └── adv/ # Advanced examples (multi-device coordination)
60
- └── venv.sh # Virtual environment script
61
- ```
62
-
63
- ## Devices
64
-
65
- ### Robot
66
-
67
- - **dummy**: Dummy robot, for testing and development
68
- - **gello**: GELLO robot, based on Dynamixel servo
69
- - **hexarm**: HexArm robot of HEXFELLOW
70
-
71
- ### Camera
72
-
73
- - **dummy**: Dummy camera, for testing and development
74
- - **berxel**: Berxel depth camera, providing RGB and depth images
75
-
76
- ### Mujoco
77
-
78
- - **archer_y6**: Physical simulation of Archer Y6 robot
79
- - **e3_desktop**: Physical simulation of E3 Desktop robot
80
-
81
- ## Installation
82
-
83
- ### Install from PyPI
84
-
85
- 1. For those who only want to use the library in their projects, it is recommended to install it from PyPI.
86
-
87
- ```bash
88
- pip install hex_zmq_servers[all]
89
- ```
90
-
91
- 2. If you don't want to install the extra dependencies for extra devices, you can run:
92
-
93
- ```bash
94
- pip install hex_zmq_servers
95
- ```
96
-
97
- ### Install from Source Code
98
-
99
- 1. For those who want to test the examples or contribute to the project, you can install it from source code.
100
-
101
- ```bash
102
- git clone https://github.com/hexfellow/hex_zmq_servers.git
103
- cd hex_zmq_servers
104
- ./venv.sh
105
- ```
106
-
107
- 2. If you don't want to install the extra dependencies for extra devices, you can run:
108
-
109
- ```bash
110
- git clone https://github.com/hexfellow/hex_zmq_servers.git
111
- cd hex_zmq_servers
112
- ./venv.sh --min
113
- ```
114
-
115
- (**Important**) Some examples would not work without the extra dependencies.
116
-
117
- 3. If you don't want to install the examples, you can run:
118
-
119
- ```bash
120
- git clone https://github.com/hexfellow/hex_zmq_servers.git
121
- cd hex_zmq_servers
122
- ./venv.sh --pkg-only
123
- ```
124
-
125
- ## Examples
126
-
127
- There are two types of examples in the project:
128
-
129
- - **basic/**: Basic examples, showing the usage of a single device
130
- - **adv/**: Advanced examples, showing multi-device coordination
131
-
132
- More details please refer to [examples/README.md](examples/README.md)
133
-
134
- ## Contributions
135
-
136
- Welcome to submit issues and pull requests!
137
-
138
- ## License
139
-
140
- Apache License 2.0
141
-
142
- ## Contact
143
-
144
- - Author: [Dong Zhaorui](https://github.com/IBNBlank)
145
- - Maintainer: [jecjune](https://github.com/Jecjune)
146
- - GitHub: [hex_zmq_servers](https://github.com/hexfellow/hex_zmq_servers)
147
- - Issue Tracker: [hex_zmq_servers](https://github.com/hexfellow/hex_zmq_servers/issues)