dexcontrol 0.2.1__py3-none-any.whl → 0.2.3__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.
Potentially problematic release.
This version of dexcontrol might be problematic. Click here for more details.
- dexcontrol/__init__.py +14 -3
- dexcontrol/apps/dualsense_teleop_base.py +16 -11
- dexcontrol/config/__init__.py +10 -5
- dexcontrol/config/core/__init__.py +8 -3
- dexcontrol/config/core/arm.py +8 -3
- dexcontrol/config/core/chassis.py +10 -5
- dexcontrol/config/core/hand.py +14 -9
- dexcontrol/config/core/head.py +8 -3
- dexcontrol/config/core/misc.py +8 -3
- dexcontrol/config/core/torso.py +8 -3
- dexcontrol/config/sensors/__init__.py +8 -3
- dexcontrol/config/sensors/cameras/__init__.py +9 -4
- dexcontrol/config/sensors/cameras/rgb_camera.py +18 -5
- dexcontrol/config/sensors/cameras/zed_camera.py +36 -0
- dexcontrol/config/sensors/imu/__init__.py +10 -5
- dexcontrol/config/sensors/imu/chassis_imu.py +21 -0
- dexcontrol/config/sensors/imu/zed_imu.py +21 -0
- dexcontrol/config/sensors/lidar/__init__.py +8 -3
- dexcontrol/config/sensors/lidar/rplidar.py +9 -3
- dexcontrol/config/sensors/ultrasonic/__init__.py +8 -3
- dexcontrol/config/sensors/ultrasonic/ultrasonic.py +9 -3
- dexcontrol/config/sensors/vega_sensors.py +34 -21
- dexcontrol/config/vega.py +14 -6
- dexcontrol/core/__init__.py +9 -0
- dexcontrol/core/arm.py +21 -6
- dexcontrol/core/chassis.py +8 -3
- dexcontrol/core/component.py +26 -6
- dexcontrol/core/hand.py +8 -3
- dexcontrol/core/head.py +18 -3
- dexcontrol/core/misc.py +94 -16
- dexcontrol/core/torso.py +8 -3
- dexcontrol/proto/dexcontrol_msg_pb2.py +17 -15
- dexcontrol/proto/dexcontrol_msg_pb2.pyi +24 -0
- dexcontrol/robot.py +82 -28
- dexcontrol/sensors/__init__.py +13 -8
- dexcontrol/sensors/camera/__init__.py +11 -6
- dexcontrol/sensors/camera/rgb_camera.py +33 -24
- dexcontrol/sensors/camera/zed_camera.py +364 -0
- dexcontrol/sensors/imu/__init__.py +13 -8
- dexcontrol/sensors/imu/chassis_imu.py +155 -0
- dexcontrol/sensors/imu/{nine_axis_imu.py → zed_imu.py} +41 -26
- dexcontrol/sensors/lidar/__init__.py +11 -1
- dexcontrol/sensors/lidar/rplidar.py +8 -3
- dexcontrol/sensors/manager.py +22 -9
- dexcontrol/sensors/ultrasonic.py +8 -3
- dexcontrol/utils/__init__.py +8 -3
- dexcontrol/utils/constants.py +10 -0
- dexcontrol/utils/io_utils.py +8 -3
- dexcontrol/utils/motion_utils.py +8 -3
- dexcontrol/utils/os_utils.py +23 -4
- dexcontrol/utils/pb_utils.py +8 -3
- dexcontrol/utils/rate_limiter.py +8 -3
- dexcontrol/utils/rtc_utils.py +144 -0
- dexcontrol/utils/subscribers/__init__.py +11 -3
- dexcontrol/utils/subscribers/base.py +26 -5
- dexcontrol/utils/subscribers/camera.py +10 -6
- dexcontrol/utils/subscribers/decoders.py +8 -3
- dexcontrol/utils/subscribers/generic.py +8 -3
- dexcontrol/utils/subscribers/imu.py +8 -3
- dexcontrol/utils/subscribers/lidar.py +8 -3
- dexcontrol/utils/subscribers/protobuf.py +8 -3
- dexcontrol/utils/subscribers/rtc.py +315 -0
- dexcontrol/utils/timer.py +8 -3
- dexcontrol/utils/trajectory_utils.py +8 -3
- dexcontrol/utils/viz_utils.py +8 -3
- dexcontrol/utils/zenoh_utils.py +83 -0
- dexcontrol-0.2.3.dist-info/METADATA +265 -0
- dexcontrol-0.2.3.dist-info/RECORD +72 -0
- {dexcontrol-0.2.1.dist-info → dexcontrol-0.2.3.dist-info}/WHEEL +1 -2
- dexcontrol-0.2.3.dist-info/licenses/LICENSE +184 -0
- dexcontrol/config/sensors/cameras/gemini_camera.py +0 -16
- dexcontrol/config/sensors/imu/gemini_imu.py +0 -15
- dexcontrol/config/sensors/imu/nine_axis_imu.py +0 -15
- dexcontrol/sensors/camera/gemini_camera.py +0 -139
- dexcontrol/sensors/imu/gemini_imu.py +0 -139
- dexcontrol/utils/reset_orbbec_camera_usb.py +0 -98
- dexcontrol-0.2.1.dist-info/METADATA +0 -369
- dexcontrol-0.2.1.dist-info/RECORD +0 -72
- dexcontrol-0.2.1.dist-info/licenses/LICENSE +0 -188
- dexcontrol-0.2.1.dist-info/licenses/NOTICE +0 -13
- dexcontrol-0.2.1.dist-info/top_level.txt +0 -1
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Dexmate CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 with Commons Clause License
|
|
4
|
-
# Condition v1.0 [see LICENSE for details].
|
|
5
|
-
|
|
6
|
-
from dataclasses import dataclass
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@dataclass
|
|
10
|
-
class GeminiIMUConfig:
|
|
11
|
-
_target_: str = "dexcontrol.sensors.imu.gemini_imu.GeminiIMUSensor"
|
|
12
|
-
topic: str = "/imu/gemini"
|
|
13
|
-
name: str = "gemini_imu"
|
|
14
|
-
enable_fps_tracking: bool = False
|
|
15
|
-
fps_log_interval: int = 30
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Dexmate CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 with Commons Clause License
|
|
4
|
-
# Condition v1.0 [see LICENSE for details].
|
|
5
|
-
|
|
6
|
-
from dataclasses import dataclass
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@dataclass
|
|
10
|
-
class NineAxisIMUConfig:
|
|
11
|
-
_target_: str = "dexcontrol.sensors.imu.nine_axis_imu.NineAxisIMUSensor"
|
|
12
|
-
topic: str = "/imu/nine_axis"
|
|
13
|
-
name: str = "nine_axis_imu"
|
|
14
|
-
enable_fps_tracking: bool = False
|
|
15
|
-
fps_log_interval: int = 30
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Dexmate CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 with Commons Clause License
|
|
4
|
-
# Condition v1.0 [see LICENSE for details].
|
|
5
|
-
|
|
6
|
-
"""Gemini RGBD camera sensor implementation using Zenoh subscriber."""
|
|
7
|
-
|
|
8
|
-
import numpy as np
|
|
9
|
-
import zenoh
|
|
10
|
-
|
|
11
|
-
from dexcontrol.utils.subscribers.camera import RGBDCameraSubscriber
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class GeminiCameraSensor:
|
|
15
|
-
"""Gemini RGBD camera sensor using Zenoh subscriber.
|
|
16
|
-
|
|
17
|
-
This sensor provides both RGB and depth image data from an Orbbec Gemini camera
|
|
18
|
-
using the RGBDCameraSubscriber for efficient data handling with lazy decoding.
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
def __init__(
|
|
22
|
-
self,
|
|
23
|
-
configs,
|
|
24
|
-
zenoh_session: zenoh.Session,
|
|
25
|
-
) -> None:
|
|
26
|
-
"""Initialize the Gemini RGBD camera sensor.
|
|
27
|
-
|
|
28
|
-
Args:
|
|
29
|
-
rgb_topic: Zenoh topic for RGB data.
|
|
30
|
-
depth_topic: Zenoh topic for depth data.
|
|
31
|
-
zenoh_session: Active Zenoh session for communication.
|
|
32
|
-
name: Name for the sensor instance.
|
|
33
|
-
enable_fps_tracking: Whether to track and log FPS metrics.
|
|
34
|
-
fps_log_interval: Number of frames between FPS calculations.
|
|
35
|
-
"""
|
|
36
|
-
self._name = configs.name
|
|
37
|
-
|
|
38
|
-
# Create the RGBD camera subscriber
|
|
39
|
-
self._subscriber = RGBDCameraSubscriber(
|
|
40
|
-
rgb_topic=configs.rgb_topic,
|
|
41
|
-
depth_topic=configs.depth_topic,
|
|
42
|
-
zenoh_session=zenoh_session,
|
|
43
|
-
name=f"{self._name}_subscriber",
|
|
44
|
-
enable_fps_tracking=configs.enable_fps_tracking,
|
|
45
|
-
fps_log_interval=configs.fps_log_interval,
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
def shutdown(self) -> None:
|
|
49
|
-
"""Shutdown the camera sensor."""
|
|
50
|
-
self._subscriber.shutdown()
|
|
51
|
-
|
|
52
|
-
def is_active(self) -> bool:
|
|
53
|
-
"""Check if the camera sensor is actively receiving data.
|
|
54
|
-
|
|
55
|
-
Returns:
|
|
56
|
-
True if both RGB and depth are receiving data, False otherwise.
|
|
57
|
-
"""
|
|
58
|
-
return self._subscriber.is_active()
|
|
59
|
-
|
|
60
|
-
def wait_for_active(self, timeout: float = 5.0) -> bool:
|
|
61
|
-
"""Wait for the camera sensor to start receiving data.
|
|
62
|
-
|
|
63
|
-
Args:
|
|
64
|
-
timeout: Maximum time to wait in seconds.
|
|
65
|
-
|
|
66
|
-
Returns:
|
|
67
|
-
True if both RGB and depth become active, False if timeout is reached.
|
|
68
|
-
"""
|
|
69
|
-
return self._subscriber.wait_for_active(timeout)
|
|
70
|
-
|
|
71
|
-
def get_obs(self, obs_keys: list[str] | None = None) -> dict[str, np.ndarray] | None:
|
|
72
|
-
"""Get the latest RGBD data.
|
|
73
|
-
|
|
74
|
-
Returns:
|
|
75
|
-
Tuple of (rgb, depth) if both available, None otherwise.
|
|
76
|
-
"""
|
|
77
|
-
if obs_keys is None:
|
|
78
|
-
obs_keys = ["rgb", "depth"]
|
|
79
|
-
obs_out = {}
|
|
80
|
-
for key in obs_keys:
|
|
81
|
-
if key == "rgb":
|
|
82
|
-
obs_out[key] = self._subscriber.get_latest_rgb()
|
|
83
|
-
elif key == "depth":
|
|
84
|
-
obs_out[key] = self._subscriber.get_latest_depth()
|
|
85
|
-
else:
|
|
86
|
-
raise ValueError(f"Invalid observation key: {key}")
|
|
87
|
-
return obs_out
|
|
88
|
-
|
|
89
|
-
def get_rgb_image(self) -> np.ndarray | None:
|
|
90
|
-
"""Get the latest RGB image.
|
|
91
|
-
|
|
92
|
-
Returns:
|
|
93
|
-
Latest RGB image as numpy array (HxWxC) if available, None otherwise.
|
|
94
|
-
"""
|
|
95
|
-
return self._subscriber.get_latest_rgb()
|
|
96
|
-
|
|
97
|
-
def get_depth_image(self) -> np.ndarray | None:
|
|
98
|
-
"""Get the latest depth image.
|
|
99
|
-
|
|
100
|
-
Returns:
|
|
101
|
-
Latest depth image as numpy array (HxW) with values in meters if available, None otherwise.
|
|
102
|
-
"""
|
|
103
|
-
return self._subscriber.get_latest_depth()
|
|
104
|
-
|
|
105
|
-
@property
|
|
106
|
-
def rgb_fps(self) -> float:
|
|
107
|
-
"""Get the RGB stream FPS measurement.
|
|
108
|
-
|
|
109
|
-
Returns:
|
|
110
|
-
Current RGB frames per second measurement.
|
|
111
|
-
"""
|
|
112
|
-
return self._subscriber.rgb_fps
|
|
113
|
-
|
|
114
|
-
@property
|
|
115
|
-
def depth_fps(self) -> float:
|
|
116
|
-
"""Get the depth stream FPS measurement.
|
|
117
|
-
|
|
118
|
-
Returns:
|
|
119
|
-
Current depth frames per second measurement.
|
|
120
|
-
"""
|
|
121
|
-
return self._subscriber.depth_fps
|
|
122
|
-
|
|
123
|
-
@property
|
|
124
|
-
def fps(self) -> float:
|
|
125
|
-
"""Get the combined FPS measurement (minimum of RGB and depth).
|
|
126
|
-
|
|
127
|
-
Returns:
|
|
128
|
-
Current frames per second measurement.
|
|
129
|
-
"""
|
|
130
|
-
return min(self.rgb_fps, self.depth_fps)
|
|
131
|
-
|
|
132
|
-
@property
|
|
133
|
-
def name(self) -> str:
|
|
134
|
-
"""Get the sensor name.
|
|
135
|
-
|
|
136
|
-
Returns:
|
|
137
|
-
Sensor name string.
|
|
138
|
-
"""
|
|
139
|
-
return self._name
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Dexmate CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 with Commons Clause License
|
|
4
|
-
# Condition v1.0 [see LICENSE for details].
|
|
5
|
-
|
|
6
|
-
"""Gemini IMU sensor implementation using Zenoh subscriber."""
|
|
7
|
-
|
|
8
|
-
import numpy as np
|
|
9
|
-
import zenoh
|
|
10
|
-
|
|
11
|
-
from dexcontrol.utils.subscribers.imu import IMUSubscriber
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class GeminiIMUSensor:
|
|
15
|
-
"""Gemini IMU sensor using Zenoh subscriber.
|
|
16
|
-
|
|
17
|
-
This sensor provides 6-axis IMU data (accelerometer + gyroscope) from Gemini hardware
|
|
18
|
-
using the IMUSubscriber for efficient data handling. Note: Gemini IMU does not include
|
|
19
|
-
magnetometer data.
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
def __init__(
|
|
23
|
-
self,
|
|
24
|
-
configs,
|
|
25
|
-
zenoh_session: zenoh.Session,
|
|
26
|
-
) -> None:
|
|
27
|
-
"""Initialize the Gemini IMU sensor.
|
|
28
|
-
|
|
29
|
-
Args:
|
|
30
|
-
topic: Zenoh topic to subscribe to for IMU data.
|
|
31
|
-
zenoh_session: Active Zenoh session for communication.
|
|
32
|
-
name: Name for the sensor instance.
|
|
33
|
-
enable_fps_tracking: Whether to track and log FPS metrics.
|
|
34
|
-
"""
|
|
35
|
-
self._name = configs.name
|
|
36
|
-
|
|
37
|
-
# Create the IMU subscriber
|
|
38
|
-
self._subscriber = IMUSubscriber(
|
|
39
|
-
topic=configs.topic,
|
|
40
|
-
zenoh_session=zenoh_session,
|
|
41
|
-
name=f"{self._name}_subscriber",
|
|
42
|
-
enable_fps_tracking=configs.enable_fps_tracking,
|
|
43
|
-
fps_log_interval=configs.fps_log_interval,
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def shutdown(self) -> None:
|
|
48
|
-
"""Shutdown the IMU sensor."""
|
|
49
|
-
self._subscriber.shutdown()
|
|
50
|
-
|
|
51
|
-
def is_active(self) -> bool:
|
|
52
|
-
"""Check if the IMU sensor is actively receiving data.
|
|
53
|
-
|
|
54
|
-
Returns:
|
|
55
|
-
True if receiving data, False otherwise.
|
|
56
|
-
"""
|
|
57
|
-
return self._subscriber.is_active()
|
|
58
|
-
|
|
59
|
-
def wait_for_active(self, timeout: float = 5.0) -> bool:
|
|
60
|
-
"""Wait for the IMU sensor to start receiving data.
|
|
61
|
-
|
|
62
|
-
Args:
|
|
63
|
-
timeout: Maximum time to wait in seconds.
|
|
64
|
-
|
|
65
|
-
Returns:
|
|
66
|
-
True if sensor becomes active, False if timeout is reached.
|
|
67
|
-
"""
|
|
68
|
-
return self._subscriber.wait_for_active(timeout)
|
|
69
|
-
|
|
70
|
-
def get_obs(self, obs_keys: list[str] | None = None) -> dict[str, np.ndarray] | None:
|
|
71
|
-
"""Get observation data for the Gemini IMU sensor.
|
|
72
|
-
|
|
73
|
-
Args:
|
|
74
|
-
obs_keys: List of observation keys to retrieve. If None, returns available data.
|
|
75
|
-
Valid keys: ['ang_vel', 'acc', 'quat'] (no magnetometer for Gemini)
|
|
76
|
-
|
|
77
|
-
Returns:
|
|
78
|
-
Dictionary with observation data including IMU measurements.
|
|
79
|
-
Note: Magnetometer data is not available for Gemini IMU.
|
|
80
|
-
"""
|
|
81
|
-
if obs_keys is None:
|
|
82
|
-
obs_keys = ['ang_vel', 'acc', 'quat']
|
|
83
|
-
|
|
84
|
-
obs_out = {}
|
|
85
|
-
data = self._subscriber.get_latest_data()
|
|
86
|
-
|
|
87
|
-
for key in obs_keys:
|
|
88
|
-
if key == 'ang_vel':
|
|
89
|
-
obs_out[key] = data['ang_vel']
|
|
90
|
-
elif key == 'acc':
|
|
91
|
-
obs_out[key] = data['acc']
|
|
92
|
-
elif key == 'quat':
|
|
93
|
-
obs_out[key] = data['quat']
|
|
94
|
-
else:
|
|
95
|
-
raise ValueError(f"Invalid observation key: {key}")
|
|
96
|
-
|
|
97
|
-
return obs_out
|
|
98
|
-
|
|
99
|
-
def get_acceleration(self) -> np.ndarray | None:
|
|
100
|
-
"""Get the latest linear acceleration.
|
|
101
|
-
|
|
102
|
-
Returns:
|
|
103
|
-
Linear acceleration [x, y, z] in m/s² if available, None otherwise.
|
|
104
|
-
"""
|
|
105
|
-
return self._subscriber.get_acceleration()
|
|
106
|
-
|
|
107
|
-
def get_angular_velocity(self) -> np.ndarray | None:
|
|
108
|
-
"""Get the latest angular velocity.
|
|
109
|
-
|
|
110
|
-
Returns:
|
|
111
|
-
Angular velocity [x, y, z] in rad/s if available, None otherwise.
|
|
112
|
-
"""
|
|
113
|
-
return self._subscriber.get_angular_velocity()
|
|
114
|
-
|
|
115
|
-
def get_orientation(self) -> np.ndarray | None:
|
|
116
|
-
"""Get the latest orientation quaternion.
|
|
117
|
-
|
|
118
|
-
Returns:
|
|
119
|
-
Orientation quaternion [x, y, z, w] if available, None otherwise.
|
|
120
|
-
"""
|
|
121
|
-
return self._subscriber.get_orientation()
|
|
122
|
-
|
|
123
|
-
@property
|
|
124
|
-
def fps(self) -> float:
|
|
125
|
-
"""Get the current FPS measurement.
|
|
126
|
-
|
|
127
|
-
Returns:
|
|
128
|
-
Current frames per second measurement.
|
|
129
|
-
"""
|
|
130
|
-
return self._subscriber.fps
|
|
131
|
-
|
|
132
|
-
@property
|
|
133
|
-
def name(self) -> str:
|
|
134
|
-
"""Get the IMU name.
|
|
135
|
-
|
|
136
|
-
Returns:
|
|
137
|
-
IMU name string.
|
|
138
|
-
"""
|
|
139
|
-
return self._name
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2025 Dexmate CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 with Commons Clause License
|
|
4
|
-
# Condition v1.0 [see LICENSE for details].
|
|
5
|
-
|
|
6
|
-
"""Utility for resetting Orbbec camera USB connection."""
|
|
7
|
-
|
|
8
|
-
import os
|
|
9
|
-
import sys
|
|
10
|
-
import time
|
|
11
|
-
|
|
12
|
-
import pyudev
|
|
13
|
-
from loguru import logger
|
|
14
|
-
|
|
15
|
-
# Orbbec vendor ID constant
|
|
16
|
-
_ORBBEC_VENDOR_ID = "2bc5"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def check_root() -> None:
|
|
20
|
-
"""Verify the script is running with root privileges.
|
|
21
|
-
|
|
22
|
-
Exits the program if not running as root.
|
|
23
|
-
"""
|
|
24
|
-
if os.geteuid() != 0:
|
|
25
|
-
logger.error("This script must be run as root (sudo). Exiting...")
|
|
26
|
-
logger.info("Run with: sudo $(which python) reset_orbbec_camera_usb.py")
|
|
27
|
-
sys.exit(1)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def reset_orbbec() -> bool:
|
|
31
|
-
"""Reset the USB connection for an Orbbec camera.
|
|
32
|
-
|
|
33
|
-
Simulates unplugging and replugging the device by toggling the USB
|
|
34
|
-
authorization state.
|
|
35
|
-
|
|
36
|
-
Returns:
|
|
37
|
-
bool: True if camera was found and reset successfully, False otherwise.
|
|
38
|
-
"""
|
|
39
|
-
# Check for root privileges first
|
|
40
|
-
check_root()
|
|
41
|
-
|
|
42
|
-
# Initialize pyudev
|
|
43
|
-
context = pyudev.Context()
|
|
44
|
-
|
|
45
|
-
# Find Orbbec device
|
|
46
|
-
for device in context.list_devices(subsystem="usb"):
|
|
47
|
-
if device.properties.get("ID_VENDOR_ID") == _ORBBEC_VENDOR_ID:
|
|
48
|
-
return _reset_device(device)
|
|
49
|
-
|
|
50
|
-
logger.warning("Orbbec camera not found")
|
|
51
|
-
return False
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
def _reset_device(device: pyudev.Device) -> bool:
|
|
55
|
-
"""Reset a specific USB device.
|
|
56
|
-
|
|
57
|
-
Args:
|
|
58
|
-
device: pyudev Device object to reset
|
|
59
|
-
|
|
60
|
-
Returns:
|
|
61
|
-
bool: True if reset was successful, False otherwise
|
|
62
|
-
"""
|
|
63
|
-
# Get the parent device (USB port)
|
|
64
|
-
port = device.find_parent("usb", "usb_device")
|
|
65
|
-
|
|
66
|
-
if port is None:
|
|
67
|
-
logger.warning("Could not find parent USB device")
|
|
68
|
-
return False
|
|
69
|
-
|
|
70
|
-
# Construct path to authorized file
|
|
71
|
-
path = os.path.join(port.sys_path, "authorized")
|
|
72
|
-
|
|
73
|
-
if not os.path.exists(path):
|
|
74
|
-
logger.warning(f"Authorize file not found at: {path}")
|
|
75
|
-
return False
|
|
76
|
-
|
|
77
|
-
try:
|
|
78
|
-
# Simulate unplug
|
|
79
|
-
with open(path, "w") as f:
|
|
80
|
-
f.write("0")
|
|
81
|
-
logger.info("USB device deauthorized")
|
|
82
|
-
|
|
83
|
-
# Wait a moment for the system to process
|
|
84
|
-
time.sleep(1)
|
|
85
|
-
|
|
86
|
-
# Simulate plug
|
|
87
|
-
with open(path, "w") as f:
|
|
88
|
-
f.write("1")
|
|
89
|
-
|
|
90
|
-
logger.info(f"Orbbec camera reset successfully. Path: {path}")
|
|
91
|
-
return True
|
|
92
|
-
except IOError as e:
|
|
93
|
-
logger.error(f"Failed to reset device: {e}")
|
|
94
|
-
return False
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if __name__ == "__main__":
|
|
98
|
-
reset_orbbec()
|