Menu

andipanda.dev

CaRadio: od pierwszych eksperymentów z Carlinkit do działającego CarPlay

W poprzednich artykułach opisałem, jak budowałem własne radio samochodowe CaRadio na Raspberry Pi, próbowałem wykorzystać elektronikę Volkswagena RCD510 i ostatecznie zamontowałem działający system w swoim Golfie.

Do tej pory jednak prawie nie opowiadałem o programowej części projektu.

Samo Raspberry Pi, wyświetlacz i wzmacniacz nie wystarczą przecież, żeby radio stało się pełnoprawnym systemem multimedialnym. Potrzebowałem CarPlay — najlepiej bezprzewodowego, z nawigacją, muzyką i obsługą przez ekran dotykowy.

Dziś wszystko to działa już w samochodzie. Droga do tego rezultatu okazała się jednak znacznie dłuższa, niż początkowo zakładałem.

Wszystko zaczęło się od wyboru radia

Kilka lat temu szukałem nowego radia do samochodu. Wśród dostępnych opcji jednymi z najciekawszych wydawały mi się urządzenia Teyes.

Były oferowane w różnych wersjach, zarówno z obsługą Apple CarPlay, jak i bez niej.

Podczas poszukiwań natrafiłem na instrukcje pokazujące, jak dodać obsługę CarPlay do niektórych modeli Teyes przez zamontowanie dodatkowego układu scalonego.

Właśnie wtedy przyszła mi do głowy myśl: skoro takie rozwiązanie można zastosować w radiu z Androidem, może dałoby się je przystosować również do Raspberry Pi?

Miałem już doświadczenie w budowaniu własnego radia samochodowego, więc pomysł wykorzystania Raspberry Pi zamiast gotowego urządzenia wydawał się całkiem naturalny.

Zacząłem szukać informacji o układach scalonych, sposobach podłączenia i programowych implementacjach CarPlay.

Dość szybko okazało się jednak, że sprawa jest nieco bardziej skomplikowana niż samo podłączenie jednego układu.

Pierwsze spotkanie z pycarplay

Podczas poszukiwań trafiłem na projekt pycarplay na GitHubie.

Była to implementacja napisana w Pythonie, umożliwiająca współpracę z adapterami USB CarPlay.

Początkowo nie do końca rozumiałem, jak to wszystko działa. Z opisu wynikało, że projekt pozwala uruchomić CarPlay na Raspberry Pi, ale wymaga dodatkowego sprzętu.

Stopniowo, analizując dokumentację i szukając informacji w internecie, dowiedziałem się, że potrzebny jest specjalny adapter USB, podobny do Carlinkit.

Pozostało go znaleźć.

Na Allegro trafiłem na niedrogi adapter powystawowy — klon Carlinkit. Jak na tamte czasy kosztował naprawdę niewiele, więc postanowiłem spróbować.

Co ciekawe, ten sam adapter do dziś działa w moim radiu.

Po zakupie podłączyłem go do Raspberry Pi, zainstalowałem potrzebne oprogramowanie i po raz pierwszy zobaczyłem działający CarPlay na własnym urządzeniu.

To był ważny moment.

Wcześniej tylko przypuszczałem, że taki system można zbudować samodzielnie. Teraz stało się jasne, że pomysł rzeczywiście jest wykonalny.

CarPlay w przeglądarce

O ile dobrze pamiętam, pierwsza implementacja, którą udało mi się uruchomić, była związana z pomysłem wykorzystania CarPlay w samochodach Tesla.

Raspberry Pi pełniło funkcję niewielkiego serwera WWW, a obraz CarPlay można było otworzyć w przeglądarce.

Do eksperymentów było to całkiem wygodne rozwiązanie.

System się uruchamiał, telefon się łączył, pojawiał się obraz i ogólnie wszystko działało stosunkowo dobrze.

Miałem jednak inny cel.

Nie zamierzałem używać przeglądarki jako głównego interfejsu radia. Chciałem mieć osobną aplikację, którą można byłoby zintegrować z własnym systemem i obsługiwać bezpośrednio na ekranie dotykowym.

Dlatego kontynuowałem poszukiwania innych implementacji.

Od mpv do VLC

Kolejnym odkryciem był projekt carplay-receiver.

On również został napisany w Pythonie, ale wykorzystywał inne podejście do wyświetlania obrazu. Zamiast przeglądarki obraz CarPlay był wyświetlany przez odtwarzacz multimedialny mpv.

To było już bliższe temu, czego potrzebowałem.

Zacząłem analizować kod i próbować uruchomić projekt na swoim Raspberry Pi.

Jednak z mpv coś mi nie wychodziło. Dziś trudno już przypomnieć sobie wszystkie szczegóły, ale nie udało mi się szybko osiągnąć zamierzonego rezultatu.

Miałem za to wcześniejsze doświadczenie z VLC.

Postanowiłem więc przerobić wyświetlanie obrazu tak, aby korzystało ze znanego mi odtwarzacza.

Po kilku eksperymentach udało się w końcu uruchomić CarPlay.

Niestety działanie było dalekie od ideału.

Dopóki system uruchamiałem tylko na biurku, można było jeszcze zaakceptować jego niedoskonałości. Kiedy jednak zacząłem myśleć o używaniu go w samochodzie, stało się jasne, że wydajność pozostawia wiele do życzenia.

Obraz wyraźnie się zacinał, a przyczyn nie udało mi się szybko ustalić.

Próba przejścia na C++

Miałem już wtedy doświadczenie w programowaniu w C++ z wykorzystaniem Qt.

Pojawił się więc pomysł, żeby zrezygnować z Pythona i przenieść potrzebną funkcjonalność do własnej aplikacji.

Wydawało mi się, że takie podejście zapewni większą kontrolę nad systemem i pozwoli wyeliminować przynajmniej część problemów z wydajnością.

Jednak uruchomienie gotowego projektu to jedno, a zrozumienie jego wewnętrznego działania na tyle dobrze, żeby przepisać go w innym języku, to zupełnie inna sprawa.

Musiałem zrozumieć, jak wygląda komunikacja z adapterem USB, w jaki sposób przesyłane są obraz i dźwięk oraz jak obsługiwane są dotknięcia ekranu i inne polecenia sterujące.

W tamtym czasie zabrakło mi do tego wiedzy i wolnego czasu.

Próba zakończyła się niepowodzeniem.

W rezultacie odłożyłem prace nad CarPlay dla Raspberry Pi. Jak się później okazało, na prawie dwa lata.

Powrót do projektu

Po prawie dwóch latach postanowiłem ponownie przyjrzeć się dostępnym rozwiązaniom. W tym czasie wiele się zmieniło i miałem nadzieję, że pojawiły się nowe projekty, które pomogą mi ruszyć dalej.

Podczas poszukiwań natrafiłem na projekt FastCarPlay.

FastCarPlay został napisany w C++, czyli w języku, w którym od początku chciałem pracować.

Nie oznaczało to jednak, że wystarczy pobrać projekt, skompilować go i od razu otrzymać gotowe radio.

Po pierwszym uruchomieniu pojawiły się problemy, które trzeba było stopniowo rozwiązywać.

Tym razem miałem jednak znacznie lepszy punkt wyjścia.

W przeciwieństwie do wcześniejszych eksperymentów z Pythonem mogłem pracować bezpośrednio z kodem C++ i stopniowo dostosowywać go do własnych potrzeb.

Nie tylko FastCarPlay

Podczas analizowania istniejących rozwiązań trafiłem również na projekt LIVI.

Był interesujący jako kolejna implementacja, na podstawie której można było poznawać sposób komunikacji z Carlinkit i porównywać różne podejścia techniczne.

Nie zdecydowałem się jednak wykorzystać LIVI jako podstawy CaRadio.

Na potrzeby mojego projektu wydawał się zbyt rozbudowany, a języka, w którym został napisany, praktycznie nie znałem.

Mimo to takie projekty są bardzo przydatne.

Kiedy próbuje się zrozumieć słabo udokumentowany protokół, możliwość zobaczenia, jak ten sam problem rozwiązali różni programiści, znacznie ułatwia pracę.

Co więcej, LIVI nadal jest aktywnie rozwijany i całkiem możliwe, że w niektórych obszarach wyprzedza już obecną wersję CaRadio.

Od eksperymentu do radia samochodowego

Po uruchomieniu FastCarPlay prace nad CaRadio wreszcie ruszyły z miejsca.

Stopniowo udało się doprowadzić oprogramowanie do stanu, w którym CarPlay nadawał się nie tylko do eksperymentów na biurku, ale również do codziennego użytkowania w samochodzie.

Z czasem aplikacja otrzymała własny interfejs napisany w C++ z wykorzystaniem SDL3.

Nie musiałem już otwierać przeglądarki ani uruchamiać osobnego odtwarzacza multimedialnego, żeby wyświetlić CarPlay.

Wszystko stało się częścią jednej aplikacji, zaprojektowanej do obsługi przez ekran dotykowy radia samochodowego.

Oczywiście nie oznacza to, że napisałem implementację CarPlay od zera.

Podstawą były wyniki pracy innych programistów, którzy badali komunikację z adapterami USB i udostępnili swoje projekty jako otwarte oprogramowanie.

To właśnie dzięki pycarplay, carplay-receiver, FastCarPlay i innym podobnym projektom mogłem przejść tę drogę.

Moim zadaniem było zrozumienie istniejących rozwiązań, dostosowanie ich do własnej konstrukcji i uzyskanie stabilnego działania w samochodzie.

Co dalej

Dziś CaRadio działa już od kilku miesięcy w moim Volkswagenie Golfie.

W tym czasie przejechała tysiące kilometrów, a bezprzewodowy CarPlay stał się zwyczajnym elementem codziennych podróży.

Jednak za pozornie prostym interfejsem kryje się wiele ciekawych rozwiązań technicznych.

Jak Raspberry Pi komunikuje się z adapterem USB Carlinkit? Skąd pochodzi strumień wideo? Jak przesyłane są dźwięk i informacje o dotknięciach ekranu? I co dokładnie trzeba było zmienić, żeby wszystko działało we własnej aplikacji?

O tym wszystkim chciałbym opowiedzieć dokładniej w kolejnych artykułach.

Na razie najważniejsze jest jedno: oprogramowanie CaRadio nie powstało w jeden wieczór i nie zostało napisane od zera.

To rezultat kilku lat eksperymentów, nieudanych prób, analizowania cudzych projektów i stopniowego poszukiwania odpowiedniego rozwiązania.

I chyba właśnie ta część historii okazała się dla mnie najciekawsza.