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,366 @@
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 os
10
+ import subprocess
11
+ import time
12
+ import threading
13
+ import numpy as np
14
+ from collections import deque
15
+
16
+ from ..robot_base import HexRobotBase
17
+ from ...zmq_base import (
18
+ hex_zmq_ts_now,
19
+ hex_zmq_ts_delta_ms,
20
+ HexRate,
21
+ )
22
+ from ...hex_launch import hex_log, HEX_LOG_LEVEL
23
+ from dynamixel_sdk.group_sync_read import GroupSyncRead
24
+ from dynamixel_sdk.group_sync_write import GroupSyncWrite
25
+ from dynamixel_sdk.packet_handler import PacketHandler
26
+ from dynamixel_sdk.port_handler import PortHandler
27
+ from dynamixel_sdk.robotis_def import (
28
+ COMM_SUCCESS,
29
+ DXL_HIBYTE,
30
+ DXL_HIWORD,
31
+ DXL_LOBYTE,
32
+ DXL_LOWORD,
33
+ )
34
+
35
+ DYNAMIXEL_TORQUE_ENABLE_ADDR = 64
36
+ DYNAMIXEL_TORQUE_ENABLE_VAL = 1
37
+ DYNAMIXEL_TORQUE_DISABLE_VAL = 0
38
+ DYNAMIXEL_GOAL_POSITION_ADDR = 116
39
+ DYNAMIXEL_GOAL_POSITION_LEN = 4
40
+ DYNAMIXEL_PRESENT_POSITION_ADDR = 132
41
+ DYNAMIXEL_PRESENT_POSITION_LEN = 4
42
+
43
+ ROBOT_CONFIG = {
44
+ "idxs": [0, 1, 2, 3, 4, 5, 6],
45
+ "invs": [1.0, -1.0, 1.0, 1.0, -1.0, -4.0],
46
+ "limits": [[[-2.7, 2.7], [-1.57, 2.09], [0, 3.14], [-1.57, 1.57],
47
+ [-1.57, 1.57], [-1.57, 1.57], [0.0, 1.0]]],
48
+ "device":
49
+ "/dev/ttyUSB0",
50
+ "baudrate":
51
+ 115200,
52
+ "max_retries":
53
+ 3,
54
+ "torque_enabled":
55
+ False,
56
+ "sens_ts":
57
+ True,
58
+ }
59
+
60
+
61
+ class HexRobotGello(HexRobotBase):
62
+
63
+ def __init__(
64
+ self,
65
+ robot_config: dict = ROBOT_CONFIG,
66
+ realtime_mode: bool = False,
67
+ ):
68
+ HexRobotBase.__init__(self, realtime_mode)
69
+
70
+ try:
71
+ self.__idxs = np.array(robot_config["idxs"])
72
+ self.__invs = np.array(robot_config["invs"])
73
+ self._limits = np.array(robot_config["limits"])
74
+ self.__device = robot_config["device"]
75
+ self.__baudrate = robot_config["baudrate"]
76
+ self.__max_retries = robot_config["max_retries"]
77
+ self.__torque_enabled = robot_config["torque_enabled"]
78
+ self.__sens_ts = robot_config["sens_ts"]
79
+ except KeyError as ke:
80
+ missing_key = ke.args[0]
81
+ raise ValueError(
82
+ f"robot_config is not valid, missing key: {missing_key}")
83
+
84
+ # variables
85
+ # gello variables
86
+ self.__servo_to_rad = np.pi / 2048
87
+ self.__port_handler = None
88
+ self.__packet_handler = None
89
+ self.__group_sync_read = None
90
+ self.__group_sync_write = None
91
+ self.__lock = threading.Lock()
92
+ # robot variables
93
+ self._dofs = [self.__idxs.shape[0]]
94
+
95
+ # open device
96
+ for attempt in range(self.__max_retries):
97
+ print(
98
+ f"Attempting to initialize Dynamixel driver (attempt {attempt + 1}/{self.__max_retries})"
99
+ )
100
+ if self.__try_open_device():
101
+ break
102
+ else:
103
+ time.sleep(1.0)
104
+
105
+ # start work loop
106
+ self._working.set()
107
+
108
+ def work_loop(self, hex_queues: list[deque | threading.Event]):
109
+ states_queue = hex_queues[0]
110
+ cmds_queue = hex_queues[1]
111
+ stop_event = hex_queues[2]
112
+
113
+ states_count = 0
114
+ last_cmds_seq = -1
115
+ rate = HexRate(1000)
116
+ while self._working.is_set() and not stop_event.is_set():
117
+ # states
118
+ ts, states = self.__get_states()
119
+ if states is not None:
120
+ states_queue.append((ts, states_count, states))
121
+ states_count = (states_count + 1) % self._max_seq_num
122
+
123
+ # cmds
124
+ cmds_pack = None
125
+ try:
126
+ cmds_pack = cmds_queue[
127
+ -1] if self._realtime_mode else cmds_queue.popleft()
128
+ except IndexError:
129
+ pass
130
+ if cmds_pack is not None:
131
+ ts, seq, cmds = cmds_pack
132
+ if seq != last_cmds_seq:
133
+ last_cmds_seq = seq
134
+ if hex_zmq_ts_delta_ms(hex_zmq_ts_now(), ts) < 200.0:
135
+ self.__set_cmds(cmds)
136
+
137
+ # sleep
138
+ rate.sleep()
139
+
140
+ # close
141
+ self.close()
142
+
143
+ def __get_states(self):
144
+ with self.__lock:
145
+ ts = hex_zmq_ts_now()
146
+ servo_values = np.zeros(self._dofs, dtype=int)
147
+ dxl_comm_result = self.__group_sync_read.txRxPacket()
148
+ if dxl_comm_result != COMM_SUCCESS:
149
+ print(f"warning, comm failed: {dxl_comm_result}")
150
+ return None, None
151
+ for i, dxl_id in enumerate(self.__idxs):
152
+ if self.__group_sync_read.isAvailable(
153
+ dxl_id, DYNAMIXEL_PRESENT_POSITION_ADDR,
154
+ DYNAMIXEL_PRESENT_POSITION_LEN):
155
+ servo_value = self.__group_sync_read.getData(
156
+ dxl_id, DYNAMIXEL_PRESENT_POSITION_ADDR,
157
+ DYNAMIXEL_PRESENT_POSITION_LEN)
158
+ servo_value = np.int32(np.uint32(servo_value))
159
+ servo_values[i] = servo_value
160
+ else:
161
+ raise RuntimeError(
162
+ f"Failed to get joint angles for Dynamixel with ID {dxl_id}"
163
+ )
164
+
165
+ rads = self._apply_pos_limits(
166
+ servo_values * self.__servo_to_rad * self.__invs,
167
+ self._limits[:, 0],
168
+ self._limits[:, 1],
169
+ )
170
+ return ts if self.__sens_ts else hex_zmq_ts_now(), rads
171
+
172
+ def __set_cmds(self, cmds: np.ndarray):
173
+ if len(cmds) != len(self.__idxs):
174
+ print(
175
+ "\033[91mThe length of joint_angles must match the number of servos\033[0m"
176
+ )
177
+ return False
178
+ if not self.__torque_enabled:
179
+ print("\033[91mTorque must be enabled to set joint angles\033[0m")
180
+ return False
181
+
182
+ for dxl_id, cmd_rad in zip(self.__idxs, cmds):
183
+ # Convert the angle to the appropriate value for the servo
184
+ position_value = int(cmd_rad / self.__servo_to_rad)
185
+
186
+ # Allocate goal position value into byte array
187
+ param_goal_position = [
188
+ DXL_LOBYTE(DXL_LOWORD(position_value)),
189
+ DXL_HIBYTE(DXL_LOWORD(position_value)),
190
+ DXL_LOBYTE(DXL_HIWORD(position_value)),
191
+ DXL_HIBYTE(DXL_HIWORD(position_value)),
192
+ ]
193
+
194
+ # Add goal position value to the Syncwrite parameter storage
195
+ dxl_addparam_result = self.__group_sync_write.addParam(
196
+ dxl_id, param_goal_position)
197
+ if not dxl_addparam_result:
198
+ print(
199
+ f"\033[91mFailed to set joint angle for Dynamixel with ID {dxl_id}\033[0m"
200
+ )
201
+ return False
202
+
203
+ # Syncwrite goal position
204
+ dxl_comm_result = self.__group_sync_write.txPacket()
205
+ if dxl_comm_result != COMM_SUCCESS:
206
+ print(f"\033[91mFailed to syncwrite goal position\033[0m")
207
+ return False
208
+
209
+ # Clear syncwrite parameter storage
210
+ self.__group_sync_write.clearParam()
211
+
212
+ return True
213
+
214
+ def __try_open_device(self):
215
+ if not self.__check_device_availability():
216
+ print("Port is busy, attempting to free it...")
217
+ if not self.__kill_processes_using_device():
218
+ print("Failed to free device, trying to fix permissions...")
219
+ self.__fix_device_permissions()
220
+ time.sleep(2)
221
+
222
+ try:
223
+ self.__initialize_hardware()
224
+ print(
225
+ f"Successfully initialized Dynamixel driver on {self.__device}"
226
+ )
227
+ return True
228
+ except Exception as e:
229
+ print(f"Failed to initialize Dynamixel driver: {e}")
230
+ if "Permission denied" in str(e):
231
+ print(
232
+ "Please add permission to the device. For more details, please refer to the \033[0;31mhttps://docs.hexfellow.com\033[0m"
233
+ )
234
+ return False
235
+ return False
236
+
237
+ def __check_device_availability(self):
238
+ try:
239
+ # Check if port exists
240
+ if not os.path.exists(self.__device):
241
+ print(f"Device {self.__device} does not exist")
242
+ return False
243
+
244
+ # Check for processes using the port
245
+ result = subprocess.run(["lsof", self.__device],
246
+ capture_output=True,
247
+ text=True)
248
+
249
+ if result.returncode == 0:
250
+ lines = result.stdout.strip().split("\n")
251
+ if len(lines) > 1: # Header + processes
252
+ print(
253
+ f"Device {self.__device} is being used by other processes:"
254
+ )
255
+ for line in lines[1:]:
256
+ print(f" {line}")
257
+ return False
258
+ return True
259
+ except Exception as e:
260
+ print(f"Error checking device availability: {e}")
261
+ return False
262
+
263
+ def __kill_processes_using_device(self):
264
+ try:
265
+ result = subprocess.run(
266
+ ["fuser", "-k", self.__device],
267
+ capture_output=True,
268
+ text=True,
269
+ )
270
+ if result.returncode == 0:
271
+ print(f"Killed processes using {self.__device}")
272
+ time.sleep(1)
273
+ return True
274
+ return False
275
+ except Exception as e:
276
+ print(f"Error killing processes: {e}")
277
+ return False
278
+
279
+ def __fix_device_permissions(self):
280
+ try:
281
+ result = subprocess.run(["sudo", "chmod", "666", self.__device],
282
+ capture_output=True,
283
+ text=True)
284
+ if result.returncode == 0:
285
+ print(f"Fixed permissions for {self.__device}")
286
+ return True
287
+ return False
288
+ except Exception as e:
289
+ print(f"Error fixing device permissions: {e}")
290
+ return False
291
+
292
+ def __initialize_hardware(self):
293
+ # Check and prepare port before connection
294
+ self.__prepare_device()
295
+
296
+ # Initialize the port handler, packet handler, and group sync read/write
297
+ self.__port_handler = PortHandler(self.__device)
298
+ self.__packet_handler = PacketHandler(2.0)
299
+ self.__group_sync_read = GroupSyncRead(
300
+ self.__port_handler,
301
+ self.__packet_handler,
302
+ DYNAMIXEL_PRESENT_POSITION_ADDR,
303
+ DYNAMIXEL_PRESENT_POSITION_LEN,
304
+ )
305
+ self.__group_sync_write = GroupSyncWrite(
306
+ self.__port_handler,
307
+ self.__packet_handler,
308
+ DYNAMIXEL_GOAL_POSITION_ADDR,
309
+ DYNAMIXEL_GOAL_POSITION_LEN,
310
+ )
311
+
312
+ # Open the port and set the baudrate
313
+ if not self.__port_handler.openPort():
314
+ raise RuntimeError("Failed to open the port")
315
+
316
+ if not self.__port_handler.setBaudRate(self.__baudrate):
317
+ raise RuntimeError(
318
+ f"Failed to change the baudrate, {self.__baudrate}")
319
+
320
+ # Add parameters for each Dynamixel servo to the group sync read
321
+ for dxl_id in self.__idxs:
322
+ if not self.__group_sync_read.addParam(dxl_id):
323
+ raise RuntimeError(
324
+ f"Failed to add parameter for Dynamixel with ID {dxl_id}")
325
+
326
+ # Disable torque for each Dynamixel servo
327
+ if self.__torque_enabled:
328
+ try:
329
+ self.__hardware_set_torque_mode(self.__torque_enabled)
330
+ except Exception as e:
331
+ print(f"device: {self.__device}, {e}")
332
+
333
+ def __prepare_device(self):
334
+ if not self.__check_device_availability():
335
+ print(
336
+ f"Device {self.__device} is not available, attempting to fix..."
337
+ )
338
+ self.__kill_processes_using_device()
339
+ self.__fix_device_permissions()
340
+
341
+ # Check again after fixing
342
+ if not self.__check_device_availability():
343
+ print(f"Warning: Device {self.__device} may still have issues")
344
+
345
+ def __hardware_set_torque_mode(self, enable: bool):
346
+ torque_value = DYNAMIXEL_TORQUE_ENABLE_VAL if enable else DYNAMIXEL_TORQUE_DISABLE_VAL
347
+ with self.__lock:
348
+ for dxl_id in self.__idxs:
349
+ dxl_comm_result, dxl_error = self.__packet_handler.write1ByteTxRx(
350
+ self.__port_handler, dxl_id, DYNAMIXEL_TORQUE_ENABLE_ADDR,
351
+ torque_value)
352
+ if dxl_comm_result != COMM_SUCCESS or dxl_error != 0:
353
+ print(dxl_comm_result)
354
+ print(dxl_error)
355
+ raise RuntimeError(
356
+ f"Failed to set torque mode for Dynamixel with ID {dxl_id}"
357
+ )
358
+
359
+ self.__torque_enabled = enable
360
+
361
+ def close(self):
362
+ if not self._working.is_set():
363
+ return
364
+ self._working.clear()
365
+ self.__port_handler.closePort()
366
+ hex_log(HEX_LOG_LEVEL["info"], "HexRobotGello 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-14
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 HexRobotGelloClient(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,93 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding:utf-8 -*-
3
+ ################################################################
4
+ # Copyright 2025 Dong Zhaorui. All rights reserved.
5
+ # Author: Dong Zhaorui 847235539@qq.com
6
+ # Date : 2025-09-14
7
+ ################################################################
8
+
9
+ import numpy as np
10
+
11
+ try:
12
+ from ..robot_base import HexRobotServerBase
13
+ from .robot_gello import HexRobotGello
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.gello.robot_gello import HexRobotGello
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
+ "idxs": [0, 1, 2, 3, 4, 5, 6],
36
+ "invs": [1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -4.0],
37
+ "limits": [[[-2.7, 2.7], [-1.57, 2.09], [0, 3.14], [-1.57, 1.57],
38
+ [-1.57, 1.57], [-1.57, 1.57], [0.0, 1.0]]],
39
+ "device":
40
+ "/dev/ttyUSB0",
41
+ "baudrate":
42
+ 115200,
43
+ "max_retries":
44
+ 3,
45
+ "torque_enabled":
46
+ False,
47
+ "sens_ts":
48
+ True,
49
+ }
50
+
51
+
52
+ class HexRobotGelloServer(HexRobotServerBase):
53
+
54
+ def __init__(
55
+ self,
56
+ net_config: dict = NET_CONFIG,
57
+ params_config: dict = ROBOT_CONFIG,
58
+ ):
59
+ HexRobotServerBase.__init__(self, net_config)
60
+
61
+ # robot
62
+ self._device = HexRobotGello(params_config,
63
+ net_config.get("realtime_mode", False))
64
+
65
+ def _process_request(self, recv_hdr: dict, recv_buf: np.ndarray):
66
+ if recv_hdr["cmd"] == "is_working":
67
+ return self.no_ts_hdr(recv_hdr, self._device.is_working()), None
68
+ elif recv_hdr["cmd"] == "seq_clear":
69
+ return self.no_ts_hdr(recv_hdr, self._seq_clear()), None
70
+ elif recv_hdr["cmd"] == "get_dofs":
71
+ dofs = self._device.get_dofs()
72
+ return self.no_ts_hdr(recv_hdr, dofs is not None), dofs
73
+ elif recv_hdr["cmd"] == "get_limits":
74
+ limits = self._device.get_limits()
75
+ return self.no_ts_hdr(recv_hdr, limits is not None), limits
76
+ elif recv_hdr["cmd"] == "get_states":
77
+ return self._get_states(recv_hdr)
78
+ elif recv_hdr["cmd"] == "set_cmds":
79
+ return self._set_cmds(recv_hdr, recv_buf)
80
+ else:
81
+ raise ValueError(f"unknown command: {recv_hdr['cmd']}")
82
+
83
+
84
+ if __name__ == "__main__":
85
+ import argparse, json
86
+ from hex_zmq_servers.zmq_base import hex_server_helper
87
+
88
+ parser = argparse.ArgumentParser()
89
+ parser.add_argument("--cfg", type=str, required=True)
90
+ args = parser.parse_args()
91
+ cfg = json.loads(args.cfg)
92
+
93
+ hex_server_helper(cfg, HexRobotGelloServer)
@@ -0,0 +1,47 @@
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_hexarm import HexRobotHexarm
10
+ from .robot_hexarm_cli import HexRobotHexarmClient
11
+ from .robot_hexarm_srv import HexRobotHexarmServer
12
+
13
+ import os
14
+
15
+ urdf_dir = os.path.join(os.path.dirname(__file__), "urdf")
16
+ HEXARM_URDF_PATH_DICT = {
17
+ "archer_y6_empty":
18
+ f"{urdf_dir}/archer_y6/empty.urdf",
19
+ "archer_y6_gp100":
20
+ f"{urdf_dir}/archer_y6/gp100.urdf",
21
+ "archer_y6_gp100_handle":
22
+ f"{urdf_dir}/archer_y6/gp100_handle.urdf",
23
+ "archer_y6_gp100_p050":
24
+ f"{urdf_dir}/archer_y6/gp100_p050.urdf",
25
+ "archer_y6_gp100_p050_handle":
26
+ f"{urdf_dir}/archer_y6/gp100_p050_handle.urdf",
27
+ "archer_l6y_empty":
28
+ f"{urdf_dir}/archer_l6y/empty.urdf",
29
+ "archer_l6y_gp100":
30
+ f"{urdf_dir}/archer_l6y/gp100.urdf",
31
+ "archer_l6y_gp100_handle":
32
+ f"{urdf_dir}/archer_l6y/gp100_handle.urdf",
33
+ "archer_l6y_gp100_p050":
34
+ f"{urdf_dir}/archer_l6y/gp100_p050.urdf",
35
+ "archer_l6y_gp100_p050_handle":
36
+ f"{urdf_dir}/archer_l6y/gp100_p050_handle.urdf",
37
+ }
38
+
39
+ __all__ = [
40
+ # path
41
+ "HEXARM_URDF_PATH_DICT",
42
+
43
+ # robot
44
+ "HexRobotHexarm",
45
+ "HexRobotHexarmClient",
46
+ "HexRobotHexarmServer",
47
+ ]