fix: 完善 MuJoCo 退出与测试环境
This commit is contained in:
@@ -104,7 +104,7 @@ source install/setup.bash
|
||||
|
||||
真机模式还需要安装睿尔曼 Python API2。若未安装,mock 模式仍可正常使用;真机启动时会提示缺少 `Robotic_Arm` 包。
|
||||
|
||||
遥操作节点固定由 `/home/robot/miniconda3/envs/xr/bin/python` 启动,并复用其中的 Python 3.10、Placo 0.9.4、Pinocchio 3.7.0 和 NumPy 2.2.6。`ros2`、`colcon` 和 `udp_controller_receiver` 仍使用系统 Python。禁止通过 `pip --user`、`sudo pip` 或系统安装升级 Placo、Pinocchio、EigenPy 和 NumPy。
|
||||
遥操作和 MuJoCo 节点固定由 `/home/robot/miniconda3/envs/xr/bin/python` 启动,并复用其中的 Python 3.10、Placo 0.9.4、Pinocchio 3.7.0、NumPy 2.2.6 和 MuJoCo 3.10.0。`ros2`、`colcon`、pytest 和 `udp_controller_receiver` 仍使用系统 Python。禁止通过 `pip --user`、`sudo pip` 或系统安装升级 Placo、Pinocchio、EigenPy 和 NumPy。
|
||||
|
||||
只读检查 Placo 版本:
|
||||
|
||||
@@ -115,6 +115,20 @@ source install/setup.bash
|
||||
|
||||
输出必须为 `0.9.4`。
|
||||
|
||||
同时检查 MuJoCo:
|
||||
|
||||
```bash
|
||||
/home/robot/miniconda3/envs/xr/bin/python -c \
|
||||
"import mujoco; print(mujoco.__version__)"
|
||||
```
|
||||
|
||||
当前验证版本为 `3.10.0`。系统 pytest 会通过 `xr_rm_mujoco/test/conftest.py` 复用该固定 XR 环境中的 MuJoCo,因此新包可直接按 ROS2 标准方式测试:
|
||||
|
||||
```bash
|
||||
colcon test --packages-select xr_rm_mujoco --event-handlers console_direct+
|
||||
colcon test-result --verbose
|
||||
```
|
||||
|
||||
如果希望 `launcher_ui.py` 从任意目录找到工作空间,可以设置:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
"""让 ROS2 系统 pytest 复用项目固定 XR 环境中的 MuJoCo。"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
XR_SITE_PACKAGES = Path(
|
||||
"/home/robot/miniconda3/envs/xr/lib/python3.10/site-packages"
|
||||
)
|
||||
if XR_SITE_PACKAGES.is_dir():
|
||||
sys.path.append(str(XR_SITE_PACKAGES))
|
||||
@@ -80,7 +80,8 @@ def test_main_closes_viewer_cleanly_on_keyboard_interrupt(monkeypatch) -> None:
|
||||
node.close_viewer = lambda: close_viewer(node)
|
||||
init = Mock()
|
||||
spin = Mock(side_effect=KeyboardInterrupt)
|
||||
sleep = Mock()
|
||||
sleep = Mock(side_effect=[KeyboardInterrupt, None])
|
||||
monotonic = Mock(side_effect=[0.0, 0.0, 0.04])
|
||||
shutdown = Mock()
|
||||
|
||||
monkeypatch.setattr(simulator_module, "DualArmSimulator", lambda: node)
|
||||
@@ -88,6 +89,7 @@ def test_main_closes_viewer_cleanly_on_keyboard_interrupt(monkeypatch) -> None:
|
||||
monkeypatch.setattr(simulator_module.rclpy, "spin", spin)
|
||||
monkeypatch.setattr(simulator_module.rclpy, "ok", lambda: True)
|
||||
monkeypatch.setattr(simulator_module.time, "sleep", sleep)
|
||||
monkeypatch.setattr(simulator_module.time, "monotonic", monotonic)
|
||||
monkeypatch.setattr(simulator_module.rclpy, "shutdown", shutdown)
|
||||
|
||||
simulator_module.main(["--test"])
|
||||
@@ -95,7 +97,9 @@ def test_main_closes_viewer_cleanly_on_keyboard_interrupt(monkeypatch) -> None:
|
||||
init.assert_called_once_with(args=["--test"])
|
||||
spin.assert_called_once_with(node)
|
||||
viewer.close.assert_called_once_with()
|
||||
sleep.assert_called_once_with(0.1)
|
||||
assert [call.args[0] for call in sleep.call_args_list] == pytest.approx(
|
||||
[0.1, 0.06]
|
||||
)
|
||||
node.destroy_node.assert_called_once_with()
|
||||
shutdown.assert_called_once_with()
|
||||
assert node._viewer is None
|
||||
|
||||
@@ -181,7 +181,16 @@ class DualArmSimulator(Node):
|
||||
if self._viewer is not None:
|
||||
self._viewer.close()
|
||||
# MuJoCo 在后台 daemon 线程释放 GLX;立即退出解释器会触发段错误。
|
||||
time.sleep(0.1)
|
||||
deadline = time.monotonic() + 0.1
|
||||
while True:
|
||||
remaining = deadline - time.monotonic()
|
||||
if remaining <= 0.0:
|
||||
break
|
||||
try:
|
||||
time.sleep(remaining)
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
continue
|
||||
self._viewer = None
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user