hex-zmq-servers 0.3.3__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.
Files changed (37) hide show
  1. hex_zmq_servers/__init__.py +5 -3
  2. hex_zmq_servers/cam/berxel/cam_berxel.py +8 -10
  3. hex_zmq_servers/cam/berxel/cam_berxel_cli.py +1 -0
  4. hex_zmq_servers/cam/cam_base.py +40 -10
  5. hex_zmq_servers/cam/dummy/cam_dummy.py +7 -7
  6. hex_zmq_servers/cam/dummy/cam_dummy_cli.py +1 -0
  7. hex_zmq_servers/cam/realsense/cam_realsense.py +9 -9
  8. hex_zmq_servers/cam/realsense/cam_realsense_cli.py +1 -0
  9. hex_zmq_servers/cam/rgb/cam_rgb.py +33 -7
  10. hex_zmq_servers/cam/rgb/cam_rgb_cli.py +11 -0
  11. hex_zmq_servers/config/cam_rgb.json +8 -0
  12. hex_zmq_servers/config/mujoco_archer_y6.json +1 -1
  13. hex_zmq_servers/config/mujoco_e3_desktop.json +1 -1
  14. hex_zmq_servers/config/robot_hexarm.json +1 -1
  15. hex_zmq_servers/device_base.py +3 -2
  16. hex_zmq_servers/mujoco/archer_y6/model/scene.xml +1 -1
  17. hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6.py +28 -22
  18. hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6_cli.py +42 -0
  19. hex_zmq_servers/mujoco/archer_y6/mujoco_archer_y6_srv.py +16 -14
  20. hex_zmq_servers/mujoco/e3_desktop/model/scene.xml +1 -1
  21. hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop.py +50 -40
  22. hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop_cli.py +148 -33
  23. hex_zmq_servers/mujoco/e3_desktop/mujoco_e3_desktop_srv.py +39 -35
  24. hex_zmq_servers/mujoco/mujoco_base.py +101 -64
  25. hex_zmq_servers/robot/dummy/robot_dummy.py +11 -7
  26. hex_zmq_servers/robot/dummy/robot_dummy_cli.py +1 -0
  27. hex_zmq_servers/robot/gello/robot_gello.py +11 -7
  28. hex_zmq_servers/robot/gello/robot_gello_cli.py +1 -0
  29. hex_zmq_servers/robot/hexarm/robot_hexarm.py +56 -22
  30. hex_zmq_servers/robot/hexarm/robot_hexarm_cli.py +1 -0
  31. hex_zmq_servers/robot/robot_base.py +40 -10
  32. hex_zmq_servers/zmq_base.py +92 -31
  33. {hex_zmq_servers-0.3.3.dist-info → hex_zmq_servers-0.3.4.dist-info}/METADATA +1 -1
  34. {hex_zmq_servers-0.3.3.dist-info → hex_zmq_servers-0.3.4.dist-info}/RECORD +37 -37
  35. {hex_zmq_servers-0.3.3.dist-info → hex_zmq_servers-0.3.4.dist-info}/WHEEL +0 -0
  36. {hex_zmq_servers-0.3.3.dist-info → hex_zmq_servers-0.3.4.dist-info}/licenses/LICENSE +0 -0
  37. {hex_zmq_servers-0.3.3.dist-info → hex_zmq_servers-0.3.4.dist-info}/top_level.txt +0 -0
@@ -9,8 +9,8 @@
9
9
  from .hex_launch import HexLaunch, HexNodeConfig, HEX_LOG_LEVEL, hex_dict_str, hex_log, hex_err
10
10
 
11
11
  from .device_base import HexDeviceBase
12
- from .zmq_base import HexRate, hex_zmq_ts_now, hex_zmq_ts_delta_ms
13
- from .zmq_base import HexSafeValue, HexZMQClientBase, HexZMQServerBase, hex_server_helper
12
+ from .zmq_base import hex_zmq_ts_to_ns, ns_to_hex_zmq_ts, hex_ns_now, hex_zmq_ts_now, hex_zmq_ts_delta_ms
13
+ from .zmq_base import HexRate, HexZMQClientBase, HexZMQServerBase, hex_server_helper
14
14
  from .zmq_base import HexZMQDummyClient, HexZMQDummyServer
15
15
 
16
16
  from .robot import HexRobotBase, HexRobotClientBase, HexRobotServerBase
@@ -62,9 +62,11 @@ __all__ = [
62
62
  # base
63
63
  "HexDeviceBase",
64
64
  "HexRate",
65
+ "hex_zmq_ts_to_ns",
66
+ "ns_to_hex_zmq_ts",
67
+ "hex_ns_now",
65
68
  "hex_zmq_ts_now",
66
69
  "hex_zmq_ts_delta_ms",
67
- "HexSafeValue",
68
70
  "HexZMQClientBase",
69
71
  "HexZMQServerBase",
70
72
  "hex_server_helper",
@@ -9,12 +9,10 @@
9
9
  import cv2
10
10
  import threading
11
11
  import numpy as np
12
+ from collections import deque
12
13
 
13
14
  from ..cam_base import HexCamBase
14
- from ...zmq_base import (
15
- hex_zmq_ts_now,
16
- HexSafeValue,
17
- )
15
+ from ...zmq_base import hex_zmq_ts_now
18
16
  from ...hex_launch import hex_log, HEX_LOG_LEVEL
19
17
  from berxel_py_wrapper import *
20
18
 
@@ -74,10 +72,10 @@ class HexCamBerxel(HexCamBase):
74
72
  self._wait_for_working()
75
73
  return self.__serial_number
76
74
 
77
- def work_loop(self, hex_values: list[HexSafeValue | threading.Event]):
78
- rgb_value = hex_values[0]
79
- depth_value = hex_values[1]
80
- stop_event = hex_values[2]
75
+ def work_loop(self, hex_queues: list[deque | threading.Event]):
76
+ rgb_queue = hex_queues[0]
77
+ depth_queue = hex_queues[1]
78
+ stop_event = hex_queues[2]
81
79
 
82
80
  rgb_count = 0
83
81
  depth_count = 0
@@ -89,13 +87,13 @@ class HexCamBerxel(HexCamBase):
89
87
  # collect rgb frame
90
88
  if hawk_rgb_frame is not None:
91
89
  ts, frame = self.__unpack_frame(hawk_rgb_frame, False)
92
- rgb_value.set((ts, rgb_count, frame))
90
+ rgb_queue.append((ts, rgb_count, frame))
93
91
  rgb_count = (rgb_count + 1) % self._max_seq_num
94
92
 
95
93
  # collect depth frame
96
94
  if hawk_depth_frame is not None:
97
95
  ts, frame = self.__unpack_frame(hawk_depth_frame, True)
98
- depth_value.set((ts, depth_count, frame))
96
+ depth_queue.append((ts, depth_count, frame))
99
97
  depth_count = (depth_count + 1) % self._max_seq_num
100
98
 
101
99
  self.__device.releaseFrame(hawk_rgb_frame)
@@ -24,6 +24,7 @@ class HexCamBerxelClient(HexCamClientBase):
24
24
  net_config: dict = NET_CONFIG,
25
25
  ):
26
26
  HexCamClientBase.__init__(self, net_config)
27
+ self._wait_for_working()
27
28
 
28
29
  def get_intri(self):
29
30
  intri_hdr, intri = self.request({"cmd": "get_intri"})
@@ -8,10 +8,11 @@
8
8
 
9
9
  import threading
10
10
  import numpy as np
11
+ from collections import deque
11
12
  from abc import abstractmethod
12
13
 
13
14
  from ..device_base import HexDeviceBase
14
- from ..zmq_base import HexSafeValue, HexZMQClientBase, HexZMQServerBase
15
+ from ..zmq_base import HexZMQClientBase, HexZMQServerBase, HexRate
15
16
 
16
17
  NET_CONFIG = {
17
18
  "ip": "127.0.0.1",
@@ -31,7 +32,7 @@ class HexCamBase(HexDeviceBase):
31
32
  HexDeviceBase.__del__(self)
32
33
 
33
34
  @abstractmethod
34
- def work_loop(self, hex_values: list[HexSafeValue | threading.Event]):
35
+ def work_loop(self, hex_queues: list[deque | threading.Event]):
35
36
  raise NotImplementedError(
36
37
  "`work_loop` should be implemented by the child class")
37
38
 
@@ -47,14 +48,30 @@ class HexCamClientBase(HexZMQClientBase):
47
48
  HexZMQClientBase.__init__(self, net_config)
48
49
  self._rgb_seq = 0
49
50
  self._depth_seq = 0
51
+ self._rgb_queue = deque(maxlen=10)
52
+ self._depth_queue = deque(maxlen=10)
50
53
 
51
54
  def __del__(self):
52
55
  HexZMQClientBase.__del__(self)
53
56
 
54
- def get_rgb(self):
57
+ def get_rgb(self, newest: bool = False):
58
+ try:
59
+ return self._rgb_queue.popleft(
60
+ ) if not newest else self._rgb_queue[-1]
61
+ except IndexError:
62
+ return None, None
63
+
64
+ def get_depth(self, newest: bool = False):
65
+ try:
66
+ return self._depth_queue.popleft(
67
+ ) if not newest else self._depth_queue[-1]
68
+ except IndexError:
69
+ return None, None
70
+
71
+ def _get_rgb_inner(self):
55
72
  return self._process_frame(False)
56
73
 
57
- def get_depth(self):
74
+ def _get_depth_inner(self):
58
75
  return self._process_frame(True)
59
76
 
60
77
  def _process_frame(self, depth_flag: bool):
@@ -83,14 +100,25 @@ class HexCamClientBase(HexZMQClientBase):
83
100
  print(f"\033[91m__process_frame failed: {e}\033[0m")
84
101
  return None, None
85
102
 
103
+ def _recv_loop(self):
104
+ rate = HexRate(200)
105
+ while self._recv_flag:
106
+ hdr, img = self._get_rgb_inner()
107
+ if hdr is not None:
108
+ self._rgb_queue.append((hdr, img))
109
+ hdr, img = self._get_depth_inner()
110
+ if hdr is not None:
111
+ self._depth_queue.append((hdr, img))
112
+ rate.sleep()
113
+
86
114
 
87
115
  class HexCamServerBase(HexZMQServerBase):
88
116
 
89
117
  def __init__(self, net_config: dict = NET_CONFIG):
90
118
  HexZMQServerBase.__init__(self, net_config)
91
119
  self._device: HexDeviceBase = None
92
- self._rgb_value = HexSafeValue()
93
- self._depth_value = HexSafeValue()
120
+ self._rgb_queue = deque(maxlen=10)
121
+ self._depth_queue = deque(maxlen=10)
94
122
 
95
123
  def __del__(self):
96
124
  HexZMQServerBase.__del__(self)
@@ -99,8 +127,8 @@ class HexCamServerBase(HexZMQServerBase):
99
127
  def work_loop(self):
100
128
  try:
101
129
  self._device.work_loop([
102
- self._rgb_value,
103
- self._depth_value,
130
+ self._rgb_queue,
131
+ self._depth_queue,
104
132
  self._stop_event,
105
133
  ])
106
134
  finally:
@@ -115,9 +143,11 @@ class HexCamServerBase(HexZMQServerBase):
115
143
 
116
144
  try:
117
145
  if depth_flag:
118
- ts, count, img = self._depth_value.get()
146
+ ts, count, img = self._depth_queue.popleft()
119
147
  else:
120
- ts, count, img = self._rgb_value.get()
148
+ ts, count, img = self._rgb_queue.popleft()
149
+ except IndexError:
150
+ return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
121
151
  except Exception as e:
122
152
  print(f"\033[91m{recv_hdr['cmd']} failed: {e}\033[0m")
123
153
  return {"cmd": f"{recv_hdr['cmd']}_failed"}, None
@@ -8,12 +8,12 @@
8
8
 
9
9
  import threading
10
10
  import numpy as np
11
+ from collections import deque
11
12
 
12
13
  from ..cam_base import HexCamBase
13
14
  from ...zmq_base import (
14
15
  hex_zmq_ts_now,
15
16
  HexRate,
16
- HexSafeValue,
17
17
  )
18
18
  from ...hex_launch import hex_log, HEX_LOG_LEVEL
19
19
 
@@ -27,10 +27,10 @@ class HexCamDummy(HexCamBase):
27
27
  def __del__(self):
28
28
  HexCamBase.__del__(self)
29
29
 
30
- def work_loop(self, hex_values: list[HexSafeValue | threading.Event]):
31
- rgb_value = hex_values[0]
32
- depth_value = hex_values[1]
33
- stop_event = hex_values[2]
30
+ def work_loop(self, hex_queues: list[deque | threading.Event]):
31
+ rgb_queue = hex_queues[0]
32
+ depth_queue = hex_queues[1]
33
+ stop_event = hex_queues[2]
34
34
 
35
35
  rgb_count = 0
36
36
  depth_count = 0
@@ -43,7 +43,7 @@ class HexCamDummy(HexCamBase):
43
43
  (480, 640, 3),
44
44
  dtype=np.uint8,
45
45
  )
46
- rgb_value.set((hex_zmq_ts_now(), rgb_count, rgb_img))
46
+ rgb_queue.append((hex_zmq_ts_now(), rgb_count, rgb_img))
47
47
  rgb_count = (rgb_count + 1) % self._max_seq_num
48
48
 
49
49
  # depth
@@ -53,7 +53,7 @@ class HexCamDummy(HexCamBase):
53
53
  (480, 640),
54
54
  dtype=np.uint16,
55
55
  )
56
- depth_value.set((hex_zmq_ts_now(), depth_count, depth_img))
56
+ depth_queue.append((hex_zmq_ts_now(), depth_count, depth_img))
57
57
  depth_count = (depth_count + 1) % self._max_seq_num
58
58
 
59
59
  # sleep
@@ -24,3 +24,4 @@ class HexCamDummyClient(HexCamClientBase):
24
24
  net_config: dict = NET_CONFIG,
25
25
  ):
26
26
  HexCamClientBase.__init__(self, net_config)
27
+ self._wait_for_working()
@@ -6,15 +6,15 @@
6
6
  # Date : 2025-09-14
7
7
  ################################################################
8
8
 
9
- import time
10
9
  import threading
11
10
  import numpy as np
11
+ from collections import deque
12
12
 
13
13
  from ..cam_base import HexCamBase
14
14
  from ...zmq_base import (
15
+ hex_ns_now,
15
16
  hex_zmq_ts_now,
16
17
  hex_zmq_ts_delta_ms,
17
- HexSafeValue,
18
18
  )
19
19
  from ...hex_launch import hex_log, HEX_LOG_LEVEL
20
20
  import pyrealsense2 as rs
@@ -103,13 +103,13 @@ class HexCamRealsense(HexCamBase):
103
103
  self._wait_for_working()
104
104
  return self.__serial_number
105
105
 
106
- def work_loop(self, hex_values: list[HexSafeValue | threading.Event]):
107
- rgb_value = hex_values[0]
108
- depth_value = hex_values[1]
109
- stop_event = hex_values[2]
106
+ def work_loop(self, hex_queues: list[deque | threading.Event]):
107
+ rgb_queue = hex_queues[0]
108
+ depth_queue = hex_queues[1]
109
+ stop_event = hex_queues[2]
110
110
 
111
111
  frames = self.__pipeline.wait_for_frames()
112
- bias_ns = np.int64(time.time_ns()) - np.int64(
112
+ bias_ns = np.int64(hex_ns_now()) - np.int64(
113
113
  frames.get_frame_metadata(rs.frame_metadata_value.sensor_timestamp)
114
114
  * 1_000)
115
115
 
@@ -134,14 +134,14 @@ class HexCamRealsense(HexCamBase):
134
134
  color_frame = aligned_frames.get_color_frame()
135
135
  if color_frame:
136
136
 
137
- rgb_value.set((sen_ts if self.__sens_ts else cur_ns, rgb_count,
137
+ rgb_queue.append((sen_ts if self.__sens_ts else cur_ns, rgb_count,
138
138
  np.asanyarray(color_frame.get_data())))
139
139
  rgb_count = (rgb_count + 1) % self._max_seq_num
140
140
 
141
141
  # collect depth frame
142
142
  depth_frame = aligned_frames.get_depth_frame()
143
143
  if depth_frame:
144
- depth_value.set(
144
+ depth_queue.append(
145
145
  (sen_ts if self.__sens_ts else cur_ns, depth_count,
146
146
  np.asanyarray(depth_frame.get_data())))
147
147
  depth_count = (depth_count + 1) % self._max_seq_num
@@ -24,6 +24,7 @@ class HexCamRealsenseClient(HexCamClientBase):
24
24
  net_config: dict = NET_CONFIG,
25
25
  ):
26
26
  HexCamClientBase.__init__(self, net_config)
27
+ self._wait_for_working()
27
28
 
28
29
  def get_intri(self):
29
30
  intri_hdr, intri = self.request({"cmd": "get_intri"})
@@ -6,21 +6,25 @@
6
6
  # Date : 2025-09-14
7
7
  ################################################################
8
8
 
9
+ import platform
9
10
  import cv2
10
11
  import threading
11
12
  import numpy as np
13
+ from collections import deque
12
14
 
13
15
  from ..cam_base import HexCamBase
14
16
  from ...zmq_base import (
15
17
  hex_zmq_ts_now,
16
18
  HexRate,
17
- HexSafeValue,
18
19
  )
19
20
  from ...hex_launch import hex_log, HEX_LOG_LEVEL
20
21
 
21
22
  CAMERA_CONFIG = {
22
23
  "cam_path": "/dev/video0",
23
24
  "resolution": [640, 480],
25
+ "crop": [0, 640, 0, 480],
26
+ "exposure": 100,
27
+ "temperature": 4000,
24
28
  "frame_rate": 30,
25
29
  "sens_ts": True,
26
30
  }
@@ -37,6 +41,9 @@ class HexCamRGB(HexCamBase):
37
41
  try:
38
42
  self.__cam_path = camera_config["cam_path"]
39
43
  self.__resolution = camera_config["resolution"]
44
+ self.__crop = camera_config["crop"]
45
+ self.__exposure = camera_config["exposure"]
46
+ self.__temperature = camera_config["temperature"]
40
47
  self.__frame_rate = camera_config["frame_rate"]
41
48
  self.__sens_ts = camera_config["sens_ts"]
42
49
  except KeyError as ke:
@@ -55,6 +62,18 @@ class HexCamRGB(HexCamBase):
55
62
  self.__cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.__resolution[0])
56
63
  self.__cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.__resolution[1])
57
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)
58
77
 
59
78
  print("#############################")
60
79
  print(
@@ -66,6 +85,11 @@ class HexCamRGB(HexCamBase):
66
85
  (four_cc_int >> 8) & 0xff) + chr((four_cc_int >> 16) & 0xff) + chr(
67
86
  (four_cc_int >> 24) & 0xff)
68
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)}")
69
93
  print("#############################")
70
94
 
71
95
  # start work loop
@@ -75,13 +99,13 @@ class HexCamRGB(HexCamBase):
75
99
  self._wait_for_working()
76
100
  return self.__intri
77
101
 
78
- def work_loop(self, hex_values: list[HexSafeValue | threading.Event]):
79
- rgb_value = hex_values[0]
80
- depth_value = hex_values[1]
81
- stop_event = hex_values[2]
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]
82
106
 
83
107
  rgb_count = 0
84
- depth_value.set((hex_zmq_ts_now(), 0,
108
+ depth_queue.append((hex_zmq_ts_now(), 0,
85
109
  np.zeros((self.__resolution[1], self.__resolution[0]),
86
110
  dtype=np.uint16)))
87
111
  rate = HexRate(self.__frame_rate * 5)
@@ -91,7 +115,9 @@ class HexCamRGB(HexCamBase):
91
115
 
92
116
  # collect rgb frame
93
117
  if ret:
94
- rgb_value.set((hex_zmq_ts_now(), rgb_count, frame))
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))
95
121
  rgb_count = (rgb_count + 1) % self._max_seq_num
96
122
 
97
123
  rate.sleep()
@@ -7,6 +7,7 @@
7
7
  ################################################################
8
8
 
9
9
  from ..cam_base import HexCamClientBase
10
+ from ...zmq_base import HexRate
10
11
 
11
12
  NET_CONFIG = {
12
13
  "ip": "127.0.0.1",
@@ -24,7 +25,17 @@ class HexCamRGBClient(HexCamClientBase):
24
25
  net_config: dict = NET_CONFIG,
25
26
  ):
26
27
  HexCamClientBase.__init__(self, net_config)
28
+ self._wait_for_working()
27
29
 
28
30
  def get_intri(self):
29
31
  intri_hdr, intri = self.request({"cmd": "get_intri"})
30
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
+
@@ -12,6 +12,14 @@
12
12
  640,
13
13
  480
14
14
  ],
15
+ "crop": [
16
+ 0,
17
+ 640,
18
+ 0,
19
+ 480
20
+ ],
21
+ "exposure": 70,
22
+ "temperature": 0,
15
23
  "frame_rate": 30,
16
24
  "sens_ts": true
17
25
  }
@@ -7,7 +7,7 @@
7
7
  "server_num_workers": 4
8
8
  },
9
9
  "params": {
10
- "states_rate": 500,
10
+ "states_rate": 1000,
11
11
  "img_rate": 30,
12
12
  "tau_ctrl": false,
13
13
  "mit_kp": [
@@ -7,7 +7,7 @@
7
7
  "server_num_workers": 4
8
8
  },
9
9
  "params": {
10
- "states_rate": 500,
10
+ "states_rate": 1000,
11
11
  "img_rate": 30,
12
12
  "tau_ctrl": false,
13
13
  "mit_kp": [
@@ -9,7 +9,7 @@
9
9
  "params": {
10
10
  "device_ip": "172.18.8.161",
11
11
  "device_port": 8439,
12
- "control_hz": 500,
12
+ "control_hz": 1000,
13
13
  "arm_type": "archer_l6y",
14
14
  "use_gripper": true,
15
15
  "mit_kp": [
@@ -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, HexSafeValue
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, hex_values: list[HexSafeValue | threading.Event]):
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
 
@@ -1,7 +1,7 @@
1
1
  <mujoco model="archer_y6 scene">
2
2
  <compiler angle="radian"/>
3
3
  <option integrator="implicitfast"/>
4
- <option timestep="2e-3"/>
4
+ <option timestep="1e-3"/>
5
5
 
6
6
  <statistic center="0.3 0 0.45" extent="0.8" meansize="0.05"/>
7
7
 
@@ -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": 500,
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],
@@ -124,6 +126,9 @@ class HexMujocoArcherY6(HexMujocoBase):
124
126
  if not self.__headless:
125
127
  self.__viewer = viewer.launch_passive(self.__model, self.__data)
126
128
 
129
+ # time init
130
+ self.__bias_ns = hex_ns_now() - self.__data.time * 1_000_000_000
131
+
127
132
  # start work loop
128
133
  self._working.set()
129
134
 
@@ -139,13 +144,13 @@ class HexMujocoArcherY6(HexMujocoBase):
139
144
  self.__viewer.sync()
140
145
  return True
141
146
 
142
- def work_loop(self, hex_values: list[HexSafeValue | threading.Event]):
143
- states_robot_value = hex_values[0]
144
- states_obj_value = hex_values[1]
145
- cmds_robot_value = hex_values[2]
146
- rgb_value = hex_values[3]
147
- depth_value = hex_values[4]
148
- stop_event = hex_values[5]
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]
149
154
 
150
155
  last_states_ts = {"s": 0, "ns": 0}
151
156
  states_robot_count = 0
@@ -159,10 +164,10 @@ class HexMujocoArcherY6(HexMujocoBase):
159
164
  states_trig_count = 0
160
165
  img_trig_count = 0
161
166
  init_ts = self.__mujoco_ts() if self.__sens_ts else hex_zmq_ts_now()
162
- rgb_value.set((init_ts, 0,
167
+ rgb_queue.append((init_ts, 0,
163
168
  np.zeros((self.__height, self.__width, 3),
164
169
  dtype=np.uint8)))
165
- depth_value.set((init_ts, 0,
170
+ depth_queue.append((init_ts, 0,
166
171
  np.zeros((self.__height, self.__width),
167
172
  dtype=np.uint16)))
168
173
  while self._working.is_set() and not stop_event.is_set():
@@ -173,23 +178,27 @@ class HexMujocoArcherY6(HexMujocoBase):
173
178
  # states
174
179
  ts, states_robot, states_obj = self.__get_states()
175
180
  if states_robot is not None:
176
- if hex_zmq_ts_delta_ms(ts, last_states_ts) > 1.0:
181
+ if hex_zmq_ts_delta_ms(ts, last_states_ts) > 1e-6:
177
182
  last_states_ts = ts
178
183
 
179
184
  # states robot
180
- states_robot_value.set(
185
+ states_robot_queue.append(
181
186
  (ts, states_robot_count, states_robot))
182
187
  states_robot_count = (states_robot_count +
183
188
  1) % self._max_seq_num
184
189
 
185
190
  # states obj
186
- states_obj_value.set(
191
+ states_obj_queue.append(
187
192
  (ts, states_obj_count, states_obj))
188
193
  states_obj_count = (states_obj_count +
189
194
  1) % self._max_seq_num
190
195
 
191
196
  # cmds
192
- cmds_robot_pack = cmds_robot_value.get(timeout_s=-1.0)
197
+ cmds_robot_pack = None
198
+ try:
199
+ cmds_robot_pack = cmds_robot_queue.popleft()
200
+ except IndexError:
201
+ pass
193
202
  if cmds_robot_pack is not None:
194
203
  ts, seq, cmds_robot_get = cmds_robot_pack
195
204
  if seq != last_cmds_robot_seq:
@@ -207,14 +216,14 @@ class HexMujocoArcherY6(HexMujocoBase):
207
216
  if self.__use_rgb:
208
217
  ts, rgb_img = self.__get_rgb()
209
218
  if rgb_img is not None:
210
- rgb_value.set((ts, rgb_count, rgb_img))
219
+ rgb_queue.append((ts, rgb_count, rgb_img))
211
220
  rgb_count = (rgb_count + 1) % self._max_seq_num
212
221
 
213
222
  # depth
214
223
  if self.__use_depth:
215
224
  ts, depth_img = self.__get_depth()
216
225
  if depth_img is not None:
217
- depth_value.set((ts, depth_count, depth_img))
226
+ depth_queue.append((ts, depth_count, depth_img))
218
227
  depth_count = (depth_count + 1) % self._max_seq_num
219
228
 
220
229
  # mujoco step
@@ -299,11 +308,8 @@ class HexMujocoArcherY6(HexMujocoBase):
299
308
  ), depth_img
300
309
 
301
310
  def __mujoco_ts(self):
302
- mujoco_ts = self.__data.time
303
- return {
304
- "s": int(mujoco_ts // 1),
305
- "ns": int((mujoco_ts % 1) * 1_000_000_000),
306
- }
311
+ mujoco_ts = self.__data.time * 1_000_000_000 + self.__bias_ns
312
+ return ns_to_hex_zmq_ts(mujoco_ts)
307
313
 
308
314
  def close(self):
309
315
  if not self._working.is_set():