hex-zmq-servers 0.3.2__py3-none-any.whl → 0.3.4__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 +45 -20
- hex_zmq_servers/cam/__init__.py +29 -5
- hex_zmq_servers/cam/berxel/cam_berxel.py +8 -10
- hex_zmq_servers/cam/berxel/cam_berxel_cli.py +1 -0
- hex_zmq_servers/cam/cam_base.py +40 -10
- hex_zmq_servers/cam/dummy/cam_dummy.py +7 -7
- hex_zmq_servers/cam/dummy/cam_dummy_cli.py +1 -0
- hex_zmq_servers/cam/realsense/__init__.py +17 -0
- hex_zmq_servers/cam/realsense/cam_realsense.py +157 -0
- hex_zmq_servers/cam/realsense/cam_realsense_cli.py +31 -0
- hex_zmq_servers/cam/realsense/cam_realsense_srv.py +75 -0
- hex_zmq_servers/cam/rgb/__init__.py +17 -0
- hex_zmq_servers/cam/rgb/cam_rgb.py +133 -0
- hex_zmq_servers/cam/rgb/cam_rgb_cli.py +41 -0
- hex_zmq_servers/cam/rgb/cam_rgb_srv.py +75 -0
- hex_zmq_servers/config/cam_realsense.json +15 -0
- hex_zmq_servers/config/cam_rgb.json +26 -0
- hex_zmq_servers/config/mujoco_archer_y6.json +2 -1
- hex_zmq_servers/config/mujoco_e3_desktop.json +6 -1
- hex_zmq_servers/config/robot_hexarm.json +1 -1
- hex_zmq_servers/device_base.py +3 -2
- hex_zmq_servers/mujoco/archer_y6/model/robot.xml +6 -6
- hex_zmq_servers/mujoco/archer_y6/model/scene.xml +1 -1
- hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6.py +74 -39
- hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6_cli.py +42 -0
- hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6_srv.py +16 -14
- hex_zmq_servers/mujoco/e3_desktop/model/robot.xml +12 -12
- hex_zmq_servers/mujoco/e3_desktop/model/scene.xml +1 -1
- hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop.py +138 -70
- hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop_cli.py +148 -33
- hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop_srv.py +39 -35
- hex_zmq_servers/mujoco/mujoco_base.py +101 -64
- hex_zmq_servers/robot/dummy/robot_dummy.py +11 -7
- hex_zmq_servers/robot/dummy/robot_dummy_cli.py +1 -0
- hex_zmq_servers/robot/gello/robot_gello.py +11 -7
- hex_zmq_servers/robot/gello/robot_gello_cli.py +1 -0
- hex_zmq_servers/robot/hexarm/robot_hexarm.py +56 -22
- hex_zmq_servers/robot/hexarm/robot_hexarm_cli.py +1 -0
- hex_zmq_servers/robot/robot_base.py +40 -10
- hex_zmq_servers/zmq_base.py +97 -33
- {hex_zmq_servers-0.3.2.dist-info → hex_zmq_servers-0.3.4.dist-info}/METADATA +7 -6
- {hex_zmq_servers-0.3.2.dist-info → hex_zmq_servers-0.3.4.dist-info}/RECORD +45 -35
- {hex_zmq_servers-0.3.2.dist-info → hex_zmq_servers-0.3.4.dist-info}/WHEEL +0 -0
- {hex_zmq_servers-0.3.2.dist-info → hex_zmq_servers-0.3.4.dist-info}/licenses/LICENSE +0 -0
- {hex_zmq_servers-0.3.2.dist-info → hex_zmq_servers-0.3.4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding:utf-8 -*-
|
|
3
|
+
################################################################
|
|
4
|
+
# Copyright 2025 Dong Zhaorui. All rights reserved.
|
|
5
|
+
# Author: Dong Zhaorui 847235539@qq.com
|
|
6
|
+
# Date : 2025-09-12
|
|
7
|
+
################################################################
|
|
8
|
+
|
|
9
|
+
from .cam_rgb import HexCamRGB
|
|
10
|
+
from .cam_rgb_cli import HexCamRGBClient
|
|
11
|
+
from .cam_rgb_srv import HexCamRGBServer
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"HexCamRGB",
|
|
15
|
+
"HexCamRGBClient",
|
|
16
|
+
"HexCamRGBServer",
|
|
17
|
+
]
|
|
@@ -0,0 +1,133 @@
|
|
|
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 platform
|
|
10
|
+
import cv2
|
|
11
|
+
import threading
|
|
12
|
+
import numpy as np
|
|
13
|
+
from collections import deque
|
|
14
|
+
|
|
15
|
+
from ..cam_base import HexCamBase
|
|
16
|
+
from ...zmq_base import (
|
|
17
|
+
hex_zmq_ts_now,
|
|
18
|
+
HexRate,
|
|
19
|
+
)
|
|
20
|
+
from ...hex_launch import hex_log, HEX_LOG_LEVEL
|
|
21
|
+
|
|
22
|
+
CAMERA_CONFIG = {
|
|
23
|
+
"cam_path": "/dev/video0",
|
|
24
|
+
"resolution": [640, 480],
|
|
25
|
+
"crop": [0, 640, 0, 480],
|
|
26
|
+
"exposure": 100,
|
|
27
|
+
"temperature": 4000,
|
|
28
|
+
"frame_rate": 30,
|
|
29
|
+
"sens_ts": True,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class HexCamRGB(HexCamBase):
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
camera_config: dict = CAMERA_CONFIG,
|
|
38
|
+
):
|
|
39
|
+
HexCamBase.__init__(self)
|
|
40
|
+
|
|
41
|
+
try:
|
|
42
|
+
self.__cam_path = camera_config["cam_path"]
|
|
43
|
+
self.__resolution = camera_config["resolution"]
|
|
44
|
+
self.__crop = camera_config["crop"]
|
|
45
|
+
self.__exposure = camera_config["exposure"]
|
|
46
|
+
self.__temperature = camera_config["temperature"]
|
|
47
|
+
self.__frame_rate = camera_config["frame_rate"]
|
|
48
|
+
self.__sens_ts = camera_config["sens_ts"]
|
|
49
|
+
except KeyError as ke:
|
|
50
|
+
missing_key = ke.args[0]
|
|
51
|
+
raise ValueError(
|
|
52
|
+
f"camera_config is not valid, missing key: {missing_key}")
|
|
53
|
+
|
|
54
|
+
# variables
|
|
55
|
+
# camera variables
|
|
56
|
+
self.__cap = cv2.VideoCapture(self.__cam_path)
|
|
57
|
+
# camera variables
|
|
58
|
+
self.__intri = np.zeros(4)
|
|
59
|
+
|
|
60
|
+
# open device
|
|
61
|
+
self.__cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"MJPG"))
|
|
62
|
+
self.__cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.__resolution[0])
|
|
63
|
+
self.__cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.__resolution[1])
|
|
64
|
+
self.__cap.set(cv2.CAP_PROP_FPS, self.__frame_rate)
|
|
65
|
+
ae_open = 1.0 if platform.system() == "Windows" else 3.0
|
|
66
|
+
ae_close = 0.0 if platform.system() == "Windows" else 1.0
|
|
67
|
+
ae_value = 10000 * (2**self.__exposure) if platform.system(
|
|
68
|
+
) == "Windows" else self.__exposure
|
|
69
|
+
self.__cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, ae_open)
|
|
70
|
+
if self.__exposure != 0:
|
|
71
|
+
self.__cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, ae_close)
|
|
72
|
+
self.__cap.set(cv2.CAP_PROP_EXPOSURE, ae_value)
|
|
73
|
+
self.__cap.set(cv2.CAP_PROP_AUTO_WB, 1)
|
|
74
|
+
if self.__temperature != 0:
|
|
75
|
+
self.__cap.set(cv2.CAP_PROP_AUTO_WB, 0)
|
|
76
|
+
self.__cap.set(cv2.CAP_PROP_WB_TEMPERATURE, self.__temperature)
|
|
77
|
+
|
|
78
|
+
print("#############################")
|
|
79
|
+
print(
|
|
80
|
+
f"# Resolution: ({self.__cap.get(cv2.CAP_PROP_FRAME_WIDTH)}, {self.__cap.get(cv2.CAP_PROP_FRAME_HEIGHT)})"
|
|
81
|
+
)
|
|
82
|
+
print(f"# FPS: {self.__cap.get(cv2.CAP_PROP_FPS)}")
|
|
83
|
+
four_cc_int = int(self.__cap.get(cv2.CAP_PROP_FOURCC))
|
|
84
|
+
four_cc_str = chr(four_cc_int & 0xff) + chr(
|
|
85
|
+
(four_cc_int >> 8) & 0xff) + chr((four_cc_int >> 16) & 0xff) + chr(
|
|
86
|
+
(four_cc_int >> 24) & 0xff)
|
|
87
|
+
print(f"# FourCC: {four_cc_str}")
|
|
88
|
+
print(f"# Auto Exposure: {self.__cap.get(cv2.CAP_PROP_AUTO_EXPOSURE)}")
|
|
89
|
+
print(f"# Exposure: {self.__cap.get(cv2.CAP_PROP_EXPOSURE)}")
|
|
90
|
+
print(f"# Auto WB: {self.__cap.get(cv2.CAP_PROP_AUTO_WB)}")
|
|
91
|
+
print(
|
|
92
|
+
f"# WB Temperature: {self.__cap.get(cv2.CAP_PROP_WB_TEMPERATURE)}")
|
|
93
|
+
print("#############################")
|
|
94
|
+
|
|
95
|
+
# start work loop
|
|
96
|
+
self._working.set()
|
|
97
|
+
|
|
98
|
+
def get_intri(self) -> np.ndarray:
|
|
99
|
+
self._wait_for_working()
|
|
100
|
+
return self.__intri
|
|
101
|
+
|
|
102
|
+
def work_loop(self, hex_queues: list[deque | threading.Event]):
|
|
103
|
+
rgb_queue = hex_queues[0]
|
|
104
|
+
depth_queue = hex_queues[1]
|
|
105
|
+
stop_event = hex_queues[2]
|
|
106
|
+
|
|
107
|
+
rgb_count = 0
|
|
108
|
+
depth_queue.append((hex_zmq_ts_now(), 0,
|
|
109
|
+
np.zeros((self.__resolution[1], self.__resolution[0]),
|
|
110
|
+
dtype=np.uint16)))
|
|
111
|
+
rate = HexRate(self.__frame_rate * 5)
|
|
112
|
+
while self._working.is_set() and not stop_event.is_set():
|
|
113
|
+
# read frame
|
|
114
|
+
ret, frame = self.__cap.read()
|
|
115
|
+
|
|
116
|
+
# collect rgb frame
|
|
117
|
+
if ret:
|
|
118
|
+
frame = frame[self.__crop[2]:self.__crop[3],
|
|
119
|
+
self.__crop[0]:self.__crop[1]]
|
|
120
|
+
rgb_queue.append((hex_zmq_ts_now(), rgb_count, frame))
|
|
121
|
+
rgb_count = (rgb_count + 1) % self._max_seq_num
|
|
122
|
+
|
|
123
|
+
rate.sleep()
|
|
124
|
+
|
|
125
|
+
# close
|
|
126
|
+
self.close()
|
|
127
|
+
|
|
128
|
+
def close(self):
|
|
129
|
+
if not self._working.is_set():
|
|
130
|
+
return
|
|
131
|
+
self._working.clear()
|
|
132
|
+
self.__cap.release()
|
|
133
|
+
hex_log(HEX_LOG_LEVEL["info"], "HexCamRGB closed")
|
|
@@ -0,0 +1,41 @@
|
|
|
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 ..cam_base import HexCamClientBase
|
|
10
|
+
from ...zmq_base import HexRate
|
|
11
|
+
|
|
12
|
+
NET_CONFIG = {
|
|
13
|
+
"ip": "127.0.0.1",
|
|
14
|
+
"port": 12345,
|
|
15
|
+
"client_timeout_ms": 200,
|
|
16
|
+
"server_timeout_ms": 1_000,
|
|
17
|
+
"server_num_workers": 4,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class HexCamRGBClient(HexCamClientBase):
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
net_config: dict = NET_CONFIG,
|
|
26
|
+
):
|
|
27
|
+
HexCamClientBase.__init__(self, net_config)
|
|
28
|
+
self._wait_for_working()
|
|
29
|
+
|
|
30
|
+
def get_intri(self):
|
|
31
|
+
intri_hdr, intri = self.request({"cmd": "get_intri"})
|
|
32
|
+
return intri_hdr, intri
|
|
33
|
+
|
|
34
|
+
def _recv_loop(self):
|
|
35
|
+
rate = HexRate(200)
|
|
36
|
+
while self._recv_flag:
|
|
37
|
+
hdr, img = self._get_rgb_inner()
|
|
38
|
+
if hdr is not None:
|
|
39
|
+
self._rgb_queue.append((hdr, img))
|
|
40
|
+
rate.sleep()
|
|
41
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding:utf-8 -*-
|
|
3
|
+
################################################################
|
|
4
|
+
# Copyright 2025 Dong Zhaorui. All rights reserved.
|
|
5
|
+
# Author: Dong Zhaorui 847235539@qq.com
|
|
6
|
+
# Date : 2025-09-12
|
|
7
|
+
################################################################
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from ..cam_base import HexCamServerBase
|
|
13
|
+
from .cam_rgb import HexCamRGB
|
|
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.cam.cam_base import HexCamServerBase
|
|
22
|
+
from hex_zmq_servers.cam.rgb.cam_rgb import HexCamRGB
|
|
23
|
+
|
|
24
|
+
NET_CONFIG = {
|
|
25
|
+
"ip": "127.0.0.1",
|
|
26
|
+
"port": 12345,
|
|
27
|
+
"client_timeout_ms": 200,
|
|
28
|
+
"server_timeout_ms": 1_000,
|
|
29
|
+
"server_num_workers": 4,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
CAMERA_CONFIG = {
|
|
33
|
+
"cam_path": "/dev/video0",
|
|
34
|
+
"resolution": [640, 480],
|
|
35
|
+
"frame_rate": 30,
|
|
36
|
+
"sens_ts": True,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class HexCamRGBServer(HexCamServerBase):
|
|
41
|
+
|
|
42
|
+
def __init__(
|
|
43
|
+
self,
|
|
44
|
+
net_config: dict = NET_CONFIG,
|
|
45
|
+
params_config: dict = CAMERA_CONFIG,
|
|
46
|
+
):
|
|
47
|
+
HexCamServerBase.__init__(self, net_config)
|
|
48
|
+
|
|
49
|
+
# camera
|
|
50
|
+
self._device = HexCamRGB(params_config)
|
|
51
|
+
|
|
52
|
+
def _process_request(self, recv_hdr: dict, recv_buf: np.ndarray):
|
|
53
|
+
if recv_hdr["cmd"] == "is_working":
|
|
54
|
+
return self.no_ts_hdr(recv_hdr, self._device.is_working()), None
|
|
55
|
+
elif recv_hdr["cmd"] == "get_intri":
|
|
56
|
+
intri = self._device.get_intri()
|
|
57
|
+
return self.no_ts_hdr(recv_hdr, intri is not None), intri
|
|
58
|
+
elif recv_hdr["cmd"] == "get_rgb":
|
|
59
|
+
return self._get_frame(recv_hdr, False)
|
|
60
|
+
elif recv_hdr["cmd"] == "get_depth":
|
|
61
|
+
return self._get_frame(recv_hdr, True)
|
|
62
|
+
else:
|
|
63
|
+
raise ValueError(f"unknown command: {recv_hdr['cmd']}")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
if __name__ == "__main__":
|
|
67
|
+
import argparse, json
|
|
68
|
+
from hex_zmq_servers.zmq_base import hex_server_helper
|
|
69
|
+
|
|
70
|
+
parser = argparse.ArgumentParser()
|
|
71
|
+
parser.add_argument("--cfg", type=str, required=True)
|
|
72
|
+
args = parser.parse_args()
|
|
73
|
+
cfg = json.loads(args.cfg)
|
|
74
|
+
|
|
75
|
+
hex_server_helper(cfg, HexCamRGBServer)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"net": {
|
|
3
|
+
"ip": "127.0.0.1",
|
|
4
|
+
"port": 12345,
|
|
5
|
+
"client_timeout_ms": 200,
|
|
6
|
+
"server_timeout_ms": 1000,
|
|
7
|
+
"server_num_workers": 4
|
|
8
|
+
},
|
|
9
|
+
"params": {
|
|
10
|
+
"serial_number": "243422073194",
|
|
11
|
+
"resolution": [640, 480],
|
|
12
|
+
"frame_rate": 30,
|
|
13
|
+
"sens_ts": true
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"net": {
|
|
3
|
+
"ip": "127.0.0.1",
|
|
4
|
+
"port": 12345,
|
|
5
|
+
"client_timeout_ms": 200,
|
|
6
|
+
"server_timeout_ms": 1000,
|
|
7
|
+
"server_num_workers": 4
|
|
8
|
+
},
|
|
9
|
+
"params": {
|
|
10
|
+
"cam_path": "/dev/video0",
|
|
11
|
+
"resolution": [
|
|
12
|
+
640,
|
|
13
|
+
480
|
|
14
|
+
],
|
|
15
|
+
"crop": [
|
|
16
|
+
0,
|
|
17
|
+
640,
|
|
18
|
+
0,
|
|
19
|
+
480
|
|
20
|
+
],
|
|
21
|
+
"exposure": 70,
|
|
22
|
+
"temperature": 0,
|
|
23
|
+
"frame_rate": 30,
|
|
24
|
+
"sens_ts": true
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"server_num_workers": 4
|
|
8
8
|
},
|
|
9
9
|
"params": {
|
|
10
|
-
"states_rate":
|
|
10
|
+
"states_rate": 1000,
|
|
11
11
|
"img_rate": 30,
|
|
12
12
|
"tau_ctrl": false,
|
|
13
13
|
"mit_kp": [
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
0.31,
|
|
29
29
|
1.0
|
|
30
30
|
],
|
|
31
|
+
"cam_type": "empty",
|
|
31
32
|
"headless": false,
|
|
32
33
|
"sens_ts": true
|
|
33
34
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"server_num_workers": 4
|
|
8
8
|
},
|
|
9
9
|
"params": {
|
|
10
|
-
"states_rate":
|
|
10
|
+
"states_rate": 1000,
|
|
11
11
|
"img_rate": 30,
|
|
12
12
|
"tau_ctrl": false,
|
|
13
13
|
"mit_kp": [
|
|
@@ -28,6 +28,11 @@
|
|
|
28
28
|
0.31,
|
|
29
29
|
1.0
|
|
30
30
|
],
|
|
31
|
+
"cam_type": [
|
|
32
|
+
"empty",
|
|
33
|
+
"empty",
|
|
34
|
+
"empty"
|
|
35
|
+
],
|
|
31
36
|
"headless": false,
|
|
32
37
|
"sens_ts": true
|
|
33
38
|
}
|
hex_zmq_servers/device_base.py
CHANGED
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
################################################################
|
|
8
8
|
|
|
9
9
|
import threading
|
|
10
|
+
from collections import deque
|
|
10
11
|
from abc import ABC, abstractmethod
|
|
11
12
|
|
|
12
|
-
from .zmq_base import MAX_SEQ_NUM
|
|
13
|
+
from .zmq_base import MAX_SEQ_NUM
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class HexDeviceBase(ABC):
|
|
@@ -32,7 +33,7 @@ class HexDeviceBase(ABC):
|
|
|
32
33
|
self._working.wait(0.1)
|
|
33
34
|
|
|
34
35
|
@abstractmethod
|
|
35
|
-
def work_loop(self,
|
|
36
|
+
def work_loop(self, hex_queues: list[deque | threading.Event]):
|
|
36
37
|
raise NotImplementedError(
|
|
37
38
|
"`work_loop` should be implemented by the child class")
|
|
38
39
|
|
|
@@ -6,37 +6,37 @@
|
|
|
6
6
|
# link 1
|
|
7
7
|
<body name="link_1" pos="0 0 0.0665">
|
|
8
8
|
<inertial pos="0.008 -0.0023 0.0213" quat="0.707107 0.707107 0 0" mass="0.2154" diaginertia="0.0003 0.0003 0.0002"/>
|
|
9
|
-
<joint name="joint_1" pos="0 0 0" axis="0 0 1" range="-2.7 2.7" limited="true" armature="0.
|
|
9
|
+
<joint name="joint_1" pos="0 0 0" axis="0 0 1" range="-2.7 2.7" limited="true" armature="0.01" damping="0.1" frictionloss="0.5"/>
|
|
10
10
|
<geom type="mesh" rgba="0.92549 0.92549 0.92549 1" mesh="arm_link_1"/>
|
|
11
11
|
|
|
12
12
|
# link 2
|
|
13
13
|
<body name="link_2" pos="0.02 0 0.045">
|
|
14
14
|
<inertial pos="0.0001 -0.0028 0.1317" quat="0.999789 0.0205404 0 0" mass="1.3123" diaginertia="0.018 0.0177288 0.000671225"/>
|
|
15
|
-
<joint name="joint_2" pos="0 0 0" axis="0 1 0" range="-1.57 2.09" limited="true" armature="0.
|
|
15
|
+
<joint name="joint_2" pos="0 0 0" axis="0 1 0" range="-1.57 2.09" limited="true" armature="0.01" damping="0.1" frictionloss="0.5"/>
|
|
16
16
|
<geom type="mesh" rgba="1 1 1 1" mesh="arm_link_2"/>
|
|
17
17
|
|
|
18
18
|
# link 3
|
|
19
19
|
<body name="link_3" pos="0 0 0.264">
|
|
20
20
|
<inertial pos="-0.051 0.0008 0.1447" quat="0.996909 0.0323182 -0.0688403 -0.019747" mass="1.1083" diaginertia="0.0115968 0.0112369 0.00136632"/>
|
|
21
|
-
<joint name="joint_3" pos="0 0 0" axis="0 1 0" range="0 3.14" limited="true" armature="0.
|
|
21
|
+
<joint name="joint_3" pos="0 0 0" axis="0 1 0" range="0 3.14" limited="true" armature="0.01" damping="0.1" frictionloss="0.5"/>
|
|
22
22
|
<geom type="mesh" rgba="1 1 1 1" mesh="arm_link_3"/>
|
|
23
23
|
|
|
24
24
|
# link 4
|
|
25
25
|
<body name="link_4" pos="-0.06 0 0.245">
|
|
26
26
|
<inertial pos="-0.0597 -0.001 0.0572" quat="0 0.92388 0 0.382683" mass="0.5398" diaginertia="0.0011 0.001 0.0005"/>
|
|
27
|
-
<joint name="joint_4" pos="0 0 0" axis="0 1 0" range="-1.57 1.57" limited="true" armature="0.
|
|
27
|
+
<joint name="joint_4" pos="0 0 0" axis="0 1 0" range="-1.57 1.57" limited="true" armature="0.01" damping="0.02" frictionloss="0.1"/>
|
|
28
28
|
<geom type="mesh" rgba="0.792157 0.792157 0.792157 1" mesh="arm_link_4"/>
|
|
29
29
|
|
|
30
30
|
# link 5
|
|
31
31
|
<body name="link_5" pos="-0.0553 0 0.070">
|
|
32
32
|
<inertial pos="0.0292 0.0001 -0.0107" quat="0.707107 0 0 0.707107" mass="0.3984" diaginertia="0.0003 0.0002 0.0002"/>
|
|
33
|
-
<joint name="joint_5" pos="0 0 0" axis="-1 0 0" range="-1.57 1.57" limited="true" armature="0.
|
|
33
|
+
<joint name="joint_5" pos="0 0 0" axis="-1 0 0" range="-1.57 1.57" limited="true" armature="0.01" damping="0.02" frictionloss="0.1"/>
|
|
34
34
|
<geom type="mesh" rgba="0.898039 0.917647 0.929412 1" mesh="arm_link_5"/>
|
|
35
35
|
|
|
36
36
|
# gripper base link
|
|
37
37
|
<body name="gripper_base_link" pos="0.0553 0 0.029" quat="0.707107 0.0 -0.707107 0.0">
|
|
38
38
|
<inertial pos="-0.0139 0.0001 0.0553" quat="0.567843 0.421372 0.421372 0.567843" mass="0.7651" diaginertia="0.0021 0.00143028 0.00106972"/>
|
|
39
|
-
<joint name="joint_6" pos="0 0 0" axis="1 0 0" range="-1.57 1.57" limited="true" armature="0.
|
|
39
|
+
<joint name="joint_6" pos="0 0 0" axis="1 0 0" range="-1.57 1.57" limited="true" armature="0.01" damping="0.02" frictionloss="0.1"/>
|
|
40
40
|
<geom type="mesh" rgba="1 1 1 1" mesh="gripper_base_link"/>
|
|
41
41
|
<geom pos="0.04 0 0.12" quat="0.6830127 0.6830127 0.1830127 -0.1830127" type="mesh" rgba="0.1 0.1 0.1 1" mesh="camera_link" />
|
|
42
42
|
<camera name="end_camera" pos="0.066 0 0.105" quat="0.8660254 0.0 -0.5 0.0" fovy="50"/>
|
|
@@ -11,22 +11,24 @@ import copy
|
|
|
11
11
|
import threading
|
|
12
12
|
import cv2
|
|
13
13
|
import numpy as np
|
|
14
|
+
from collections import deque
|
|
14
15
|
|
|
15
16
|
import mujoco
|
|
16
17
|
from mujoco import viewer
|
|
17
18
|
|
|
18
19
|
from ..mujoco_base import HexMujocoBase
|
|
19
20
|
from ...zmq_base import (
|
|
21
|
+
hex_ns_now,
|
|
20
22
|
hex_zmq_ts_now,
|
|
23
|
+
ns_to_hex_zmq_ts,
|
|
21
24
|
hex_zmq_ts_delta_ms,
|
|
22
25
|
HexRate,
|
|
23
|
-
HexSafeValue,
|
|
24
26
|
)
|
|
25
27
|
from ...hex_launch import hex_log, HEX_LOG_LEVEL
|
|
26
28
|
from hex_robo_utils import HexCtrlUtilMitJoint as CtrlUtil
|
|
27
29
|
|
|
28
30
|
MUJOCO_CONFIG = {
|
|
29
|
-
"states_rate":
|
|
31
|
+
"states_rate": 1000,
|
|
30
32
|
"img_rate": 30,
|
|
31
33
|
"tau_ctrl": False,
|
|
32
34
|
"mit_kp": [200.0, 200.0, 200.0, 75.0, 15.0, 15.0, 20.0],
|
|
@@ -34,6 +36,12 @@ MUJOCO_CONFIG = {
|
|
|
34
36
|
"headless": False,
|
|
35
37
|
"sens_ts": True,
|
|
36
38
|
}
|
|
39
|
+
CAMERA_CONFIG = {
|
|
40
|
+
"empty": (False, False),
|
|
41
|
+
"rgb": (True, False),
|
|
42
|
+
"berxel": (True, True),
|
|
43
|
+
"realsense": (True, True),
|
|
44
|
+
}
|
|
37
45
|
|
|
38
46
|
|
|
39
47
|
class HexMujocoArcherY6(HexMujocoBase):
|
|
@@ -50,6 +58,7 @@ class HexMujocoArcherY6(HexMujocoBase):
|
|
|
50
58
|
self.__tau_ctrl = mujoco_config["tau_ctrl"]
|
|
51
59
|
self.__mit_kp = mujoco_config["mit_kp"]
|
|
52
60
|
self.__mit_kd = mujoco_config["mit_kd"]
|
|
61
|
+
self.__cam_type = mujoco_config["cam_type"]
|
|
53
62
|
self.__headless = mujoco_config["headless"]
|
|
54
63
|
self.__sens_ts = mujoco_config["sens_ts"]
|
|
55
64
|
except KeyError as ke:
|
|
@@ -95,20 +104,31 @@ class HexMujocoArcherY6(HexMujocoBase):
|
|
|
95
104
|
self.__states_trig_thresh = int(self.__sim_rate / states_rate)
|
|
96
105
|
|
|
97
106
|
# camera init
|
|
98
|
-
width, height = 640, 400
|
|
99
|
-
fovy_rad = self.__model.cam_fovy[0] * np.pi / 180.0
|
|
100
|
-
focal = 0.5 * height / np.tan(fovy_rad / 2.0)
|
|
101
|
-
self._intri = np.array([focal, focal, height / 2, height / 2])
|
|
102
|
-
self.__rgb_cam = mujoco.Renderer(self.__model, height, width)
|
|
103
|
-
self.__depth_cam = mujoco.Renderer(self.__model, height, width)
|
|
104
|
-
self.__depth_cam.enable_depth_rendering()
|
|
105
107
|
self.__img_trig_thresh = int(self.__sim_rate / img_rate)
|
|
108
|
+
self.__width, self.__height = 640, 400
|
|
109
|
+
fovy_rad = self.__model.cam_fovy[0] * np.pi / 180.0
|
|
110
|
+
focal = 0.5 * self.__height / np.tan(fovy_rad / 2.0)
|
|
111
|
+
self._intri = np.array(
|
|
112
|
+
[focal, focal, self.__height / 2, self.__height / 2])
|
|
113
|
+
self.__use_rgb, self.__use_depth = CAMERA_CONFIG.get(
|
|
114
|
+
self.__cam_type, (False, False))
|
|
115
|
+
self.__rgb_cam, self.__depth_cam = None, None
|
|
116
|
+
if self.__use_rgb:
|
|
117
|
+
self.__rgb_cam = mujoco.Renderer(self.__model, self.__height,
|
|
118
|
+
self.__width)
|
|
119
|
+
if self.__use_depth:
|
|
120
|
+
self.__depth_cam = mujoco.Renderer(self.__model, self.__height,
|
|
121
|
+
self.__width)
|
|
122
|
+
self.__depth_cam.enable_depth_rendering()
|
|
106
123
|
|
|
107
124
|
# viewer init
|
|
108
125
|
mujoco.mj_forward(self.__model, self.__data)
|
|
109
126
|
if not self.__headless:
|
|
110
127
|
self.__viewer = viewer.launch_passive(self.__model, self.__data)
|
|
111
128
|
|
|
129
|
+
# time init
|
|
130
|
+
self.__bias_ns = hex_ns_now() - self.__data.time * 1_000_000_000
|
|
131
|
+
|
|
112
132
|
# start work loop
|
|
113
133
|
self._working.set()
|
|
114
134
|
|
|
@@ -124,13 +144,13 @@ class HexMujocoArcherY6(HexMujocoBase):
|
|
|
124
144
|
self.__viewer.sync()
|
|
125
145
|
return True
|
|
126
146
|
|
|
127
|
-
def work_loop(self,
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
stop_event =
|
|
147
|
+
def work_loop(self, hex_queues: list[deque | threading.Event]):
|
|
148
|
+
states_robot_queue = hex_queues[0]
|
|
149
|
+
states_obj_queue = hex_queues[1]
|
|
150
|
+
cmds_robot_queue = hex_queues[2]
|
|
151
|
+
rgb_queue = hex_queues[3]
|
|
152
|
+
depth_queue = hex_queues[4]
|
|
153
|
+
stop_event = hex_queues[5]
|
|
134
154
|
|
|
135
155
|
last_states_ts = {"s": 0, "ns": 0}
|
|
136
156
|
states_robot_count = 0
|
|
@@ -138,11 +158,18 @@ class HexMujocoArcherY6(HexMujocoBase):
|
|
|
138
158
|
last_cmds_robot_seq = -1
|
|
139
159
|
rgb_count = 0
|
|
140
160
|
depth_count = 0
|
|
161
|
+
cmds_robot = None
|
|
141
162
|
|
|
142
163
|
rate = HexRate(self.__sim_rate)
|
|
143
164
|
states_trig_count = 0
|
|
144
165
|
img_trig_count = 0
|
|
145
|
-
|
|
166
|
+
init_ts = self.__mujoco_ts() if self.__sens_ts else hex_zmq_ts_now()
|
|
167
|
+
rgb_queue.append((init_ts, 0,
|
|
168
|
+
np.zeros((self.__height, self.__width, 3),
|
|
169
|
+
dtype=np.uint8)))
|
|
170
|
+
depth_queue.append((init_ts, 0,
|
|
171
|
+
np.zeros((self.__height, self.__width),
|
|
172
|
+
dtype=np.uint16)))
|
|
146
173
|
while self._working.is_set() and not stop_event.is_set():
|
|
147
174
|
states_trig_count += 1
|
|
148
175
|
if states_trig_count >= self.__states_trig_thresh:
|
|
@@ -151,45 +178,53 @@ class HexMujocoArcherY6(HexMujocoBase):
|
|
|
151
178
|
# states
|
|
152
179
|
ts, states_robot, states_obj = self.__get_states()
|
|
153
180
|
if states_robot is not None:
|
|
154
|
-
if hex_zmq_ts_delta_ms(ts, last_states_ts) >
|
|
181
|
+
if hex_zmq_ts_delta_ms(ts, last_states_ts) > 1e-6:
|
|
155
182
|
last_states_ts = ts
|
|
156
183
|
|
|
157
184
|
# states robot
|
|
158
|
-
|
|
185
|
+
states_robot_queue.append(
|
|
159
186
|
(ts, states_robot_count, states_robot))
|
|
160
187
|
states_robot_count = (states_robot_count +
|
|
161
188
|
1) % self._max_seq_num
|
|
162
189
|
|
|
163
190
|
# states obj
|
|
164
|
-
|
|
191
|
+
states_obj_queue.append(
|
|
165
192
|
(ts, states_obj_count, states_obj))
|
|
166
193
|
states_obj_count = (states_obj_count +
|
|
167
194
|
1) % self._max_seq_num
|
|
168
195
|
|
|
169
196
|
# cmds
|
|
170
|
-
cmds_robot_pack =
|
|
197
|
+
cmds_robot_pack = None
|
|
198
|
+
try:
|
|
199
|
+
cmds_robot_pack = cmds_robot_queue.popleft()
|
|
200
|
+
except IndexError:
|
|
201
|
+
pass
|
|
171
202
|
if cmds_robot_pack is not None:
|
|
172
|
-
ts, seq,
|
|
203
|
+
ts, seq, cmds_robot_get = cmds_robot_pack
|
|
173
204
|
if seq != last_cmds_robot_seq:
|
|
174
205
|
last_cmds_robot_seq = seq
|
|
175
206
|
if hex_zmq_ts_delta_ms(hex_zmq_ts_now(), ts) < 200.0:
|
|
176
|
-
|
|
207
|
+
cmds_robot = cmds_robot_get.copy()
|
|
208
|
+
if cmds_robot is not None:
|
|
209
|
+
self.__set_cmds(cmds_robot)
|
|
177
210
|
|
|
178
211
|
img_trig_count += 1
|
|
179
212
|
if img_trig_count >= self.__img_trig_thresh:
|
|
180
213
|
img_trig_count = 0
|
|
181
214
|
|
|
182
215
|
# rgb
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
216
|
+
if self.__use_rgb:
|
|
217
|
+
ts, rgb_img = self.__get_rgb()
|
|
218
|
+
if rgb_img is not None:
|
|
219
|
+
rgb_queue.append((ts, rgb_count, rgb_img))
|
|
220
|
+
rgb_count = (rgb_count + 1) % self._max_seq_num
|
|
187
221
|
|
|
188
222
|
# depth
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
223
|
+
if self.__use_depth:
|
|
224
|
+
ts, depth_img = self.__get_depth()
|
|
225
|
+
if depth_img is not None:
|
|
226
|
+
depth_queue.append((ts, depth_count, depth_img))
|
|
227
|
+
depth_count = (depth_count + 1) % self._max_seq_num
|
|
193
228
|
|
|
194
229
|
# mujoco step
|
|
195
230
|
mujoco.mj_step(self.__model, self.__data)
|
|
@@ -236,7 +271,8 @@ class HexMujocoArcherY6(HexMujocoBase):
|
|
|
236
271
|
cmd_kp = cmds[:, 3].copy()
|
|
237
272
|
cmd_kd = cmds[:, 4].copy()
|
|
238
273
|
else:
|
|
239
|
-
raise ValueError(
|
|
274
|
+
raise ValueError(
|
|
275
|
+
f"The shape of cmds is invalid: {cmds.shape}")
|
|
240
276
|
else:
|
|
241
277
|
raise ValueError(f"The shape of cmds is invalid: {cmds.shape}")
|
|
242
278
|
tar_pos = self._apply_pos_limits(
|
|
@@ -272,18 +308,17 @@ class HexMujocoArcherY6(HexMujocoBase):
|
|
|
272
308
|
), depth_img
|
|
273
309
|
|
|
274
310
|
def __mujoco_ts(self):
|
|
275
|
-
mujoco_ts = self.__data.time
|
|
276
|
-
return
|
|
277
|
-
"s": int(mujoco_ts // 1),
|
|
278
|
-
"ns": int((mujoco_ts % 1) * 1_000_000_000),
|
|
279
|
-
}
|
|
311
|
+
mujoco_ts = self.__data.time * 1_000_000_000 + self.__bias_ns
|
|
312
|
+
return ns_to_hex_zmq_ts(mujoco_ts)
|
|
280
313
|
|
|
281
314
|
def close(self):
|
|
282
315
|
if not self._working.is_set():
|
|
283
316
|
return
|
|
284
317
|
self._working.clear()
|
|
285
|
-
self.__rgb_cam
|
|
286
|
-
|
|
318
|
+
if self.__rgb_cam is not None:
|
|
319
|
+
self.__rgb_cam.close()
|
|
320
|
+
if self.__depth_cam is not None:
|
|
321
|
+
self.__depth_cam.close()
|
|
287
322
|
if not self.__headless:
|
|
288
323
|
self.__viewer.close()
|
|
289
324
|
hex_log(HEX_LOG_LEVEL["info"], "HexMujocoArcherY6 closed")
|