hex-zmq-servers 1.0.1__py3-none-any.whl → 1.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hex_zmq_servers/__init__.py +6 -0
- hex_zmq_servers/config/robot_hello.json +18 -0
- hex_zmq_servers/robot/__init__.py +6 -0
- hex_zmq_servers/robot/hello/__init__.py +18 -0
- hex_zmq_servers/robot/hello/robot_hello.py +312 -0
- hex_zmq_servers/robot/hello/robot_hello_cli.py +84 -0
- hex_zmq_servers/robot/hello/robot_hello_srv.py +114 -0
- hex_zmq_servers/robot/hexarm/__init__.py +2 -2
- hex_zmq_servers/robot/hexarm/robot_hexarm.py +6 -3
- {hex_zmq_servers-1.0.1.dist-info → hex_zmq_servers-1.0.2.dist-info}/METADATA +2 -2
- {hex_zmq_servers-1.0.1.dist-info → hex_zmq_servers-1.0.2.dist-info}/RECORD +14 -9
- {hex_zmq_servers-1.0.1.dist-info → hex_zmq_servers-1.0.2.dist-info}/WHEEL +0 -0
- {hex_zmq_servers-1.0.1.dist-info → hex_zmq_servers-1.0.2.dist-info}/licenses/LICENSE +0 -0
- {hex_zmq_servers-1.0.1.dist-info → hex_zmq_servers-1.0.2.dist-info}/top_level.txt +0 -0
hex_zmq_servers/__init__.py
CHANGED
|
@@ -15,6 +15,7 @@ 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 HexRobotHello, HexRobotHelloClient, HexRobotHelloServer
|
|
18
19
|
from .robot import HexRobotHexarm, HexRobotHexarmClient, HexRobotHexarmServer, HEXARM_URDF_PATH_DICT
|
|
19
20
|
|
|
20
21
|
from .cam import HexCamBase, HexCamClientBase, HexCamServerBase
|
|
@@ -28,6 +29,7 @@ HEX_ZMQ_SERVERS_PATH_DICT = {
|
|
|
28
29
|
"zmq_dummy": f"{file_dir}/zmq_base.py",
|
|
29
30
|
"robot_dummy": f"{file_dir}/robot/dummy/robot_dummy_srv.py",
|
|
30
31
|
"robot_hexarm": f"{file_dir}/robot/hexarm/robot_hexarm_srv.py",
|
|
32
|
+
"robot_hello": f"{file_dir}/robot/hello/robot_hello_srv.py",
|
|
31
33
|
"cam_dummy": f"{file_dir}/cam/dummy/cam_dummy_srv.py",
|
|
32
34
|
"cam_rgb": f"{file_dir}/cam/rgb/cam_rgb_srv.py",
|
|
33
35
|
}
|
|
@@ -35,6 +37,7 @@ HEX_ZMQ_CONFIGS_PATH_DICT = {
|
|
|
35
37
|
"zmq_dummy": f"{file_dir}/config/zmq_dummy.json",
|
|
36
38
|
"robot_dummy": f"{file_dir}/config/robot_dummy.json",
|
|
37
39
|
"robot_hexarm": f"{file_dir}/config/robot_hexarm.json",
|
|
40
|
+
"robot_hello": f"{file_dir}/config/robot_hello.json",
|
|
38
41
|
"cam_dummy": f"{file_dir}/config/cam_dummy.json",
|
|
39
42
|
"cam_rgb": f"{file_dir}/config/cam_rgb.json",
|
|
40
43
|
}
|
|
@@ -77,6 +80,9 @@ __all__ = [
|
|
|
77
80
|
"HexRobotDummy",
|
|
78
81
|
"HexRobotDummyClient",
|
|
79
82
|
"HexRobotDummyServer",
|
|
83
|
+
"HexRobotHello",
|
|
84
|
+
"HexRobotHelloClient",
|
|
85
|
+
"HexRobotHelloServer",
|
|
80
86
|
"HexRobotHexarm",
|
|
81
87
|
"HexRobotHexarmClient",
|
|
82
88
|
"HexRobotHexarmServer",
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"net": {
|
|
3
|
+
"ip": "127.0.0.1",
|
|
4
|
+
"port": 12345,
|
|
5
|
+
"realtime_mode": false,
|
|
6
|
+
"deque_maxlen": 10,
|
|
7
|
+
"client_timeout_ms": 200,
|
|
8
|
+
"server_timeout_ms": 1000,
|
|
9
|
+
"server_num_workers": 4
|
|
10
|
+
},
|
|
11
|
+
"params": {
|
|
12
|
+
"device_ip": "172.18.8.161",
|
|
13
|
+
"device_port": 8439,
|
|
14
|
+
"control_hz": 1000,
|
|
15
|
+
"arm_type": "archer_y6",
|
|
16
|
+
"sens_ts": true
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
from .robot_base import HexRobotBase, HexRobotClientBase, HexRobotServerBase
|
|
10
10
|
from .dummy import HexRobotDummy, HexRobotDummyClient, HexRobotDummyServer
|
|
11
|
+
from .hello import HexRobotHello, HexRobotHelloClient, HexRobotHelloServer
|
|
11
12
|
from .hexarm import HexRobotHexarm, HexRobotHexarmClient, HexRobotHexarmServer, HEXARM_URDF_PATH_DICT
|
|
12
13
|
|
|
13
14
|
__all__ = [
|
|
@@ -24,6 +25,11 @@ __all__ = [
|
|
|
24
25
|
"HexRobotDummyClient",
|
|
25
26
|
"HexRobotDummyServer",
|
|
26
27
|
|
|
28
|
+
# hello
|
|
29
|
+
"HexRobotHello",
|
|
30
|
+
"HexRobotHelloClient",
|
|
31
|
+
"HexRobotHelloServer",
|
|
32
|
+
|
|
27
33
|
# hexarm
|
|
28
34
|
"HexRobotHexarm",
|
|
29
35
|
"HexRobotHexarmClient",
|
|
@@ -0,0 +1,18 @@
|
|
|
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_hello import HexRobotHello
|
|
10
|
+
from .robot_hello_cli import HexRobotHelloClient
|
|
11
|
+
from .robot_hello_srv import HexRobotHelloServer
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
# robot
|
|
15
|
+
"HexRobotHello",
|
|
16
|
+
"HexRobotHelloClient",
|
|
17
|
+
"HexRobotHelloServer",
|
|
18
|
+
]
|
|
@@ -0,0 +1,312 @@
|
|
|
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 time
|
|
10
|
+
import threading
|
|
11
|
+
import numpy as np
|
|
12
|
+
from collections import deque
|
|
13
|
+
|
|
14
|
+
from ..robot_base import HexRobotBase
|
|
15
|
+
from ...zmq_base import (
|
|
16
|
+
hex_zmq_ts_now,
|
|
17
|
+
hex_zmq_ts_delta_ms,
|
|
18
|
+
HexRate,
|
|
19
|
+
)
|
|
20
|
+
from ...hex_launch import hex_log, HEX_LOG_LEVEL
|
|
21
|
+
from hex_device import HexDeviceApi, Arm, Hands
|
|
22
|
+
from hex_device.motor_base import CommandType
|
|
23
|
+
|
|
24
|
+
ROBOT_CONFIG = {
|
|
25
|
+
"device_ip": "172.18.8.161",
|
|
26
|
+
"device_port": 8439,
|
|
27
|
+
"control_hz": 250,
|
|
28
|
+
"arm_type": "archer_y6",
|
|
29
|
+
"sens_ts": True,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
HELLO_DEVICE_TYPE_DICT = {
|
|
33
|
+
# 6 dof
|
|
34
|
+
"archer_y6": 26,
|
|
35
|
+
"archer_d6y": 26,
|
|
36
|
+
"archer_l6y": 26,
|
|
37
|
+
"firefly_y6": 26,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class HexRobotHello(HexRobotBase):
|
|
42
|
+
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
robot_config: dict = ROBOT_CONFIG,
|
|
46
|
+
realtime_mode: bool = False,
|
|
47
|
+
):
|
|
48
|
+
HexRobotBase.__init__(self, realtime_mode)
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
device_ip = robot_config["device_ip"]
|
|
52
|
+
device_port = robot_config["device_port"]
|
|
53
|
+
control_hz = robot_config["control_hz"]
|
|
54
|
+
arm_type = HELLO_DEVICE_TYPE_DICT[robot_config["arm_type"]]
|
|
55
|
+
self.__sens_ts = robot_config["sens_ts"]
|
|
56
|
+
except KeyError as ke:
|
|
57
|
+
missing_key = ke.args[0]
|
|
58
|
+
raise ValueError(
|
|
59
|
+
f"robot_config is not valid, missing key: {missing_key}")
|
|
60
|
+
|
|
61
|
+
# variables
|
|
62
|
+
# hex_arm variables
|
|
63
|
+
self.__hex_api: HexDeviceApi | None = None
|
|
64
|
+
self.__arm: Arm | None = None
|
|
65
|
+
self.__gripper: Hands | None = None
|
|
66
|
+
|
|
67
|
+
# buffer
|
|
68
|
+
self.__arm_state_buffer: dict | None = None
|
|
69
|
+
self.__gripper_state_buffer: dict | None = None
|
|
70
|
+
|
|
71
|
+
# open device
|
|
72
|
+
self.__hex_api = HexDeviceApi(
|
|
73
|
+
ws_url=f"ws://{device_ip}:{device_port}",
|
|
74
|
+
control_hz=control_hz,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# open arm
|
|
78
|
+
while self.__hex_api.find_device_by_robot_type(arm_type) is None:
|
|
79
|
+
print("\033[33mArm not found\033[0m")
|
|
80
|
+
time.sleep(1)
|
|
81
|
+
self.__arm = self.__hex_api.find_device_by_robot_type(arm_type)
|
|
82
|
+
self.__arm.start()
|
|
83
|
+
|
|
84
|
+
# try to open gripper
|
|
85
|
+
self.__gripper = self.__hex_api.find_optional_device_by_id(1)
|
|
86
|
+
if self.__gripper is None:
|
|
87
|
+
print("\033[33mGripper not found\033[0m")
|
|
88
|
+
self.__gripper.set_rgb_stripe_command([0] * 6, [255] * 6, [0] * 6)
|
|
89
|
+
|
|
90
|
+
# variables init
|
|
91
|
+
arm_dofs = len(self.__arm)
|
|
92
|
+
self._dofs = [arm_dofs]
|
|
93
|
+
self._limits = np.array(self.__arm.get_joint_limits()).reshape(
|
|
94
|
+
-1, 3, 2)
|
|
95
|
+
self.__motor_idx = {"robot_arm": np.arange(arm_dofs).tolist()}
|
|
96
|
+
if self.__gripper is not None:
|
|
97
|
+
gripper_dofs = len(self.__gripper)
|
|
98
|
+
self._dofs.append(gripper_dofs)
|
|
99
|
+
gripper_limits = np.array(
|
|
100
|
+
self.__gripper.get_joint_limits()).reshape(-1, 3, 2)
|
|
101
|
+
self._limits = np.concatenate([self._limits, gripper_limits],
|
|
102
|
+
axis=0)
|
|
103
|
+
self.__motor_idx["robot_gripper"] = (np.arange(gripper_dofs) +
|
|
104
|
+
arm_dofs).tolist()
|
|
105
|
+
|
|
106
|
+
# modify variables
|
|
107
|
+
self._dofs = np.array(self._dofs)
|
|
108
|
+
self._dofs_sum = self._dofs.sum()
|
|
109
|
+
self._limits = np.ascontiguousarray(np.asarray(self._limits)).reshape(
|
|
110
|
+
self._dofs_sum, 3, 2)
|
|
111
|
+
|
|
112
|
+
# start work loop
|
|
113
|
+
self._working.set()
|
|
114
|
+
|
|
115
|
+
def work_loop(self, hex_queues: list[deque | threading.Event]):
|
|
116
|
+
states_queue = hex_queues[0]
|
|
117
|
+
rgbs_queue = hex_queues[1]
|
|
118
|
+
stop_event = hex_queues[2]
|
|
119
|
+
|
|
120
|
+
last_states_ts = hex_zmq_ts_now()
|
|
121
|
+
states_count = 0
|
|
122
|
+
cmds_count = 0
|
|
123
|
+
cmds = np.zeros((self._dofs_sum, 5))
|
|
124
|
+
last_rgbs_seq = -1
|
|
125
|
+
rate = HexRate(2000)
|
|
126
|
+
while self._working.is_set() and not stop_event.is_set():
|
|
127
|
+
# states
|
|
128
|
+
ts, states = self.__get_states()
|
|
129
|
+
if states is not None:
|
|
130
|
+
if hex_zmq_ts_delta_ms(ts, last_states_ts) > 1e-6:
|
|
131
|
+
last_states_ts = ts
|
|
132
|
+
states_queue.append((ts, states_count, states))
|
|
133
|
+
states_count = (states_count + 1) % self._max_seq_num
|
|
134
|
+
|
|
135
|
+
# cmds
|
|
136
|
+
cmds_count += 1
|
|
137
|
+
if cmds_count >= 1000:
|
|
138
|
+
cmds_count = 0
|
|
139
|
+
self.__set_cmds(cmds)
|
|
140
|
+
|
|
141
|
+
# rgbs
|
|
142
|
+
rgbs_pack = None
|
|
143
|
+
try:
|
|
144
|
+
rgbs_pack = rgbs_queue[
|
|
145
|
+
-1] if self._realtime_mode else rgbs_queue.popleft()
|
|
146
|
+
except IndexError:
|
|
147
|
+
pass
|
|
148
|
+
if rgbs_pack is not None:
|
|
149
|
+
ts, seq, rgbs = rgbs_pack
|
|
150
|
+
if seq != last_rgbs_seq:
|
|
151
|
+
last_rgbs_seq = seq
|
|
152
|
+
if hex_zmq_ts_delta_ms(hex_zmq_ts_now(), ts) < 200.0:
|
|
153
|
+
self.__set_rgbs(rgbs)
|
|
154
|
+
|
|
155
|
+
# sleep
|
|
156
|
+
rate.sleep()
|
|
157
|
+
|
|
158
|
+
# close
|
|
159
|
+
self.close()
|
|
160
|
+
|
|
161
|
+
def __get_states(self) -> tuple[np.ndarray | None, dict | None]:
|
|
162
|
+
if self.__arm is None:
|
|
163
|
+
return None, None
|
|
164
|
+
|
|
165
|
+
# (arm_dofs, 3) # pos vel eff
|
|
166
|
+
if self.__arm_state_buffer is None:
|
|
167
|
+
self.__arm_state_buffer = self.__arm.get_simple_motor_status()
|
|
168
|
+
|
|
169
|
+
# (gripper_dofs, 3) # pos vel eff
|
|
170
|
+
if self.__gripper is not None and self.__gripper_state_buffer is None:
|
|
171
|
+
self.__gripper_state_buffer = self.__gripper.get_simple_motor_status(
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
arm_ready = self.__arm_state_buffer is not None
|
|
175
|
+
gripper_ready = self.__gripper is None or self.__gripper_state_buffer is not None
|
|
176
|
+
if arm_ready and gripper_ready:
|
|
177
|
+
arm_ts = self.__arm_state_buffer['ts']
|
|
178
|
+
gripper_ts = self.__gripper_state_buffer[
|
|
179
|
+
'ts'] if self.__gripper is not None else arm_ts
|
|
180
|
+
|
|
181
|
+
delta_ms = hex_zmq_ts_delta_ms(arm_ts, gripper_ts)
|
|
182
|
+
if np.fabs(delta_ms) < 1e-6:
|
|
183
|
+
pos = self.__arm_state_buffer['pos']
|
|
184
|
+
vel = self.__arm_state_buffer['vel']
|
|
185
|
+
eff = self.__arm_state_buffer['eff']
|
|
186
|
+
|
|
187
|
+
if self.__gripper is not None:
|
|
188
|
+
pos = np.concatenate(
|
|
189
|
+
[pos, self.__gripper_state_buffer['pos']])
|
|
190
|
+
vel = np.concatenate(
|
|
191
|
+
[vel, self.__gripper_state_buffer['vel']])
|
|
192
|
+
eff = np.concatenate(
|
|
193
|
+
[eff, self.__gripper_state_buffer['eff']])
|
|
194
|
+
|
|
195
|
+
state = np.array([pos, vel, eff]).T
|
|
196
|
+
self.__arm_state_buffer, self.__gripper_state_buffer = None, None
|
|
197
|
+
return arm_ts if self.__sens_ts else hex_zmq_ts_now(), state
|
|
198
|
+
elif delta_ms > 0.0:
|
|
199
|
+
self.__gripper_state_buffer = None
|
|
200
|
+
return None, None
|
|
201
|
+
else:
|
|
202
|
+
self.__arm_state_buffer = None
|
|
203
|
+
return None, None
|
|
204
|
+
|
|
205
|
+
return None, None
|
|
206
|
+
|
|
207
|
+
def __set_cmds(self, cmds: np.ndarray) -> bool:
|
|
208
|
+
# cmds: (n)
|
|
209
|
+
# [pos_0, ..., pos_n]
|
|
210
|
+
# cmds: (n, 2)
|
|
211
|
+
# [[pos_0, tor_0], ..., [pos_n, tor_n]]
|
|
212
|
+
# cmds: (n, 5)
|
|
213
|
+
# [[pos_0, vel_0, tor_0, kp_0, kd_0], ..., [pos_n, vel_n, tor_n, kp_n, kd_n]]
|
|
214
|
+
if self.__arm is None:
|
|
215
|
+
print("\033[91mArm not found\033[0m")
|
|
216
|
+
return False
|
|
217
|
+
|
|
218
|
+
if cmds.shape[0] < self._dofs_sum:
|
|
219
|
+
print(
|
|
220
|
+
"\033[91mThe length of joint_angles must be greater than or equal to the number of motors\033[0m"
|
|
221
|
+
)
|
|
222
|
+
return False
|
|
223
|
+
elif cmds.shape[0] > self._dofs_sum:
|
|
224
|
+
print(
|
|
225
|
+
f"\033[33mThe length of joint_angles is greater than the number of motors\033[0m"
|
|
226
|
+
)
|
|
227
|
+
cmds = cmds[:self._dofs_sum]
|
|
228
|
+
|
|
229
|
+
cmd_pos = None
|
|
230
|
+
tar_vel = np.zeros(self._dofs_sum)
|
|
231
|
+
cmd_tor = np.zeros(self._dofs_sum)
|
|
232
|
+
cmd_kp = np.zeros(self._dofs_sum)
|
|
233
|
+
cmd_kd = np.zeros(self._dofs_sum)
|
|
234
|
+
if len(cmds.shape) == 1:
|
|
235
|
+
cmd_pos = cmds
|
|
236
|
+
elif len(cmds.shape) == 2:
|
|
237
|
+
if cmds.shape[1] == 2:
|
|
238
|
+
cmd_pos = cmds[:, 0]
|
|
239
|
+
cmd_tor = cmds[:, 1]
|
|
240
|
+
elif cmds.shape[1] == 5:
|
|
241
|
+
cmd_pos = cmds[:, 0]
|
|
242
|
+
tar_vel = cmds[:, 1]
|
|
243
|
+
cmd_tor = cmds[:, 2]
|
|
244
|
+
cmd_kp = cmds[:, 3]
|
|
245
|
+
cmd_kd = cmds[:, 4]
|
|
246
|
+
else:
|
|
247
|
+
raise ValueError(f"The shape of cmds is invalid: {cmds.shape}")
|
|
248
|
+
else:
|
|
249
|
+
raise ValueError(f"The shape of cmds is invalid: {cmds.shape}")
|
|
250
|
+
tar_pos = self._apply_pos_limits(
|
|
251
|
+
cmd_pos,
|
|
252
|
+
self._limits[:, 0, 0],
|
|
253
|
+
self._limits[:, 0, 1],
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
# arm
|
|
257
|
+
arm_cmd = self.__arm.construct_mit_command(
|
|
258
|
+
tar_pos[self.__motor_idx["robot_arm"]],
|
|
259
|
+
tar_vel[self.__motor_idx["robot_arm"]],
|
|
260
|
+
cmd_tor[self.__motor_idx["robot_arm"]],
|
|
261
|
+
cmd_kp[self.__motor_idx["robot_arm"]],
|
|
262
|
+
cmd_kd[self.__motor_idx["robot_arm"]],
|
|
263
|
+
)
|
|
264
|
+
self.__arm.motor_command(CommandType.MIT, arm_cmd)
|
|
265
|
+
|
|
266
|
+
# gripper
|
|
267
|
+
if self.__gripper is not None:
|
|
268
|
+
gripper_cmd = self.__gripper.construct_mit_command(
|
|
269
|
+
tar_pos[self.__motor_idx["robot_gripper"]],
|
|
270
|
+
tar_vel[self.__motor_idx["robot_gripper"]],
|
|
271
|
+
cmd_tor[self.__motor_idx["robot_gripper"]],
|
|
272
|
+
cmd_kp[self.__motor_idx["robot_gripper"]],
|
|
273
|
+
cmd_kd[self.__motor_idx["robot_gripper"]],
|
|
274
|
+
)
|
|
275
|
+
self.__gripper.motor_command(CommandType.MIT, gripper_cmd)
|
|
276
|
+
|
|
277
|
+
return True
|
|
278
|
+
|
|
279
|
+
def __set_rgbs(self, rgbs: np.ndarray) -> bool:
|
|
280
|
+
if self.__gripper is None:
|
|
281
|
+
print("\033[91mGripper not found\033[0m")
|
|
282
|
+
return False
|
|
283
|
+
|
|
284
|
+
rgbs_int = rgbs.astype(int)
|
|
285
|
+
rgbs_shape = rgbs_int.shape
|
|
286
|
+
rgbs_dim = len(rgbs_shape)
|
|
287
|
+
if rgbs_dim == 1:
|
|
288
|
+
if rgbs_shape[0] != 3:
|
|
289
|
+
print("\033[91mThe shape of rgbs is invalid\033[0m")
|
|
290
|
+
return False
|
|
291
|
+
rgbs_int = rgbs_int.reshape(1, 3)
|
|
292
|
+
rgbs_int = np.tile(rgbs_int, (6, 1))
|
|
293
|
+
elif rgbs_dim == 2 and rgbs_shape[1] != 3:
|
|
294
|
+
print("\033[91mThe shape of rgbs is invalid\033[0m")
|
|
295
|
+
return False
|
|
296
|
+
|
|
297
|
+
self.__gripper.set_rgb_stripe_command(
|
|
298
|
+
rgbs_int[:, 0].tolist(),
|
|
299
|
+
rgbs_int[:, 1].tolist(),
|
|
300
|
+
rgbs_int[:, 2].tolist(),
|
|
301
|
+
)
|
|
302
|
+
return True
|
|
303
|
+
|
|
304
|
+
def close(self):
|
|
305
|
+
if not self._working.is_set():
|
|
306
|
+
return
|
|
307
|
+
self._working.clear()
|
|
308
|
+
self.__gripper.set_rgb_stripe_command([255] * 6, [0] * 6, [0] * 6)
|
|
309
|
+
time.sleep(0.2)
|
|
310
|
+
self.__arm.stop()
|
|
311
|
+
self.__hex_api.close()
|
|
312
|
+
hex_log(HEX_LOG_LEVEL["info"], "HexRobotHello closed")
|
|
@@ -0,0 +1,84 @@
|
|
|
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
|
+
from ...zmq_base import hex_zmq_ts_now, HexRate
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
from collections import deque
|
|
14
|
+
|
|
15
|
+
NET_CONFIG = {
|
|
16
|
+
"ip": "127.0.0.1",
|
|
17
|
+
"port": 12345,
|
|
18
|
+
"realtime_mode": False,
|
|
19
|
+
"deque_maxlen": 10,
|
|
20
|
+
"client_timeout_ms": 200,
|
|
21
|
+
"server_timeout_ms": 1_000,
|
|
22
|
+
"server_num_workers": 4,
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
ROBOT_CONFIG = {
|
|
26
|
+
"device_ip": "172.18.8.161",
|
|
27
|
+
"device_port": 8439,
|
|
28
|
+
"control_hz": 250,
|
|
29
|
+
"sens_ts": True,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class HexRobotHelloClient(HexRobotClientBase):
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
net_config: dict = NET_CONFIG,
|
|
38
|
+
):
|
|
39
|
+
HexRobotClientBase.__init__(self, net_config)
|
|
40
|
+
self._rgbs_seq = 0
|
|
41
|
+
self._rgbs_queue = deque(maxlen=1)
|
|
42
|
+
self._wait_for_working()
|
|
43
|
+
|
|
44
|
+
def set_rgbs(self, rgbs: np.ndarray):
|
|
45
|
+
self._rgbs_queue.append(rgbs)
|
|
46
|
+
|
|
47
|
+
def _set_rgbs_inner(self, rgbs: np.ndarray) -> bool:
|
|
48
|
+
hdr, rgbs = self.request(
|
|
49
|
+
{
|
|
50
|
+
"cmd": "set_rgbs",
|
|
51
|
+
"ts": hex_zmq_ts_now(),
|
|
52
|
+
"args": self._rgbs_seq,
|
|
53
|
+
},
|
|
54
|
+
rgbs,
|
|
55
|
+
)
|
|
56
|
+
# print(f"set_rgbs seq: {self._rgbs_seq}")
|
|
57
|
+
try:
|
|
58
|
+
cmd = hdr["cmd"]
|
|
59
|
+
if cmd == "set_rgbs_ok":
|
|
60
|
+
self._rgbs_seq = (self._rgbs_seq + 1) % self._max_seq_num
|
|
61
|
+
return True
|
|
62
|
+
else:
|
|
63
|
+
return False
|
|
64
|
+
except KeyError:
|
|
65
|
+
print(f"\033[91m{hdr['cmd']} requires `cmd`\033[0m")
|
|
66
|
+
return False
|
|
67
|
+
except Exception as e:
|
|
68
|
+
print(f"\033[91mset_rgbs failed: {e}\033[0m")
|
|
69
|
+
return False
|
|
70
|
+
|
|
71
|
+
def _recv_loop(self):
|
|
72
|
+
rate = HexRate(2000)
|
|
73
|
+
while self._recv_flag:
|
|
74
|
+
hdr, states = self._get_states_inner()
|
|
75
|
+
if hdr is not None:
|
|
76
|
+
self._states_queue.append((hdr, states))
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
rgbs = self._rgbs_queue[-1]
|
|
80
|
+
_ = self._set_rgbs_inner(rgbs)
|
|
81
|
+
except IndexError:
|
|
82
|
+
pass
|
|
83
|
+
|
|
84
|
+
rate.sleep()
|
|
@@ -0,0 +1,114 @@
|
|
|
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
|
+
from collections import deque
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from ..robot_base import HexRobotServerBase
|
|
14
|
+
from .robot_hello import HexRobotHello
|
|
15
|
+
except (ImportError, ValueError):
|
|
16
|
+
import sys
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
this_file = Path(__file__).resolve()
|
|
19
|
+
project_root = this_file.parents[3]
|
|
20
|
+
if str(project_root) not in sys.path:
|
|
21
|
+
sys.path.insert(0, str(project_root))
|
|
22
|
+
from hex_zmq_servers.robot.robot_base import HexRobotServerBase
|
|
23
|
+
from hex_zmq_servers.robot.hello.robot_hello import HexRobotHello
|
|
24
|
+
|
|
25
|
+
NET_CONFIG = {
|
|
26
|
+
"ip": "127.0.0.1",
|
|
27
|
+
"port": 12345,
|
|
28
|
+
"realtime_mode": False,
|
|
29
|
+
"deque_maxlen": 10,
|
|
30
|
+
"client_timeout_ms": 200,
|
|
31
|
+
"server_timeout_ms": 1_000,
|
|
32
|
+
"server_num_workers": 4,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
ROBOT_CONFIG = {
|
|
36
|
+
"device_ip": "172.18.8.161",
|
|
37
|
+
"device_port": 8439,
|
|
38
|
+
"control_hz": 250,
|
|
39
|
+
"sens_ts": True,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class HexRobotHelloServer(HexRobotServerBase):
|
|
44
|
+
|
|
45
|
+
def __init__(
|
|
46
|
+
self,
|
|
47
|
+
net_config: dict = NET_CONFIG,
|
|
48
|
+
params_config: dict = ROBOT_CONFIG,
|
|
49
|
+
):
|
|
50
|
+
HexRobotServerBase.__init__(self, net_config)
|
|
51
|
+
self._rgbs_queue = deque(maxlen=1)
|
|
52
|
+
self._rgbs_seq = -1
|
|
53
|
+
|
|
54
|
+
# robot
|
|
55
|
+
self._device = HexRobotHello(params_config,
|
|
56
|
+
net_config.get("realtime_mode", False))
|
|
57
|
+
|
|
58
|
+
def work_loop(self):
|
|
59
|
+
try:
|
|
60
|
+
self._device.work_loop([
|
|
61
|
+
self._states_queue,
|
|
62
|
+
self._rgbs_queue,
|
|
63
|
+
self._stop_event,
|
|
64
|
+
])
|
|
65
|
+
finally:
|
|
66
|
+
self._device.close()
|
|
67
|
+
|
|
68
|
+
def _process_request(self, recv_hdr: dict, recv_buf: np.ndarray):
|
|
69
|
+
if recv_hdr["cmd"] == "is_working":
|
|
70
|
+
return self.no_ts_hdr(recv_hdr, self._device.is_working()), None
|
|
71
|
+
elif recv_hdr["cmd"] == "seq_clear":
|
|
72
|
+
return self.no_ts_hdr(recv_hdr, self._seq_clear()), None
|
|
73
|
+
elif recv_hdr["cmd"] == "get_dofs":
|
|
74
|
+
dofs = self._device.get_dofs()
|
|
75
|
+
return self.no_ts_hdr(recv_hdr, dofs is not None), dofs
|
|
76
|
+
elif recv_hdr["cmd"] == "get_limits":
|
|
77
|
+
limits = self._device.get_limits()
|
|
78
|
+
return self.no_ts_hdr(recv_hdr, limits is not None), limits
|
|
79
|
+
elif recv_hdr["cmd"] == "get_states":
|
|
80
|
+
return self._get_states(recv_hdr)
|
|
81
|
+
elif recv_hdr["cmd"] == "set_rgbs":
|
|
82
|
+
return self.__set_rgbs(recv_hdr, recv_buf)
|
|
83
|
+
else:
|
|
84
|
+
raise ValueError(f"unknown command: {recv_hdr['cmd']}")
|
|
85
|
+
|
|
86
|
+
def __set_rgbs(self, recv_hdr: dict, recv_buf: np.ndarray):
|
|
87
|
+
seq = recv_hdr.get("args", None)
|
|
88
|
+
if self._seq_clear_flag:
|
|
89
|
+
self._seq_clear_flag = False
|
|
90
|
+
self._rgbs_seq = -1
|
|
91
|
+
return self.no_ts_hdr(recv_hdr, False), None
|
|
92
|
+
|
|
93
|
+
if seq is not None:
|
|
94
|
+
delta = (seq - self._rgbs_seq) % self._max_seq_num
|
|
95
|
+
if delta >= 0 and delta < 1e6:
|
|
96
|
+
self._rgbs_seq = seq
|
|
97
|
+
self._rgbs_queue.append((recv_hdr["ts"], seq, recv_buf))
|
|
98
|
+
return self.no_ts_hdr(recv_hdr, True), None
|
|
99
|
+
else:
|
|
100
|
+
return self.no_ts_hdr(recv_hdr, False), None
|
|
101
|
+
else:
|
|
102
|
+
return self.no_ts_hdr(recv_hdr, False), None
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
if __name__ == "__main__":
|
|
106
|
+
import argparse, json
|
|
107
|
+
from hex_zmq_servers.zmq_base import hex_server_helper
|
|
108
|
+
|
|
109
|
+
parser = argparse.ArgumentParser()
|
|
110
|
+
parser.add_argument("--cfg", type=str, required=True)
|
|
111
|
+
args = parser.parse_args()
|
|
112
|
+
cfg = json.loads(args.cfg)
|
|
113
|
+
|
|
114
|
+
hex_server_helper(cfg, HexRobotHelloServer)
|
|
@@ -26,6 +26,8 @@ HEXARM_URDF_PATH_DICT = {
|
|
|
26
26
|
f"{urdf_dir}/archer_y6/gp100_p050_handle.urdf",
|
|
27
27
|
"archer_d6y_empty":
|
|
28
28
|
f"{urdf_dir}/archer_d6y/empty.urdf",
|
|
29
|
+
"archer_d6y_gp80":
|
|
30
|
+
f"{urdf_dir}/archer_d6y/gp80.urdf",
|
|
29
31
|
"archer_d6y_gp100":
|
|
30
32
|
f"{urdf_dir}/archer_d6y/gp100.urdf",
|
|
31
33
|
"archer_d6y_gp100_handle":
|
|
@@ -46,8 +48,6 @@ HEXARM_URDF_PATH_DICT = {
|
|
|
46
48
|
f"{urdf_dir}/archer_l6y/gp100_p050_handle.urdf",
|
|
47
49
|
"firefly_y6_empty":
|
|
48
50
|
f"{urdf_dir}/firefly_y6/empty.urdf",
|
|
49
|
-
"archer_d6y_gp80":
|
|
50
|
-
f"{urdf_dir}/archer_d6y/gp80.urdf",
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
__all__ = [
|
|
@@ -100,13 +100,16 @@ class HexRobotHexarm(HexRobotBase):
|
|
|
100
100
|
# variables init
|
|
101
101
|
arm_dofs = len(self.__arm)
|
|
102
102
|
self._dofs = [arm_dofs]
|
|
103
|
-
self._limits = np.array(self.__arm.get_joint_limits()).reshape(
|
|
103
|
+
self._limits = np.array(self.__arm.get_joint_limits()).reshape(
|
|
104
|
+
-1, 3, 2)
|
|
104
105
|
self.__motor_idx = {"robot_arm": np.arange(arm_dofs).tolist()}
|
|
105
106
|
if self.__gripper is not None:
|
|
106
107
|
gripper_dofs = len(self.__gripper)
|
|
107
108
|
self._dofs.append(gripper_dofs)
|
|
108
|
-
gripper_limits = np.array(
|
|
109
|
-
|
|
109
|
+
gripper_limits = np.array(
|
|
110
|
+
self.__gripper.get_joint_limits()).reshape(-1, 3, 2)
|
|
111
|
+
self._limits = np.concatenate([self._limits, gripper_limits],
|
|
112
|
+
axis=0)
|
|
110
113
|
self.__motor_idx["robot_gripper"] = (np.arange(gripper_dofs) +
|
|
111
114
|
arm_dofs).tolist()
|
|
112
115
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hex_zmq_servers
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: HEXFELLOW ZMQ Servers
|
|
5
5
|
Author-email: Dong Zhaorui <dzr159@gmail.com>
|
|
6
6
|
Maintainer-email: jecjune <zejun.chen@hexfellow.com>, Dong Zhaorui <dzr159@gmail.com>
|
|
@@ -23,7 +23,7 @@ Requires-Python: >=3.10
|
|
|
23
23
|
Description-Content-Type: text/markdown
|
|
24
24
|
License-File: LICENSE
|
|
25
25
|
Requires-Dist: pyzmq>=27.0.1
|
|
26
|
-
Requires-Dist: hex_device<1.4.0,>=1.3.
|
|
26
|
+
Requires-Dist: hex_device<1.4.0,>=1.3.17
|
|
27
27
|
Requires-Dist: hex_robo_utils<0.3.0,>=0.2.0
|
|
28
28
|
Requires-Dist: opencv-python>=4.2
|
|
29
29
|
Provides-Extra: berxel
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
hex_zmq_servers/__init__.py,sha256=
|
|
1
|
+
hex_zmq_servers/__init__.py,sha256=IB2KJ-5mS-tKv_nXnhc82uUvpfMlw8WoJLUnTtHI7zo,5957
|
|
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
4
|
hex_zmq_servers/zmq_base.py,sha256=DXLBSCT2VJQG8Y4aXCZEuKrawupOx3sk7H4crz9uXtc,17030
|
|
@@ -28,6 +28,7 @@ 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_hello.json,sha256=br_NVFQ6Q-ofZdL-9ZsVIeCpjyF3K9vEH6nEr7_cY3Q,407
|
|
31
32
|
hex_zmq_servers/config/robot_hexarm.json,sha256=01QovR0ibsDypVUKL4h_6EVeHG3I8QqfCc-jztH7Mm4,925
|
|
32
33
|
hex_zmq_servers/config/zmq_dummy.json,sha256=yuWindzdHoXv2-nlMEXY1e7W-_vWLYKwe-w8m7eBxWQ,251
|
|
33
34
|
hex_zmq_servers/mujoco/__init__.py,sha256=OKG7aJ2BACpob_DuAvikLiRo4M_3DO9Ffapwen87k_0,870
|
|
@@ -81,7 +82,7 @@ hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_right_helper_link.STL,sha
|
|
|
81
82
|
hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_right_link_1.STL,sha256=fjz04vqaBZGOb9GL6N4CVdIR1kOWrsdwh-jo7CRp9pg,28384
|
|
82
83
|
hex_zmq_servers/mujoco/e3_desktop/model/assets/gripper_right_link_2.STL,sha256=ucyn656VxBpRx3sshxLxMPJIUZfNfEQ90P-9b8sR0xg,80284
|
|
83
84
|
hex_zmq_servers/mujoco/e3_desktop/model/assets/table_link.STL,sha256=dqFXHRqjZSDyvYHCaJkbmYFsKngZRk1xjg_Zl2_jDc4,684
|
|
84
|
-
hex_zmq_servers/robot/__init__.py,sha256=
|
|
85
|
+
hex_zmq_servers/robot/__init__.py,sha256=0aDZMmkXCbuE37HuWLMF3d1fMEVgdYkMxxJecxZcjvY,1400
|
|
85
86
|
hex_zmq_servers/robot/robot_base.py,sha256=iau5aCLBKuPkRT3E1PTUfHxM2ji41pohVjO1T4Sdd8k,8564
|
|
86
87
|
hex_zmq_servers/robot/dummy/__init__.py,sha256=_lDtPH-JQ1ltPB8JzD7wLu77iwNOgEZ3fJkz8MNKXrw,517
|
|
87
88
|
hex_zmq_servers/robot/dummy/robot_dummy.py,sha256=_dTLajZCO5gjyw0KWedr8VsOTrtSkikcrJ8L2YpEwwQ,2781
|
|
@@ -91,8 +92,12 @@ hex_zmq_servers/robot/gello/__init__.py,sha256=7xSTc8ZB-bQODyEo6pzPz3ILZ1eAgVSsy
|
|
|
91
92
|
hex_zmq_servers/robot/gello/robot_gello.py,sha256=AwgMZcADtJR0NPjEYV4_p6v70RCFCwVgcT6ycE25Vts,13216
|
|
92
93
|
hex_zmq_servers/robot/gello/robot_gello_cli.py,sha256=1Ik9sDT8Xh2sXtqR46wbJCt7QhnhTKzJeCEzUiiFLtA,751
|
|
93
94
|
hex_zmq_servers/robot/gello/robot_gello_srv.py,sha256=5w95Rgt0p0vxaH2olX40V3h0CwVH8eEtx2U0iTO8cxM,2970
|
|
94
|
-
hex_zmq_servers/robot/
|
|
95
|
-
hex_zmq_servers/robot/
|
|
95
|
+
hex_zmq_servers/robot/hello/__init__.py,sha256=v9a7jJ9tNpUC-vzRNH7OA6YZZoWdnAtgZAoepXk7x8E,529
|
|
96
|
+
hex_zmq_servers/robot/hello/robot_hello.py,sha256=FVXHkLX95aWNbtHFBuNxHkAQwqyIw-0m7Nk5wLt2AB4,11006
|
|
97
|
+
hex_zmq_servers/robot/hello/robot_hello_cli.py,sha256=tnLIgpcMO4Cqvr2xZ1UOv-ytnOcwroYjjiMN3YP_Kg8,2309
|
|
98
|
+
hex_zmq_servers/robot/hello/robot_hello_srv.py,sha256=-vu86YpPmxM7K9JuynoZgaaN4udjxUiPucxv2NB8Qts,3780
|
|
99
|
+
hex_zmq_servers/robot/hexarm/__init__.py,sha256=0qUShNo7suei0u3raL5sNvgzDs0GtLR_Ra4WS3WfSEo,1915
|
|
100
|
+
hex_zmq_servers/robot/hexarm/robot_hexarm.py,sha256=mH4jBW92xuqUMbwD1Cc7OnOvpDf1SI2I7YIX3w2jngg,10899
|
|
96
101
|
hex_zmq_servers/robot/hexarm/robot_hexarm_cli.py,sha256=QbFiZFHnmyu5Wfwzj2fMRGqLdXBrS2HcpTGnG-BH_D8,904
|
|
97
102
|
hex_zmq_servers/robot/hexarm/robot_hexarm_srv.py,sha256=ANmqwl532d0cV9XCA29_55E-HGwrSmvSzQEDG-r-a2Y,2924
|
|
98
103
|
hex_zmq_servers/robot/hexarm/urdf/archer_d6y/empty.urdf,sha256=3qrJq2dQ77k2iz_N2hZQwudvqPsLR_-JUAeCE3M7twQ,7451
|
|
@@ -113,8 +118,8 @@ hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100_p050.urdf,sha256=Ayq0xhf8euYWD
|
|
|
113
118
|
hex_zmq_servers/robot/hexarm/urdf/archer_y6/gp100_p050_handle.urdf,sha256=UjeDE7bZgUMPGJlHOJMJofcEjQ2BRkShCUomxhKUPk0,7445
|
|
114
119
|
hex_zmq_servers/robot/hexarm/urdf/firefly_y6/empty.urdf,sha256=OWNmNHVNP0PvYY8s3jvrNBFAiMEYs3Zxr9NnV1APd8g,7601
|
|
115
120
|
hex_zmq_servers/robot/hexarm/urdf/firefly_y6/gp80.urdf,sha256=bauC1_kVDeym3yMAJoZppdiyyxJAmf1F4xF56zAdFSo,7650
|
|
116
|
-
hex_zmq_servers-1.0.
|
|
117
|
-
hex_zmq_servers-1.0.
|
|
118
|
-
hex_zmq_servers-1.0.
|
|
119
|
-
hex_zmq_servers-1.0.
|
|
120
|
-
hex_zmq_servers-1.0.
|
|
121
|
+
hex_zmq_servers-1.0.2.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
|
122
|
+
hex_zmq_servers-1.0.2.dist-info/METADATA,sha256=gbG4C9AlMKvNgSBdbqfjyQvKysllrqlDlB_CTK5quRs,6690
|
|
123
|
+
hex_zmq_servers-1.0.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
124
|
+
hex_zmq_servers-1.0.2.dist-info/top_level.txt,sha256=lPH1DfgMrQOe0Grh8zSZopf6LmnLvb_aStVmZ41PyAg,16
|
|
125
|
+
hex_zmq_servers-1.0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|