fix: 安全关闭 MuJoCo 显示窗口
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import math
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
import yaml
|
||||
|
||||
from xr_rm_mujoco import dual_arm_simulator as simulator_module
|
||||
from xr_rm_mujoco.dual_arm_simulator import (
|
||||
ARM_JOINT_NAMES,
|
||||
DualArmKinematicModel,
|
||||
@@ -70,6 +73,34 @@ def test_mujoco_config_contains_only_render_parameters() -> None:
|
||||
assert parameters == {"render_rate_hz": 60.0}
|
||||
|
||||
|
||||
def test_main_closes_viewer_cleanly_on_keyboard_interrupt(monkeypatch) -> None:
|
||||
close_viewer = simulator_module.DualArmSimulator.close_viewer
|
||||
viewer = Mock()
|
||||
node = SimpleNamespace(_viewer=viewer, destroy_node=Mock())
|
||||
node.close_viewer = lambda: close_viewer(node)
|
||||
init = Mock()
|
||||
spin = Mock(side_effect=KeyboardInterrupt)
|
||||
sleep = Mock()
|
||||
shutdown = Mock()
|
||||
|
||||
monkeypatch.setattr(simulator_module, "DualArmSimulator", lambda: node)
|
||||
monkeypatch.setattr(simulator_module.rclpy, "init", init)
|
||||
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.rclpy, "shutdown", shutdown)
|
||||
|
||||
simulator_module.main(["--test"])
|
||||
|
||||
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)
|
||||
node.destroy_node.assert_called_once_with()
|
||||
shutdown.assert_called_once_with()
|
||||
assert node._viewer is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("names", "positions", "match"),
|
||||
[
|
||||
|
||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
||||
|
||||
import math
|
||||
from pathlib import Path
|
||||
import time
|
||||
from typing import Callable
|
||||
|
||||
import mujoco
|
||||
@@ -179,6 +180,8 @@ class DualArmSimulator(Node):
|
||||
def close_viewer(self) -> None:
|
||||
if self._viewer is not None:
|
||||
self._viewer.close()
|
||||
# MuJoCo 在后台 daemon 线程释放 GLX;立即退出解释器会触发段错误。
|
||||
time.sleep(0.1)
|
||||
self._viewer = None
|
||||
|
||||
|
||||
@@ -188,6 +191,8 @@ def main(args=None) -> None:
|
||||
try:
|
||||
node = DualArmSimulator()
|
||||
rclpy.spin(node)
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
if node is not None:
|
||||
node.close_viewer()
|
||||
|
||||
Reference in New Issue
Block a user