reachy-mini 1.2.5rc1__py3-none-any.whl → 1.2.11__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.
- reachy_mini/apps/app.py +24 -21
- reachy_mini/apps/manager.py +17 -3
- reachy_mini/apps/sources/hf_auth.py +92 -0
- reachy_mini/apps/sources/hf_space.py +1 -1
- reachy_mini/apps/sources/local_common_venv.py +199 -24
- reachy_mini/apps/templates/main.py.j2 +4 -3
- reachy_mini/daemon/app/dashboard/static/js/apps.js +9 -1
- reachy_mini/daemon/app/dashboard/static/js/appstore.js +228 -0
- reachy_mini/daemon/app/dashboard/static/js/logs.js +148 -0
- reachy_mini/daemon/app/dashboard/templates/logs.html +37 -0
- reachy_mini/daemon/app/dashboard/templates/sections/appstore.html +92 -0
- reachy_mini/daemon/app/dashboard/templates/sections/cache.html +82 -0
- reachy_mini/daemon/app/dashboard/templates/sections/daemon.html +5 -0
- reachy_mini/daemon/app/dashboard/templates/settings.html +1 -0
- reachy_mini/daemon/app/main.py +172 -7
- reachy_mini/daemon/app/models.py +8 -0
- reachy_mini/daemon/app/routers/apps.py +56 -0
- reachy_mini/daemon/app/routers/cache.py +58 -0
- reachy_mini/daemon/app/routers/hf_auth.py +57 -0
- reachy_mini/daemon/app/routers/logs.py +124 -0
- reachy_mini/daemon/app/routers/state.py +25 -1
- reachy_mini/daemon/app/routers/wifi_config.py +75 -0
- reachy_mini/daemon/app/services/bluetooth/bluetooth_service.py +1 -1
- reachy_mini/daemon/app/services/bluetooth/commands/WIFI_RESET.sh +8 -0
- reachy_mini/daemon/app/services/wireless/launcher.sh +8 -2
- reachy_mini/daemon/app/services/wireless/reachy-mini-daemon.service +13 -0
- reachy_mini/daemon/backend/abstract.py +29 -9
- reachy_mini/daemon/backend/mockup_sim/__init__.py +12 -0
- reachy_mini/daemon/backend/mockup_sim/backend.py +176 -0
- reachy_mini/daemon/backend/mujoco/backend.py +0 -5
- reachy_mini/daemon/backend/robot/backend.py +78 -5
- reachy_mini/daemon/daemon.py +46 -7
- reachy_mini/daemon/utils.py +71 -15
- reachy_mini/io/zenoh_client.py +26 -0
- reachy_mini/io/zenoh_server.py +10 -6
- reachy_mini/kinematics/nn_kinematics.py +2 -2
- reachy_mini/kinematics/placo_kinematics.py +15 -15
- reachy_mini/media/__init__.py +55 -1
- reachy_mini/media/audio_base.py +185 -13
- reachy_mini/media/audio_control_utils.py +60 -5
- reachy_mini/media/audio_gstreamer.py +97 -16
- reachy_mini/media/audio_sounddevice.py +120 -19
- reachy_mini/media/audio_utils.py +110 -5
- reachy_mini/media/camera_base.py +182 -11
- reachy_mini/media/camera_constants.py +132 -4
- reachy_mini/media/camera_gstreamer.py +42 -2
- reachy_mini/media/camera_opencv.py +83 -5
- reachy_mini/media/camera_utils.py +95 -7
- reachy_mini/media/media_manager.py +139 -6
- reachy_mini/media/webrtc_client_gstreamer.py +142 -13
- reachy_mini/media/webrtc_daemon.py +72 -7
- reachy_mini/motion/recorded_move.py +76 -2
- reachy_mini/reachy_mini.py +196 -40
- reachy_mini/tools/reflash_motors.py +1 -1
- reachy_mini/tools/scan_motors.py +86 -0
- reachy_mini/tools/setup_motor.py +49 -31
- reachy_mini/utils/interpolation.py +1 -1
- reachy_mini/utils/wireless_version/startup_check.py +278 -21
- reachy_mini/utils/wireless_version/update.py +44 -1
- {reachy_mini-1.2.5rc1.dist-info → reachy_mini-1.2.11.dist-info}/METADATA +7 -6
- {reachy_mini-1.2.5rc1.dist-info → reachy_mini-1.2.11.dist-info}/RECORD +65 -53
- {reachy_mini-1.2.5rc1.dist-info → reachy_mini-1.2.11.dist-info}/WHEEL +0 -0
- {reachy_mini-1.2.5rc1.dist-info → reachy_mini-1.2.11.dist-info}/entry_points.txt +0 -0
- {reachy_mini-1.2.5rc1.dist-info → reachy_mini-1.2.11.dist-info}/licenses/LICENSE +0 -0
- {reachy_mini-1.2.5rc1.dist-info → reachy_mini-1.2.11.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,27 @@
|
|
|
1
|
-
"""Camera constants for Reachy Mini.
|
|
1
|
+
r"""Camera constants for Reachy Mini.
|
|
2
|
+
|
|
3
|
+
This module defines camera specifications and resolutions for various camera models
|
|
4
|
+
used with the Reachy Mini robot. It includes camera calibration parameters,
|
|
5
|
+
supported resolutions, and camera identification information.
|
|
6
|
+
|
|
7
|
+
The module provides:
|
|
8
|
+
- CameraResolution enum: Standardized resolutions and frame rates
|
|
9
|
+
- CameraSpecs dataclass: Base camera specifications with calibration data
|
|
10
|
+
- Specific camera specifications for different camera models
|
|
11
|
+
|
|
12
|
+
Example usage:
|
|
13
|
+
>>> from reachy_mini.media.camera_constants import CameraResolution, ReachyMiniLiteCamSpecs
|
|
14
|
+
>>>
|
|
15
|
+
>>> # Get available resolutions for Reachy Mini Lite Camera
|
|
16
|
+
>>> print("Available resolutions:")
|
|
17
|
+
>>> for res in ReachyMiniLiteCamSpecs.available_resolutions:
|
|
18
|
+
... width, height, fps = res.value
|
|
19
|
+
... print(f" {width}x{height}@{fps}fps")
|
|
20
|
+
>>>
|
|
21
|
+
>>> # Access camera calibration parameters
|
|
22
|
+
>>> print(f"Camera matrix:\\n{ReachyMiniLiteCamSpecs.K}")
|
|
23
|
+
>>> print(f"Distortion coefficients: {ReachyMiniLiteCamSpecs.D}")
|
|
24
|
+
"""
|
|
2
25
|
|
|
3
26
|
from dataclasses import dataclass, field
|
|
4
27
|
from enum import Enum
|
|
@@ -9,7 +32,48 @@ import numpy.typing as npt
|
|
|
9
32
|
|
|
10
33
|
|
|
11
34
|
class CameraResolution(Enum):
|
|
12
|
-
"""Base class for camera resolutions.
|
|
35
|
+
"""Base class for camera resolutions.
|
|
36
|
+
|
|
37
|
+
Enumeration of standardized camera resolutions and frame rates supported
|
|
38
|
+
by Reachy Mini cameras. Each enum value contains a tuple of (width, height, fps).
|
|
39
|
+
|
|
40
|
+
Attributes:
|
|
41
|
+
R1536x864at40fps: 1536x864 resolution at 40 fps
|
|
42
|
+
R1280x720at60fps: 1280x720 resolution at 60 fps (HD)
|
|
43
|
+
R1280x720at30fps: 1280x720 resolution at 30 fps (HD)
|
|
44
|
+
R1920x1080at30fps: 1920x1080 resolution at 30 fps (Full HD)
|
|
45
|
+
R1920x1080at60fps: 1920x1080 resolution at 60 fps (Full HD)
|
|
46
|
+
R2304x1296at30fps: 2304x1296 resolution at 30 fps
|
|
47
|
+
R1600x1200at30fps: 1600x1200 resolution at 30 fps
|
|
48
|
+
R3264x2448at30fps: 3264x2448 resolution at 30 fps
|
|
49
|
+
R3264x2448at10fps: 3264x2448 resolution at 10 fps
|
|
50
|
+
R3840x2592at30fps: 3840x2592 resolution at 30 fps
|
|
51
|
+
R3840x2592at10fps: 3840x2592 resolution at 10 fps
|
|
52
|
+
R3840x2160at30fps: 3840x2160 resolution at 30 fps (4K UHD)
|
|
53
|
+
R3840x2160at10fps: 3840x2160 resolution at 10 fps (4K UHD)
|
|
54
|
+
R3072x1728at10fps: 3072x1728 resolution at 10 fps
|
|
55
|
+
R4608x2592at10fps: 4608x2592 resolution at 10 fps
|
|
56
|
+
|
|
57
|
+
Note:
|
|
58
|
+
The enum values are tuples containing (width, height, frames_per_second).
|
|
59
|
+
Not all resolutions are supported by all camera models - check the specific
|
|
60
|
+
camera specifications for available resolutions.
|
|
61
|
+
|
|
62
|
+
Example:
|
|
63
|
+
>>> from reachy_mini.media.camera_constants import CameraResolution
|
|
64
|
+
>>>
|
|
65
|
+
>>> # Get resolution information
|
|
66
|
+
>>> res = CameraResolution.R1280x720at30fps
|
|
67
|
+
>>> width, height, fps = res.value
|
|
68
|
+
>>> print(f"Resolution: {width}x{height}@{fps}fps")
|
|
69
|
+
>>>
|
|
70
|
+
>>> # Check if a resolution is supported by a camera
|
|
71
|
+
>>> from reachy_mini.media.camera_constants import ReachyMiniLiteCamSpecs
|
|
72
|
+
>>> res = CameraResolution.R1920x1080at60fps
|
|
73
|
+
>>> if res in ReachyMiniLiteCamSpecs.available_resolutions:
|
|
74
|
+
... print("This resolution is supported")
|
|
75
|
+
|
|
76
|
+
"""
|
|
13
77
|
|
|
14
78
|
R1536x864at40fps = (1536, 864, 40)
|
|
15
79
|
|
|
@@ -37,7 +101,48 @@ class CameraResolution(Enum):
|
|
|
37
101
|
|
|
38
102
|
@dataclass
|
|
39
103
|
class CameraSpecs:
|
|
40
|
-
"""Base camera specifications.
|
|
104
|
+
"""Base camera specifications.
|
|
105
|
+
|
|
106
|
+
Dataclass containing specifications for a camera model, including supported
|
|
107
|
+
resolutions, calibration parameters, and USB identification information.
|
|
108
|
+
|
|
109
|
+
Attributes:
|
|
110
|
+
name (str): Human-readable name of the camera model.
|
|
111
|
+
available_resolutions (List[CameraResolution]): List of supported resolutions
|
|
112
|
+
and frame rates for this camera model.
|
|
113
|
+
default_resolution (CameraResolution): Default resolution used when the camera
|
|
114
|
+
is initialized.
|
|
115
|
+
vid (int): USB Vendor ID for identifying this camera model.
|
|
116
|
+
pid (int): USB Product ID for identifying this camera model.
|
|
117
|
+
K (npt.NDArray[np.float64]): 3x3 camera intrinsic matrix containing focal
|
|
118
|
+
lengths and principal point coordinates.
|
|
119
|
+
D (npt.NDArray[np.float64]): 5-element array containing distortion coefficients
|
|
120
|
+
(k1, k2, p1, p2, k3) for radial and tangential distortion.
|
|
121
|
+
|
|
122
|
+
Note:
|
|
123
|
+
The intrinsic matrix K has the format:
|
|
124
|
+
[[fx, 0, cx],
|
|
125
|
+
[ 0, fy, cy],
|
|
126
|
+
[ 0, 0, 1]]
|
|
127
|
+
|
|
128
|
+
Where fx, fy are focal lengths in pixels, and cx, cy are the principal
|
|
129
|
+
point coordinates (typically near the image center).
|
|
130
|
+
|
|
131
|
+
Example:
|
|
132
|
+
>>> from reachy_mini.media.camera_constants import CameraSpecs
|
|
133
|
+
>>>
|
|
134
|
+
>>> # Create a custom camera specification
|
|
135
|
+
>>> custom_specs = CameraSpecs(
|
|
136
|
+
... name="custom_camera",
|
|
137
|
+
... available_resolutions=[CameraResolution.R1280x720at30fps],
|
|
138
|
+
... default_resolution=CameraResolution.R1280x720at30fps,
|
|
139
|
+
... vid=0x1234,
|
|
140
|
+
... pid=0x5678,
|
|
141
|
+
... K=np.array([[800, 0, 640], [0, 800, 360], [0, 0, 1]]),
|
|
142
|
+
... D=np.zeros(5)
|
|
143
|
+
... )
|
|
144
|
+
|
|
145
|
+
"""
|
|
41
146
|
|
|
42
147
|
name: str = ""
|
|
43
148
|
available_resolutions: List[CameraResolution] = field(default_factory=list)
|
|
@@ -106,6 +211,7 @@ class ReachyMiniWirelessCamSpecs(ReachyMiniLiteCamSpecs):
|
|
|
106
211
|
|
|
107
212
|
name = "wireless"
|
|
108
213
|
available_resolutions = [
|
|
214
|
+
CameraResolution.R1280x720at30fps, # Default for H264 Level 3.1 (Safari/WebKit)
|
|
109
215
|
CameraResolution.R1920x1080at30fps,
|
|
110
216
|
CameraResolution.R1280x720at60fps,
|
|
111
217
|
CameraResolution.R3840x2592at10fps,
|
|
@@ -113,7 +219,8 @@ class ReachyMiniWirelessCamSpecs(ReachyMiniLiteCamSpecs):
|
|
|
113
219
|
CameraResolution.R3264x2448at10fps,
|
|
114
220
|
CameraResolution.R3072x1728at10fps,
|
|
115
221
|
]
|
|
116
|
-
|
|
222
|
+
# 720p@30fps for H264 Level 3.1 compatibility (Safari/WebKit)
|
|
223
|
+
default_resolution = CameraResolution.R1280x720at30fps
|
|
117
224
|
|
|
118
225
|
|
|
119
226
|
@dataclass
|
|
@@ -150,3 +257,24 @@ class MujocoCameraSpecs(CameraSpecs):
|
|
|
150
257
|
]
|
|
151
258
|
)
|
|
152
259
|
D = np.zeros((5,)) # no distortion
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
@dataclass
|
|
263
|
+
class GenericWebcamSpecs(CameraSpecs):
|
|
264
|
+
"""Generic webcam specifications (fallback for any webcam)."""
|
|
265
|
+
|
|
266
|
+
name = "generic"
|
|
267
|
+
available_resolutions = [
|
|
268
|
+
CameraResolution.R1280x720at30fps,
|
|
269
|
+
CameraResolution.R1920x1080at30fps,
|
|
270
|
+
]
|
|
271
|
+
default_resolution = CameraResolution.R1280x720at30fps
|
|
272
|
+
# Approximate camera matrix for generic 720p webcam
|
|
273
|
+
K = np.array(
|
|
274
|
+
[
|
|
275
|
+
[640.0, 0.0, 640.0],
|
|
276
|
+
[0.0, 640.0, 360.0],
|
|
277
|
+
[0.0, 0.0, 1.0],
|
|
278
|
+
]
|
|
279
|
+
)
|
|
280
|
+
D = np.zeros((5,)) # assume no distortion
|
|
@@ -1,7 +1,42 @@
|
|
|
1
1
|
"""GStreamer camera backend.
|
|
2
2
|
|
|
3
3
|
This module provides an implementation of the CameraBase class using GStreamer.
|
|
4
|
-
|
|
4
|
+
It offers advanced video processing capabilities including hardware-accelerated
|
|
5
|
+
decoding, image format conversion, and support for various camera models.
|
|
6
|
+
|
|
7
|
+
The GStreamer camera backend features:
|
|
8
|
+
- Hardware-accelerated video decoding
|
|
9
|
+
- Support for multiple camera models (Reachy Mini Lite, Arducam, etc.)
|
|
10
|
+
- Advanced image processing pipelines
|
|
11
|
+
- Automatic camera detection and configuration
|
|
12
|
+
- Multiple resolution and frame rate support
|
|
13
|
+
- JPEG and raw image format support
|
|
14
|
+
|
|
15
|
+
Example usage:
|
|
16
|
+
>>> from reachy_mini.media.camera_gstreamer import GStreamerCamera
|
|
17
|
+
>>> from reachy_mini.media.camera_constants import CameraResolution
|
|
18
|
+
>>>
|
|
19
|
+
>>> # Create GStreamer camera instance
|
|
20
|
+
>>> camera = GStreamerCamera(log_level="INFO")
|
|
21
|
+
>>>
|
|
22
|
+
>>> # Open the camera
|
|
23
|
+
>>> camera.open()
|
|
24
|
+
>>>
|
|
25
|
+
>>> # Set resolution (optional)
|
|
26
|
+
>>> camera.set_resolution(CameraResolution.R1280x720at30fps)
|
|
27
|
+
>>>
|
|
28
|
+
>>> # Capture frames
|
|
29
|
+
>>> frame = camera.read()
|
|
30
|
+
>>> if frame is not None:
|
|
31
|
+
... print(f"Captured frame with shape: {frame.shape}")
|
|
32
|
+
>>>
|
|
33
|
+
>>> # Get camera information
|
|
34
|
+
>>> width, height = camera.resolution
|
|
35
|
+
>>> fps = camera.framerate
|
|
36
|
+
>>> print(f"Camera: {width}x{height}@{fps}fps")
|
|
37
|
+
>>>
|
|
38
|
+
>>> # Clean up
|
|
39
|
+
>>> camera.close()
|
|
5
40
|
"""
|
|
6
41
|
|
|
7
42
|
import os
|
|
@@ -78,7 +113,7 @@ class GStreamerCamera(CameraBase):
|
|
|
78
113
|
self.pipeline.add(camsrc)
|
|
79
114
|
queue = Gst.ElementFactory.make("queue")
|
|
80
115
|
self.pipeline.add(queue)
|
|
81
|
-
videoconvert = Gst.ElementFactory.make("
|
|
116
|
+
videoconvert = Gst.ElementFactory.make("v4l2convert")
|
|
82
117
|
self.pipeline.add(videoconvert)
|
|
83
118
|
camsrc.link(queue)
|
|
84
119
|
queue.link(videoconvert)
|
|
@@ -96,6 +131,11 @@ class GStreamerCamera(CameraBase):
|
|
|
96
131
|
else:
|
|
97
132
|
camsrc = Gst.ElementFactory.make("v4l2src")
|
|
98
133
|
camsrc.set_property("device", cam_path)
|
|
134
|
+
# examples of camera controls settings:
|
|
135
|
+
# extra_controls_structure = Gst.Structure.new_empty("extra-controls")
|
|
136
|
+
# extra_controls_structure.set_value("saturation", 64)
|
|
137
|
+
# extra_controls_structure.set_value("brightness", 50)
|
|
138
|
+
# camsrc.set_property("extra-controls", extra_controls_structure)
|
|
99
139
|
self.pipeline.add(camsrc)
|
|
100
140
|
queue = Gst.ElementFactory.make("queue")
|
|
101
141
|
self.pipeline.add(queue)
|
|
@@ -1,6 +1,51 @@
|
|
|
1
|
-
"""
|
|
1
|
+
r"""OpenCV camera backend.
|
|
2
2
|
|
|
3
3
|
This module provides an implementation of the CameraBase class using OpenCV.
|
|
4
|
+
It offers cross-platform camera support with automatic camera detection and
|
|
5
|
+
configuration for various Reachy Mini camera models.
|
|
6
|
+
|
|
7
|
+
The OpenCV camera backend features:
|
|
8
|
+
- Cross-platform compatibility (Windows, macOS, Linux)
|
|
9
|
+
- Automatic camera detection and model identification
|
|
10
|
+
- Support for multiple camera models (Reachy Mini Lite, Beta (Arducam), etc.)
|
|
11
|
+
- Resolution and frame rate configuration
|
|
12
|
+
- Camera calibration parameter access
|
|
13
|
+
- Simulation mode support (Mujoco)
|
|
14
|
+
|
|
15
|
+
Note:
|
|
16
|
+
This class is typically used internally by the MediaManager when the DEFAULT
|
|
17
|
+
backend is selected. Direct usage is possible but usually not necessary.
|
|
18
|
+
|
|
19
|
+
Example usage via MediaManager:
|
|
20
|
+
>>> from reachy_mini.media.media_manager import MediaManager, MediaBackend
|
|
21
|
+
>>>
|
|
22
|
+
>>> # Create media manager with OpenCV backend (default)
|
|
23
|
+
>>> media = MediaManager(backend=MediaBackend.DEFAULT, log_level="INFO")
|
|
24
|
+
>>>
|
|
25
|
+
>>> # Capture frames
|
|
26
|
+
>>> frame = media.get_frame()
|
|
27
|
+
>>> if frame is not None:
|
|
28
|
+
... print(f"Captured frame with shape: {frame.shape}")
|
|
29
|
+
... cv2.imshow("Camera", frame)
|
|
30
|
+
... cv2.waitKey(1)
|
|
31
|
+
>>>
|
|
32
|
+
>>> # Get camera information
|
|
33
|
+
>>> if media.camera is not None:
|
|
34
|
+
... width, height = media.camera.resolution
|
|
35
|
+
... fps = media.camera.framerate
|
|
36
|
+
... print(f"Camera: {width}x{height}@{fps}fps")
|
|
37
|
+
...
|
|
38
|
+
... # Access calibration information
|
|
39
|
+
... K = media.camera.K
|
|
40
|
+
... D = media.camera.D
|
|
41
|
+
... if K is not None:
|
|
42
|
+
... print(f"Camera matrix:\\n{K}")
|
|
43
|
+
... if D is not None:
|
|
44
|
+
... print(f"Distortion coefficients: {D}")
|
|
45
|
+
>>>
|
|
46
|
+
>>> # Clean up
|
|
47
|
+
>>> media.close()
|
|
48
|
+
|
|
4
49
|
"""
|
|
5
50
|
|
|
6
51
|
from typing import Optional, cast
|
|
@@ -20,13 +65,33 @@ from .camera_base import CameraBase
|
|
|
20
65
|
|
|
21
66
|
|
|
22
67
|
class OpenCVCamera(CameraBase):
|
|
23
|
-
"""Camera implementation using OpenCV.
|
|
68
|
+
"""Camera implementation using OpenCV.
|
|
69
|
+
|
|
70
|
+
This class implements the CameraBase interface using OpenCV, providing
|
|
71
|
+
cross-platform camera support for Reachy Mini robots. It automatically
|
|
72
|
+
detects and configures supported camera models.
|
|
73
|
+
|
|
74
|
+
Attributes:
|
|
75
|
+
Inherits all attributes from CameraBase.
|
|
76
|
+
Additionally manages OpenCV VideoCapture objects and camera connections.
|
|
77
|
+
|
|
78
|
+
"""
|
|
24
79
|
|
|
25
80
|
def __init__(
|
|
26
81
|
self,
|
|
27
82
|
log_level: str = "INFO",
|
|
28
83
|
) -> None:
|
|
29
|
-
"""Initialize the OpenCV camera.
|
|
84
|
+
"""Initialize the OpenCV camera.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
log_level (str): Logging level for camera operations.
|
|
88
|
+
Default: 'INFO'.
|
|
89
|
+
|
|
90
|
+
Note:
|
|
91
|
+
This constructor initializes the OpenCV camera system. The actual
|
|
92
|
+
camera device is opened when the open() method is called.
|
|
93
|
+
|
|
94
|
+
"""
|
|
30
95
|
super().__init__(log_level=log_level)
|
|
31
96
|
self.cap: Optional[cv2.VideoCapture] = None
|
|
32
97
|
|
|
@@ -40,7 +105,10 @@ class OpenCVCamera(CameraBase):
|
|
|
40
105
|
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self._resolution.value[1])
|
|
41
106
|
|
|
42
107
|
def open(self, udp_camera: Optional[str] = None) -> None:
|
|
43
|
-
"""Open the camera using OpenCV VideoCapture.
|
|
108
|
+
"""Open the camera using OpenCV VideoCapture.
|
|
109
|
+
|
|
110
|
+
See CameraBase.open() for complete documentation.
|
|
111
|
+
"""
|
|
44
112
|
if udp_camera:
|
|
45
113
|
self.cap = cv2.VideoCapture(udp_camera)
|
|
46
114
|
self.camera_specs = cast(CameraSpecs, MujocoCameraSpecs)
|
|
@@ -57,6 +125,11 @@ class OpenCVCamera(CameraBase):
|
|
|
57
125
|
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self._resolution.value[0])
|
|
58
126
|
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self._resolution.value[1])
|
|
59
127
|
|
|
128
|
+
# example of camera controls settings:
|
|
129
|
+
# self.cap.set(cv2.CAP_PROP_BRIGHTNESS, 0.5)
|
|
130
|
+
# self.cap.set(cv2.CAP_PROP_CONTRAST, 0.5)
|
|
131
|
+
# self.cap.set(cv2.CAP_PROP_SATURATION, 64)
|
|
132
|
+
|
|
60
133
|
self.resized_K = self.camera_specs.K
|
|
61
134
|
|
|
62
135
|
if not self.cap.isOpened():
|
|
@@ -65,6 +138,8 @@ class OpenCVCamera(CameraBase):
|
|
|
65
138
|
def read(self) -> Optional[npt.NDArray[np.uint8]]:
|
|
66
139
|
"""Read a frame from the camera.
|
|
67
140
|
|
|
141
|
+
See CameraBase.read() for complete documentation.
|
|
142
|
+
|
|
68
143
|
Returns:
|
|
69
144
|
The frame as a uint8 numpy array, or None if no frame could be read.
|
|
70
145
|
|
|
@@ -83,7 +158,10 @@ class OpenCVCamera(CameraBase):
|
|
|
83
158
|
return cast(npt.NDArray[np.uint8], frame)
|
|
84
159
|
|
|
85
160
|
def close(self) -> None:
|
|
86
|
-
"""Release the camera resource.
|
|
161
|
+
"""Release the camera resource.
|
|
162
|
+
|
|
163
|
+
See CameraBase.close() for complete documentation.
|
|
164
|
+
"""
|
|
87
165
|
if self.cap is not None:
|
|
88
166
|
self.cap.release()
|
|
89
167
|
self.cap = None
|
|
@@ -1,4 +1,28 @@
|
|
|
1
|
-
"""Camera utility for Reachy Mini.
|
|
1
|
+
"""Camera utility for Reachy Mini.
|
|
2
|
+
|
|
3
|
+
This module provides utility functions for working with cameras on the Reachy Mini robot.
|
|
4
|
+
It includes functions for detecting and identifying different camera models, managing
|
|
5
|
+
camera connections, and handling camera-specific configurations.
|
|
6
|
+
|
|
7
|
+
Supported camera types:
|
|
8
|
+
- Reachy Mini Lite Camera
|
|
9
|
+
- Arducam
|
|
10
|
+
- Older Raspberry Pi Camera
|
|
11
|
+
- Generic Webcams (fallback)
|
|
12
|
+
|
|
13
|
+
Example usage:
|
|
14
|
+
>>> from reachy_mini.media.camera_utils import find_camera
|
|
15
|
+
>>>
|
|
16
|
+
>>> # Find and open the Reachy Mini camera
|
|
17
|
+
>>> cap, camera_specs = find_camera()
|
|
18
|
+
>>> if cap is not None:
|
|
19
|
+
... print(f"Found {camera_specs.name} camera")
|
|
20
|
+
... # Use the camera
|
|
21
|
+
... ret, frame = cap.read()
|
|
22
|
+
... cap.release()
|
|
23
|
+
... else:
|
|
24
|
+
... print("No camera found")
|
|
25
|
+
"""
|
|
2
26
|
|
|
3
27
|
import platform
|
|
4
28
|
from typing import Optional, Tuple, cast
|
|
@@ -9,6 +33,7 @@ from cv2_enumerate_cameras import enumerate_cameras
|
|
|
9
33
|
from reachy_mini.media.camera_constants import (
|
|
10
34
|
ArducamSpecs,
|
|
11
35
|
CameraSpecs,
|
|
36
|
+
GenericWebcamSpecs,
|
|
12
37
|
OlderRPiCamSpecs,
|
|
13
38
|
ReachyMiniLiteCamSpecs,
|
|
14
39
|
)
|
|
@@ -19,14 +44,45 @@ def find_camera(
|
|
|
19
44
|
) -> Tuple[Optional[cv2.VideoCapture], Optional[CameraSpecs]]:
|
|
20
45
|
"""Find and return the Reachy Mini camera.
|
|
21
46
|
|
|
22
|
-
Looks for the Reachy Mini camera first, then Arducam, then older Raspberry Pi Camera.
|
|
47
|
+
Looks for the Reachy Mini camera first, then Arducam, then older Raspberry Pi Camera.
|
|
48
|
+
Returns None if no camera is found. Falls back to generic webcam if no specific camera is detected.
|
|
23
49
|
|
|
24
50
|
Args:
|
|
25
51
|
apiPreference (int): Preferred API backend for the camera. Default is cv2.CAP_ANY.
|
|
26
|
-
|
|
52
|
+
Options include cv2.CAP_V4L2 (Linux), cv2.CAP_DSHOW (Windows),
|
|
53
|
+
cv2.CAP_MSMF (Windows), etc.
|
|
54
|
+
no_cap (bool): If True, close the camera after finding it. Useful for testing
|
|
55
|
+
camera detection without keeping the camera open. Default is False.
|
|
27
56
|
|
|
28
57
|
Returns:
|
|
29
|
-
cv2.VideoCapture
|
|
58
|
+
Tuple[Optional[cv2.VideoCapture], Optional[CameraSpecs]]: A tuple containing:
|
|
59
|
+
- cv2.VideoCapture: A VideoCapture object if the camera is found and opened
|
|
60
|
+
successfully, otherwise None.
|
|
61
|
+
- CameraSpecs: The camera specifications for the detected camera, or None if
|
|
62
|
+
no camera was found.
|
|
63
|
+
|
|
64
|
+
Note:
|
|
65
|
+
This function tries to detect cameras in the following order:
|
|
66
|
+
1. Reachy Mini Lite Camera (preferred)
|
|
67
|
+
2. Older Raspberry Pi Camera
|
|
68
|
+
3. Arducam
|
|
69
|
+
4. Generic Webcam (fallback)
|
|
70
|
+
|
|
71
|
+
The function automatically sets the appropriate video codec (MJPG) for
|
|
72
|
+
Reachy Mini and Raspberry Pi cameras to ensure compatibility.
|
|
73
|
+
|
|
74
|
+
Example:
|
|
75
|
+
>>> cap, specs = find_camera()
|
|
76
|
+
>>> if cap is not None:
|
|
77
|
+
... print(f"Found {specs.name} camera")
|
|
78
|
+
... # Set resolution
|
|
79
|
+
... cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
|
|
80
|
+
... cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
|
|
81
|
+
... # Capture a frame
|
|
82
|
+
... ret, frame = cap.read()
|
|
83
|
+
... cap.release()
|
|
84
|
+
... else:
|
|
85
|
+
... print("No camera found")
|
|
30
86
|
|
|
31
87
|
"""
|
|
32
88
|
cap = find_camera_by_vid_pid(
|
|
@@ -55,6 +111,13 @@ def find_camera(
|
|
|
55
111
|
cap.release()
|
|
56
112
|
return cap, cast(CameraSpecs, ArducamSpecs)
|
|
57
113
|
|
|
114
|
+
# Fallback: try to open any available webcam (useful for mockup-sim mode on desktop)
|
|
115
|
+
cap = cv2.VideoCapture(0)
|
|
116
|
+
if cap is not None and cap.isOpened():
|
|
117
|
+
if no_cap:
|
|
118
|
+
cap.release()
|
|
119
|
+
return cap, cast(CameraSpecs, GenericWebcamSpecs)
|
|
120
|
+
|
|
58
121
|
return None, None
|
|
59
122
|
|
|
60
123
|
|
|
@@ -66,12 +129,37 @@ def find_camera_by_vid_pid(
|
|
|
66
129
|
"""Find and return a camera with the specified VID and PID.
|
|
67
130
|
|
|
68
131
|
Args:
|
|
69
|
-
vid (int): Vendor ID of the camera. Default is
|
|
70
|
-
pid (int): Product ID of the camera. Default is
|
|
132
|
+
vid (int): Vendor ID of the camera. Default is ReachyMiniLiteCamSpecs.vid (0x38FB).
|
|
133
|
+
pid (int): Product ID of the camera. Default is ReachyMiniLiteCamSpecs.pid (0x1002).
|
|
71
134
|
apiPreference (int): Preferred API backend for the camera. Default is cv2.CAP_ANY.
|
|
135
|
+
On Linux, this automatically uses cv2.CAP_V4L2 for better compatibility.
|
|
72
136
|
|
|
73
137
|
Returns:
|
|
74
|
-
cv2.VideoCapture | None: A VideoCapture object if the camera
|
|
138
|
+
cv2.VideoCapture | None: A VideoCapture object if the camera with matching
|
|
139
|
+
VID/PID is found and opened successfully, otherwise None.
|
|
140
|
+
|
|
141
|
+
Note:
|
|
142
|
+
This function uses the cv2_enumerate_cameras package to enumerate available
|
|
143
|
+
cameras and find one with the specified USB Vendor ID and Product ID.
|
|
144
|
+
This is useful for selecting specific camera models when multiple cameras
|
|
145
|
+
are connected to the system.
|
|
146
|
+
|
|
147
|
+
The Arducam camera creates two /dev/videoX devices that enumerate_cameras
|
|
148
|
+
cannot differentiate, so this function tries to open each potential device
|
|
149
|
+
until it finds a working one.
|
|
150
|
+
|
|
151
|
+
Example:
|
|
152
|
+
>>> # Find Reachy Mini Lite Camera by its default VID/PID
|
|
153
|
+
>>> cap = find_camera_by_vid_pid()
|
|
154
|
+
>>> if cap is not None:
|
|
155
|
+
... print("Found Reachy Mini Lite Camera")
|
|
156
|
+
... cap.release()
|
|
157
|
+
>>>
|
|
158
|
+
>>> # Find a specific camera by custom VID/PID
|
|
159
|
+
>>> cap = find_camera_by_vid_pid(vid=0x0C45, pid=0x636D) # Arducam
|
|
160
|
+
>>> if cap is not None:
|
|
161
|
+
... print("Found Arducam")
|
|
162
|
+
... cap.release()
|
|
75
163
|
|
|
76
164
|
"""
|
|
77
165
|
if platform.system() == "Linux":
|