Mắt, tai và giọng nói- xây dựng ngăn xếp truyền thông của Reachy Mini
Xây dựng ngăn xếp truyền thông của Reachy Mini
- 16 min read
Mắt, tai và giọng nói: Xây dựng hệ thống truyền thông (media stack) cho Reachy Mini
Reachy Mini tương tác với môi trường xung quanh dựa trên những gì nó cảm nhận được qua camera và micrô. Do đó, việc xử lý âm thanh và hình ảnh là một phần then chốt của chú robot nhỏ này. Cả hai phiên bản, Lite và Wireless, đều có thể được sử dụng cục bộ hoặc từ xa, và chúng tôi muốn trải nghiệm đó phải thật mượt mà đối với người dùng: cùng một đoạn mã sẽ hoạt động trong mọi trường hợp.
Kết quả là bạn có thể xây dựng các ứng dụng AI trực tiếp trên các luồng âm thanh và hình ảnh của Reachy Mini, và chạy chúng ở bất cứ nơi nào hợp lý: trên robot, trên laptop của bạn, hoặc trên một Hugging Face Space có hỗ trợ GPU. Bài viết này sẽ trình bày chi tiết các lựa chọn kỹ thuật và thiết kế mà chúng tôi đã áp dụng để hiện thực hóa điều đó.
Theo dõi đối tượng chạy trên một Hugging Face Space ZeroGPU, nhận luồng camera WebRTC trực tiếp từ robot.
Phần cứng
Trước khi đi sâu vào phần mềm, hãy cùng xem qua các thiết bị phần cứng mà robot sử dụng để cảm nhận thế giới.
Các thành phần của bản Lite và Wireless được liệt kê trong các trang tài liệu tương ứng. Về cơ bản chúng giống nhau, với một vài điểm khác biệt đáng lưu ý.
Camera
Trên cả hai phiên bản, camera được sử dụng là Raspberry Pi Camera 3 Wide, với các đặc điểm sau:
- Cảm biến hình ảnh Sony IMX708
- Độ phân giải 12 MP
- Lấy nét tự động (Auto focus)
- Kết nối MIPI DSI
Cả hai camera đều có thể truyền phát ở độ phân giải 1920×1080 với tốc độ 60 fps, điều này rất hữu ích cho các ứng dụng theo dõi đối tượng. Dưới đây là thông số của camera rpi:
$ rpicam-vid --list-cameras
Available cameras
0 : imx708_wide [4608x2592 10-bit RGGB] (/base/axi/pcie@1000120000/rp1/i2c@88000/imx708@1a)
Modes: 'SRGGB10_CSI2P' : 1536x864 [120.13 fps - (768, 432)/3072x1728 crop]
2304x1296 [56.03 fps - (0, 0)/4608x2592 crop]
4608x2592 [14.35 fps - (0, 0)/4608x2592 crop]
Để trở thành thiết bị USB plug-and-play, camera của bản Lite nằm trên một bo mạch tùy chỉnh giúp nó tuân thủ chuẩn UVC. Độ phân giải tương đương, nhưng lưu ý rằng camera của bản Lite xuất ra các hình ảnh JPEG nén, sau đó sẽ được giải nén cho bạn. Tuy nhiên, tùy vào ứng dụng, bạn có thể muốn truy cập trực tiếp các khung hình JPEG.
v4l2-ctl --device=/dev/video4 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
Type: Video Capture
[0]: 'MJPG' (Motion-JPEG, compressed)
Size: Discrete 3840x2592
Interval: Discrete 0.033s (30.000 fps)
Size: Discrete 1920x1080
Interval: Discrete 0.017s (60.000 fps)
Size: Discrete 3840x2160
Interval: Discrete 0.033s (30.000 fps)
Size: Discrete 3264x2448
Interval: Discrete 0.033s (30.000 fps)
Trên macOS, nguồn
avfvideosrc(AVFoundation) của GStreamer giới hạn tốc độ khung hình ở mức 30 fps.
Camera được hiệu chuẩn bằng multical, vì vậy các thông số của nó luôn sẵn sàng cho bất kỳ tác vụ thị giác máy tính nào (xem ví dụ look_at).
Âm thanh
Micrô là một phiên bản tùy chỉnh của Seeed reSpeaker XVF3800, một mảng micrô được xây dựng quanh chip xử lý giọng nói XMOS XVF3800:
- 4 micrô kỹ thuật số PDM MEMS, được cách ly bằng gioăng silicone.
- Tốc độ lấy mẫu tối đa 16 kHz / độ nhạy −26 dBFS / SNR 64 dBA.
Chúng tôi kết hợp nó với một loa 5 W / 4 Ω. Mặc dù có bốn micrô, nhưng phần sụn (firmware) sẽ trộn và làm sạch âm thanh thu được thành một tín hiệu stereo.
Hệ thống âm thanh này có hai tính năng nổi bật:
- Khử tiếng vang âm học (Acoustic Echo Cancellation - AEC): Lọc bỏ âm thanh phát ra từ chính loa của robot, để Reachy Mini không tự “trò chuyện” với chính mình. AEC được tích hợp sẵn trong micrô và luôn bật.
- Xác định hướng âm thanh (Direction of Arrival - DoA): Xác định vị trí nguồn âm thanh trong phạm vi 180°. (Mảng micrô là dạng tuyến tính; cần bố cục hình tròn để bao phủ toàn bộ 360°). DoA được cung cấp thông qua SDK và được đọc khi ứng dụng yêu cầu.
Các micrô đã được hiệu chuẩn với sự hợp tác của Seeed trong quá trình thiết kế. Thiết lập lý tưởng là nguồn âm thanh đối diện với robot từ khoảng cách 1m. Xa hơn mức đó, chip XMOS XVF3800 cung cấp nhiều thông số mà bạn vẫn có thể tinh chỉnh nếu cấu hình mặc định không đáp ứng được nhu cầu.
Khi đã có phần cứng, công việc thực sự nằm ở phần mềm: làm sao để đưa các luồng dữ liệu này đến ứng dụng của bạn, bất kể ứng dụng đó chạy ở đâu.
Thử thách kỹ thuật
Việc truy cập luồng camera ngày nay lẽ ra phải rất đơn giản. Reachy Mini Lite có camera USB (Raspberry Pi Camera 3 Wide trên module tùy chỉnh) có thể được đọc trực tiếp từ máy tính điều khiển. Reachy Mini Wireless sử dụng cùng loại camera, nhưng nó nằm trên module tính toán nhúng của robot, vì vậy phải truy cập từ xa. SDK của chúng tôi che giấu sự khác biệt này: cùng một API sẽ trả về khung hình trên cả hai robot.
Nhưng tại sao phải dừng lại ở đó? Nếu chúng tôi có thể truyền phát camera của bản Wireless từ xa, chúng tôi cũng có thể làm điều tương tự cho bản Lite, và từ bất kỳ nền tảng nào.
Âm thanh cũng có những yêu cầu tương tự, nhưng có thêm một điểm đặc biệt: nó là hai chiều. Reachy Mini vừa nghe vừa nói.
Để xử lý tất cả các cấu hình này với một thiết kế nhất quán duy nhất, chúng tôi đã chọn GStreamer.
GStreamer
GStreamer là một thư viện đa phương tiện mã nguồn mở, được tài liệu hóa tốt, bảo trì kỹ lưỡng và đa nền tảng. Trong số nhiều tính năng, nó có thể truy cập camera và micrô, sau đó chuyển đổi dữ liệu sang bất kỳ định dạng nào cần thiết để hiển thị hoặc xử lý. GStreamer cũng đi kèm với triển khai WebRTC riêng, tiêu chuẩn hiện nay cho truyền phát phương tiện độ trễ thấp qua mạng (người đọc tò mò có thể tìm hiểu thêm tại đây).
WebRTC là công nghệ mà các trình duyệt sử dụng cho các cuộc gọi video thời gian thực. Nó thiết lập kết nối trực tiếp, độ trễ thấp giữa hai thiết bị (peer-to-peer) và truyền tải âm thanh, hình ảnh cũng như dữ liệu tùy ý. Chúng tôi sử dụng nó để truyền phát camera và micrô của robot, cũng như gửi các lệnh điều khiển ngược lại.
Hệ sinh thái plugin khổng lồ của GStreamer cũng giúp dễ dàng mở rộng khả năng của Reachy Mini. Ví dụ, các plugin chuyển lời nói thành văn bản (speech-to-text) và văn bản thành lời nói (text-to-speech) đã có sẵn.
Điều duy nhất còn thiếu là việc cài đặt dễ dàng thông qua pip. SDK của Reachy Mini cần phải đơn giản để cài đặt: không gì hơn ngoài lệnh pip install reachy-mini. Vì vậy, chúng tôi đã hợp tác với Centricular để cung cấp GStreamer dưới dạng Python wheels cho tất cả mọi người.
Với GStreamer đã được chọn, hãy xem cách chúng tôi lắp ráp các mảnh ghép thành kiến trúc truyền thông của Reachy Mini.
Kiến trúc
Kiến trúc chi tiết có trong tài liệu chính thức. Các phần dưới đây sẽ phân tích chi tiết phía server (robot) và phía client (máy tính của bạn).
Phía Server (Reachy Mini)
Mục tiêu ở phía server là làm cho camera và micrô có thể truy cập được từ cả client cục bộ và từ xa.
“Cục bộ” bao gồm hai trường hợp. Trên bản Lite, SDK đọc các khung hình từ camera kết nối USB trên máy tính điều khiển. Trên bản Wireless, một ứng dụng có thể chạy trực tiếp trên module tính toán Raspberry Pi nhúng. Bản Wireless cũng được thiết kế để dùng từ xa (người dùng có thể muốn lấy khung hình bằng SDK và xử lý trên một máy tính riêng), và truy cập từ xa là bắt buộc đối với các ứng dụng web (xem phần Ứng dụng từ xa bên dưới). Vì vậy, bản Lite cũng cần cung cấp luồng âm thanh/hình ảnh của nó.
Để đáp ứng tất cả, chúng tôi xây dựng một pipeline GStreamer duy nhất với hai đầu ra. Luồng camera được chuyển tiếp đến cả phần tử webrtcsink (cho client từ xa) và một điểm cuối IPC cục bộ: unixfdsink trên Linux và macOS, win32ipcvideosink trên Windows. Mục đích của việc chia luồng này là để tránh việc khóa camera cho một người dùng duy nhất: một người xem từ xa và một ứng dụng cục bộ có thể đọc luồng cùng một lúc.
IPC (inter-process communication - giao tiếp liên tiến trình) đơn giản là một kênh cục bộ tốc độ cao giữa hai tiến trình trên cùng một máy. Ở đây, nó cho phép ứng dụng trên thiết bị nhận các khung hình camera thô trực tiếp từ daemon mà không cần mã hóa hay giải mã trung gian.
Âm thanh đơn giản hơn vì card âm thanh có thể được mở bởi nhiều client cùng lúc. Ở phía server, chúng tôi chỉ cần định tuyến âm thanh đến phần tử WebRTC. Nếu một client cục bộ muốn mở thiết bị âm thanh, họ có thể làm trực tiếp thông qua GStreamer mà không cần IPC.
Đối với những người quen thuộc với pipeline GStreamer, điều này tương đương với:
gst-launch-1.0 webrtcsink run-signalling-server=true meta="meta,name=reachymini" name=ws libcamerasrc ! capsfilter caps=video/x-raw,width=1280,height=720,framerate=60/1,format=YUY2,colorimetry=bt709,interlace-mode=progressive ! tee name=t t. ! queue ! v4l2h264enc extra-controls="controls,repeat_sequence_header=1" ! 'video/x-h264,level=(string)4' ! ws. t. ! queue ! videoconvert ! video/x-raw,format=BGR ! unixfdsink socket-path=/tmp/reachymini_camera_socket alsasrc device=reachymini_audio_src provide-clock=false ! ws.
Đây là dành cho Reachy Mini Wireless (Raspberry Pi). Pipeline được điều chỉnh nhẹ cho các nền tảng khác.
Phía Client (Máy tính của bạn)
Phía client phản chiếu phía server. Có hai trường hợp: client cục bộ đọc khung hình từ điểm cuối IPC cục bộ, và client từ xa nhận chúng qua WebRTC. SDK tự động phát hiện trường hợp nào đang áp dụng: nếu điểm cuối cục bộ của daemon có thể truy cập được, nó sẽ dùng IPC; nếu không, nó sẽ chuyển sang WebRTC. Dù thế nào, mã của bạn vẫn gọi cùng một API. Bạn có thể tìm thấy nhiều ví dụ trong tài liệu như look at hoặc sound playback.
Cho đến nay, chúng ta đã biết SDK đọc các luồng dữ liệu như thế nào. Nhưng con đường WebRTC mở ra nhiều hơn thế: nó cho phép các ứng dụng chạy xa robot, trong trình duyệt hoặc trên một server từ xa. Hãy xem điều đó cho phép làm gì.
Pipeline GStreamer để tiêu thụ các luồng dữ liệu cục bộ là:
gst-launch-1.0 unixfdsrc socket-path=/tmp/reachymini_camera_socket ! videoconvert ! fakesink alsasrc device=reachymini_audio_src ! queue ! audioconvert ! audioresample ! fakesink
Và đối với client từ xa:
gst-launch-1.0 webrtcsrc signaller::uri="ws://<ip_robot>:8443" connect-to-first-producer=true name=src src. ! videoconvert ! autovideosink src. ! autoaudiosink
Trong SDK của chúng tôi, các sink là các phần tử appsink cung cấp các khung hình và mẫu âm thanh cho mã của bạn, nhưng các pipeline này vẫn rất hữu ích cho việc gỡ lỗi!
Ứng dụng từ xa
Một lợi thế lớn của WebRTC là ứng dụng có thể tiêu thụ luồng âm thanh/hình ảnh từ bất cứ đâu. Ngoài phương tiện truyền thông, WebRTC còn hỗ trợ trao đổi dữ liệu hai chiều, vì vậy chúng tôi cung cấp API điều khiển thông qua cùng một kết nối. Do đó, một ứng dụng từ xa có thể điều khiển robot chứ không chỉ xem.
WebRTC hướng tới kết nối ngang hàng (peer-to-peer) giữa robot và ứng dụng, giúp giữ độ trễ ở mức thấp. Chúng tôi chỉ sử dụng tài khoản Hugging Face của bạn để ghép nối robot với ứng dụng trên một signaling server: nó định danh hai điểm cuối để chúng có thể tìm thấy nhau. Ngay cả khi mọi thứ chạy trên mạng cục bộ, hai peer vẫn cần sự giới thiệu ban đầu này. Khi đã hoàn tất, dữ liệu truyền trực tiếp giữa chúng và tài khoản của bạn không còn tham gia vào quá trình này nữa. Việc dữ liệu có thực sự truyền trực tiếp hay không tùy thuộc vào nơi ứng dụng chạy, như hai phần tiếp theo sẽ giải thích.
Signaling server. Trước khi hai peer có thể nói chuyện trực tiếp, trước tiên họ phải tìm thấy nhau và đồng ý về cách kết nối (địa chỉ mạng, codec, khóa mã hóa). Signaling server là “người mai mối” chuyển tiếp cái bắt tay ban đầu này. Nó chỉ mang theo các tin nhắn thiết lập, không bao giờ mang theo âm thanh hay hình ảnh.
Ứng dụng JavaScript
Gói reachy-mini-sdk cho phép bạn kết nối các ứng dụng TypeScript/JavaScript với Reachy Mini. Ví dụ WebRTC trình diễn luồng video, âm thanh và điều khiển robot.
Kết hợp với Transformers.js, bạn có thể đưa các mô hình AI tiên tiến nhất vào robot với rất ít công sức. Nhờ WebGPU, các mô hình AI nâng cao có thể chạy trực tiếp trong trình duyệt, và vì kết nối vẫn là peer-to-peer, dữ liệu không bao giờ rời khỏi mạng cục bộ của bạn. Ví dụ, trình tạo truyện kể trước khi ngủ (bedtime story generator) dựa trên một LLM cục bộ (Gemma 3) và TTS cục bộ (Kokoro) để viết và kể chuyện.
Về cơ bản, reachy-mini-sdk.js cung cấp hệ thống đường ống WebRTC để tiêu thụ luồng âm thanh/hình ảnh từ robot. Nó cũng cung cấp một module host xử lý kết nối với Hugging Face Spaces bằng tài khoản của bạn.
Chạy mọi thứ trong trình duyệt là tuyệt vời, nhưng WebGPU bị giới hạn bởi GPU trong máy bạn, điều này có thể không đủ cho các mô hình lớn hơn. Đó là lúc tính toán từ xa (remote compute) phát huy tác dụng.
Hugging Face Spaces
Một Space nói ngắn gọn là một máy ảo từ xa, và nó có thể đi kèm với GPU mạnh mẽ. Bạn có thể kết nối Reachy Mini với một Space để đẩy các tác vụ nặng, ngốn GPU sang đó. Ví dụ, ví dụ theo dõi đối tượng (object tracking) tiêu thụ luồng video qua WebRTC và gửi ngược lại tư thế đầu để robot theo dõi đối tượng đã chọn.
Không giống như ứng dụng trình duyệt, một Space chạy trong một trung tâm dữ liệu thay vì trên mạng cục bộ của bạn, vì vậy robot và Space thường không thể tiếp cận nhau trực tiếp. Trong trường hợp đó, luồng dữ liệu được chuyển tiếp qua một TURN server (chúng tôi dựa vào dịch vụ TURN của fastrtc). Điều này thêm một bước nhảy (hop) so với đường dẫn trình duyệt peer-to-peer hoàn toàn.
TURN server. Khi hai peer không thể mở kết nối trực tiếp (do tường lửa, NAT, hoặc một trong hai nằm trong trung tâm dữ liệu), TURN server sẽ đóng vai trò là trạm chuyển tiếp: cả hai bên kết nối với nó, và nó chuyển tiếp phương tiện giữa họ. Nó đảm bảo khả năng kết nối, đánh đổi bằng một bước nhảy bổ sung.
Lợi thế lớn của cách tiếp cận này là người dùng cuối không phải cài đặt hay tải xuống bất cứ thứ gì. Mọi thứ, bao gồm cả các mô hình có thể nặng vài gigabyte, đều nằm trong Space. Điều này khiến Spaces trở thành một cách tuyệt vời để chia sẻ ứng dụng Reachy Mini tích hợp AI: bất kỳ ai cũng có thể thử nó từ trình duyệt, với robot trong vòng lặp và việc tính toán được xử lý sẵn cho họ.
Tính toán cục bộ hay từ xa là sự đánh đổi giữa sức mạnh, độ trễ và quyền riêng tư.
Độ trễ truyền phát (Streaming latency)
Một đặc tính chính của luồng video là độ trễ bạn trải nghiệm trước khi một khung hình đến với bạn. Độ trễ càng thấp càng tốt. Đối với bất kỳ tương tác vòng kín (closed-loop) nào như theo dõi khuôn mặt, các khung hình cần đến nhanh nhất có thể.
Chúng tôi đo độ trễ từ đầu đến cuối dưới dạng độ trễ glass-to-glass (từ kính đến kính): thời gian một hình ảnh đi từ ống kính camera (mặt kính đầu tiên) đến màn hình (mặt kính cuối cùng). Để đo điều này, chúng tôi xây dựng một thiết bị đơn giản làm từ một đèn LED và một quang trở. Vì thiết bị này nằm ngoài hệ thống của chúng tôi (nó đo thời gian đèn LED nhấp nháy mất bao lâu để đến được quang trở), nó đưa ra phép đo thực tế, từ đầu đến cuối.
Trong bài kiểm tra này, chúng tôi sử dụng Reachy Mini Wireless và một ứng dụng JavaScript chạy trong Chrome trên laptop Windows. GPU của laptop là Intel® UHD Graphics (TGL GT1) với bộ giải mã H.264 phần cứng. Robot và laptop nằm trên cùng một mạng cục bộ qua Wi-Fi dân dụng (5 GHz), trên màn hình 140 Hz.
Chúng tôi đo được tổng độ trễ khoảng 100 ms.
Con số này có thể thay đổi nhiều tùy thuộc vào thiết lập của bạn. Về cơ bản, độ trễ đến từ ba nơi:
- Bên gửi (Robot). Phần cứng là cố định, nhưng có thể tiết kiệm được vài mili giây bằng cách tinh chỉnh driver camera, bộ mã hóa hoặc pipeline GStreamer ở mức thấp, chủ yếu bằng cách tránh các bản sao thừa và xử lý không cần thiết.
- Mạng. Điều này phụ thuộc nhiều vào chất lượng kết nối và đường đi từ robot đến client. Trên mạng cục bộ, việc kết nối Reachy qua Wi-Fi và máy tính bằng dây vào router sẽ giúp ích. Ở khoảng cách xa (qua internet), khả năng kiểm soát tắc nghẽn của WebRTC có thể bù đắp cho sự chậm trễ bằng cách hạ thấp bitrate video, mặc dù trên Raspberry Pi điều này chỉ hoạt động với một patch mà chúng tôi vừa đẩy lên. Một thông số đáng tinh chỉnh ở đây là jitter buffer, giúp hấp thụ sự biến thiên trong thời gian đến của các gói tin: mạng càng kém, buffer cần càng lớn, đánh đổi một chút độ trễ để có hình ảnh mượt mà hơn. Trong tương lai, giao thức QUIC, được thiết kế cho các thách thức về độ trễ thấp, có thể trở thành một giải pháp thay thế cho WebRTC, và một plugin GStreamer đã tồn tại. Tuy nhiên, các bài thử nghiệm đầu tiên của chúng tôi trong điều kiện mạng cục bộ không cho thấy sự cải thiện đáng kể.
- Client. Khi một khung hình đến, nó phải được giải mã, và thời gian thực hiện việc này phụ thuộc vào phần cứng của bạn: GPU rời nhanh hơn GPU tích hợp. Sau đó, việc đưa khung hình lên màn hình cũng có độ trễ riêng.
Kết luận
Bài viết này đã cung cấp cái nhìn tổng quan về các lựa chọn thiết kế cho phép phiên bản Lite và Wireless của Reachy Mini hoạt động mượt mà, dù là cục bộ hay từ xa. Kết quả là một API nhất quán duy nhất trên các luồng âm thanh và hình ảnh mà bạn có thể tiêu thụ từ Python hoặc trình duyệt, và một lộ trình rõ ràng để xây dựng các ứng dụng AI trên đó, cho dù bạn chạy mô hình trên robot, trên laptop hay trên một Hugging Face Space.
Như thường lệ với Pollen, tất cả mã nguồn đều được mở (open source).
Link bài viết gốc
- Tags:
- Ai
- 10 June 2026
- Huggingface.co