Skip to content

Commit 03fedbe

Browse files
Merge pull request #398 from pollen-robotics/397-no-input-sound---badly-initialized-microphones
397 no input sound badly initialized microphones
2 parents a5148a0 + 1e9a5c4 commit 03fedbe

File tree

9 files changed

+488
-117
lines changed

9 files changed

+488
-117
lines changed

docs/troubleshooting.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,30 @@
11
# Troubleshooting
22

3+
34
## No Microphone Input
45
*For beta only*
56

6-
There is a known issue where the microphone may not initialize correctly. The best way to resolve this is to reboot the microphone array using [xvf_host](https://github.com/respeaker/reSpeaker_XVF3800_USB_4MIC_ARRAY/tree/master/host_control):
7-
8-
```bash
9-
xvf_host(.exe) REBOOT 1
10-
```
7+
There is a known issue where the microphone may not initialize correctly. Please update to [firmware 2.1.3](../src/reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.3.bin). You may need to run the [update script](../src/reachy_mini/assets/firmware/update.sh).
118

12-
Then run [examples/debug/sound_record.py](../examples/debug/sound_record.py) to check that everything is working properly.
9+
Afterwards, run [examples/debug/sound_record.py](../examples/debug/sound_record.py) to check that everything is working properly.
1310

1411
If the problem persists, check the connection of the flex cables ([see slides 45 to 47](https://huggingface.co/spaces/pollen-robotics/Reachy_Mini_Assembly_Guide)).
1512

13+
1614
## Sound Direction of Arrival Not Working
1715
*For beta only*
1816

19-
The microphone array requires firmware version 2.1.0 or higher to support this feature. The firmware is located in `src/reachy_mini/assets/firmware/*.bin`.
17+
The microphone array requires firmware version 2.1.0 or higher to support this feature. The firmware files are located in `src/reachy_mini/assets/firmware/*.bin`.
2018

2119
Refer to the [Seeed documentation](https://wiki.seeedstudio.com/respeaker_xvf3800_introduction/#update-firmware) for the upgrade process.
2220

21+
A [helper script](../src/reachy_mini/assets/firmware/update.sh) is available for Unix users.
22+
23+
2324
## Volume Is Too Low
2425
*Linux only*
2526

26-
Check with `alsamixer` that PCM1 is set to 100%. Then use PCM,0 to adjust the volume.
27+
Check in `alsamixer` that PCM1 is set to 100%. Then use PCM,0 to adjust the volume.
2728

2829
To make this change permanent:
2930
```bash
@@ -32,6 +33,7 @@ amixer -c "$CARD" set PCM,1 100%
3233
sudo alsactl store "$CARD"
3334
```
3435

36+
3537
## Circular Buffer Overrun Warning
3638

3739
When starting a client with `with ReachyMini() as mini:` in Mujoco (--sim mode), you may see the following warning:

examples/debug/sound_doa.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def main() -> None:
2626
doa = mini.media.audio.get_DoA()
2727
print(f"DOA: {doa}")
2828
if doa[1] and np.abs(doa[0] - last_doa) > THRESHOLD:
29-
print(f" Speech detected at {doa[0]:.1f}°")
29+
print(f" Speech detected at {doa[0]:.1f} radians")
3030
p_head = [np.sin(doa[0]), np.cos(doa[0]), 0.0]
3131
print(
3232
f" Pointing to x={p_head[0]:.2f}, y={p_head[1]:.2f}, z={p_head[2]:.2f}"

src/reachy_mini/assets/firmware/reachymini_ua_io16_lin_v2.1.0.bin

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:134d4f119a5f3e9eda7fedd60b1eb0274ece9b8fafcfbe5b35117c40b31beb9a
3+
size 933888
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/bash
2+
# Firmware update script for Reachy Mini
3+
# Usage: ./update.sh <firmware_file>
4+
firmware="$1"
5+
if [ -z "$firmware" ]; then
6+
echo "Usage: $0 <firmware_file>"
7+
exit 1
8+
fi
9+
dfu-util -R -e -a 1 -D "$firmware"

src/reachy_mini/media/audio_base.py

Lines changed: 7 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,30 @@
55
"""
66

77
import logging
8-
import struct
98
from abc import ABC, abstractmethod
10-
from typing import List, Optional
9+
from typing import Optional
1110

1211
import numpy as np
1312
import numpy.typing as npt
14-
import usb
15-
from libusb_package import get_libusb1_backend
13+
14+
from reachy_mini.media.audio_control_utils import ReSpeaker, init_respeaker_usb
1615

1716

1817
class AudioBase(ABC):
1918
"""Abstract class for opening and managing audio devices."""
2019

2120
SAMPLE_RATE = 16000 # respeaker samplerate
22-
TIMEOUT = 100000
23-
PARAMETERS = {
24-
"VERSION": (48, 0, 4, "ro", "uint8"),
25-
"AEC_AZIMUTH_VALUES": (33, 75, 16 + 1, "ro", "radians"),
26-
"DOA_VALUE": (20, 18, 4 + 1, "ro", "uint16"),
27-
"DOA_VALUE_RADIANS": (20, 19, 8 + 1, "ro", "radians"),
28-
}
2921

3022
def __init__(self, log_level: str = "INFO") -> None:
3123
"""Initialize the audio device."""
3224
self.logger = logging.getLogger(__name__)
3325
self.logger.setLevel(log_level)
34-
self._respeaker = self._init_respeaker_usb()
35-
# name, resid, cmdid, length, type
26+
self._respeaker: Optional[ReSpeaker] = init_respeaker_usb()
3627

3728
def __del__(self) -> None:
3829
"""Destructor to ensure resources are released."""
3930
if self._respeaker:
40-
usb.util.dispose_resources(self._respeaker)
31+
self._respeaker.close()
4132

4233
@abstractmethod
4334
def start_recording(self) -> None:
@@ -79,63 +70,6 @@ def play_sound(self, sound_file: str) -> None:
7970
"""
8071
pass
8172

82-
def _init_respeaker_usb(self) -> Optional[usb.core.Device]:
83-
try:
84-
dev = usb.core.find(
85-
idVendor=0x2886, idProduct=0x001A, backend=get_libusb1_backend()
86-
)
87-
return dev
88-
except usb.core.NoBackendError:
89-
self.logger.error(
90-
"No USB backend was found ! Make sure libusb_package is correctly installed with `pip install libusb_package`."
91-
)
92-
return None
93-
94-
def _read_usb(self, name: str) -> Optional[List[int] | List[float]]:
95-
try:
96-
data = self.PARAMETERS[name]
97-
except KeyError:
98-
self.logger.error(f"Unknown parameter: {name}")
99-
return None
100-
101-
if not self._respeaker:
102-
self.logger.warning("ReSpeaker device not found.")
103-
return None
104-
105-
resid = data[0]
106-
cmdid = 0x80 | data[1]
107-
length = data[2]
108-
109-
response = self._respeaker.ctrl_transfer(
110-
usb.util.CTRL_IN
111-
| usb.util.CTRL_TYPE_VENDOR
112-
| usb.util.CTRL_RECIPIENT_DEVICE,
113-
0,
114-
cmdid,
115-
resid,
116-
length,
117-
self.TIMEOUT,
118-
)
119-
120-
self.logger.debug(f"Response for {name}: {response}")
121-
122-
result: Optional[List[float] | List[int]] = None
123-
if data[4] == "uint8":
124-
result = response.tolist()
125-
elif data[4] == "radians":
126-
byte_data = response.tobytes()
127-
num_values = (data[2] - 1) / 4
128-
match_str = "<"
129-
for i in range(int(num_values)):
130-
match_str += "f"
131-
result = [
132-
float(x) for x in struct.unpack(match_str, byte_data[1 : data[2]])
133-
]
134-
elif data[4] == "uint16":
135-
result = response.tolist()
136-
137-
return result
138-
13973
def get_DoA(self) -> tuple[float, bool] | None:
14074
"""Get the Direction of Arrival (DoA) value from the ReSpeaker device.
14175
@@ -153,7 +87,8 @@ def get_DoA(self) -> tuple[float, bool] | None:
15387
if not self._respeaker:
15488
self.logger.warning("ReSpeaker device not found.")
15589
return None
156-
result = self._read_usb("DOA_VALUE_RADIANS")
90+
91+
result = self._respeaker.read("DOA_VALUE_RADIANS")
15792
if result is None:
15893
return None
15994
return float(result[0]), bool(result[1])

0 commit comments

Comments
 (0)