Trwa konkurs "Ogól naczelnego", w którym codziennie możecie wygrać najnowsze maszynki systemowe Hydro Connect 5 marki Wilkinson Sword.

Więcej informacji
Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

System typu CarPi część 2, QML/C++

Witam wszystkich ponownie.

Poniżej na filmie prezentuję przepisany od nowa, z użyciem technologii QML + logika C++ amatorski system typu Car Pi (a przynajmniej ja go tak nazywam).

Oczywiście, jak to zwykle bywa system jest w fazie gruntownej budowy, co za tym idzie nie zdecydowałem się pokazać wszystkich funkcjonalności, żeby nie było jakiegoś Segmentation fault ;)

Sprzęt, na którym to wszystko działa to jeden Raspberry Pi 2 (jako główny sterownik) i po jednym Raspberry Pi B+ na kamerę (kamera Sony IMX219 do rpi). Do tego tani, chiński wyświetlacz z aliexpress za ok. 100 zł, moduł GPS z Kamami, modem Huawei E3131 do wysyłania danych o współrzędnych na serwer i oglądania youtube'a, oraz kilka innych gadżetów. Na filmie prezentuję w postaci developerskiej, bez obudowy, ponieważ cały czas dokonuję pewnych modyfikacji w bebechach.

Od strony programowej:

Na sterowniku głównym i kamerach Raspbian Jessie. Własnoręcznie skompilowane Qt 5.7.0, QtGstreamer i kilka innych, też ważnych komponentów.

Do poprawnego działania touchscreen'a jest potrzebny tslib, czyli biblioteka obsługująca panele dotykowe, w moim przypadku model Bus 001 Device 004: ID 0eef:0001 D-WAV Scientific Co., Ltd eGalax TouchScreen

1. Odtwarzanie/nagrywanie obrazu z kamer zamontowanych z przodu i z tyłu pojazdu

Zdecydowałem się, żeby przesyłać obraz w chyba najbardziej powszechnym standardzie, mianowicie h264. Na kamerach jest zainstalowany prosty soft obsługujący autorejestrację kamery w systemie, oraz obsługujący raspivid'a i gstreamera.
Śmiało można skorzystać ze zwykłego pipelina uruchamianego z basha, ale chciałem mieć możliwość zmiany pewnych parametrów obrazu, czego uruchomiony z basha raspivid nie umożliwia.

raspivid -t 0 -w 1280 -h 720 -fps 30 -n -b 10000000 -o - | gst-launch-1.0 -vvv fdsrc ! h264parse ! rtph264pay config-interval=1 pt=96 ! udpsink host=225.0.0.0 port=2050 sync=false

Po stronie sterownika sprawa była trochę bardziej skomplikowana. Standardowy playbin gstreamerowy nie "łyka" strumieni RTP. Ze strumieniem RTSP miałem taki problem, że opóźnienia obrazu sięgały po kilka sekund. I co tu zrobić...

Z pomocą przychodzi być może niektórym znany QtGstreamer. Jest to binding C++ gstreamera. Strona domowa projektu: https://gstreamer.freedesktop.org/modules/qt-gstreamer.html

W przykładach znalazłem, jak odtwarzać coś playbinem (wszyscy uczepili się tego playbina). Nic o strumieniach RTP. Dlatego musiałem trochę pokminić i w końcu wyszło !
Zapodaję fragment kodu:

bool StreamPlayer::setUri(const QString &host, const QString &port) { if (streamContainer.count() == 0) return false; stop(); if (m_pipeline.isNull() && !m_videoSink.isNull()) { m_pipeline = QGst::Parse::launch(QString("udpsrc name=src multicast-iface=eth0 address=%1 port=%2 caps=\"application/x-rtp\" ! rtph264depay ! h264parse disable-passthrough=true ! omxh264dec name=omx").arg(host).arg(port)).dynamicCast<QGst::Pipeline>(); if (!m_pipeline.isNull()) { udpsrc = m_pipeline->getElementByName("src"); if (udpsrc.isNull()) return false; udpsrc->setProperty("timeout", UDPSRC_TIMEOUT); omx = m_pipeline->getElementByName("omx"); if (omx.isNull()) return false; m_videoSink->setProperty("sync", false); m_pipeline->add(m_videoSink); omx->link(m_videoSink); QGst::BusPtr bus = m_pipeline->bus(); bus->addSignalWatch(); return QGlib::connect(bus, "message", this, &StreamPlayer::onBusMessage); } else return false; } return false; }

Rzecz polega na tym, że trzeba pobrać element dekodera i zlinkować go z sinkiem, który to jest elementem wyświetlającym obraz w kontrolce QMLowej. Udało się, co widać na filmie.

Nagrywanie video wygląda tak od strony gstreamer'a:

void StreamRecorder::setStream(QString host, QString port, QString location) { bin = QGst::Bin::fromDescription(QString("udpsrc multicast-iface=eth0 address=%1 port=%2 caps=\"application/x-rtp\" ! rtpjitterbuffer latency=1 ! rtph264depay ! h264parse ! matroskamux ! filesink sync=false location=%3 name=sink").arg(host).arg(port).arg(location)); if (!m_pipeline) { m_pipeline = QGst::Pipeline::create(); m_pipeline->add(bin); if (m_pipeline) { QGst::BusPtr bus = m_pipeline->bus(); bus->addSignalWatch(); QGlib::connect(bus, "message", this, &StreamRecorder::onBusMessage); } else { qCritical() << "Failed to create the pipeline"; } } }

bool StreamRecorder::start() { if (m_pipeline) { if (m_pipeline->setState(QGst::StatePlaying) == QGst::StateChangeSuccess) return true; } return true; }

2. Radio internetowe

W przypadku radia internetowego sprawa była dosyć prosta i faktycznie wystarczył poczciwy playbin. Radio to nic innego jak strumień mp3, który playbin "łyka". Kilka prostych kontrolek typu ListView i komponent Audio

import QtMultimedia 5.7 Audio { id: radioPlayer onPlaying: { toolbarRadioImage.show() streamPlayButtonImage.visible = true radioMetaDataTimer.running = true } onStopped: { toolbarRadioImage.hide() streamPlayButtonImage.visible = false radioMetaDataTimer.running = false radioTitleText.text = "" } }

i lista stacji radiowych, póki co w ListModel:

import QtQuick 2.0 ListModel { id: radioModel ListElement { name: "Radio Rzeszów" url: "http://radiointernetowe.net:9500/;?.mp3" image: "file:///home/pi/radio/radiorzeszow.jpg" } ListElement { name: "Radio Plus" url: "http://s3a.deb1.scdn.smcloud.net/t051-1.mp3" image: "file:///home/pi/radio/plusradio.jpg" } .....

Część stacji radiowych w swoim strumieniu umieszcza tak zwane meta data, czyli dane o np. tytule granego utworu lub nazwę audycji. Kontrolka Audio z QtMultimedia umożliwia pobranie takich danych:

radioTitleText.text = radioPlayer.metaData.title

Nie wszystkie stacje to nadają, a niektóre w ogóle nadają tytuł w innych właściwościach niż title, więc nie dociekałem, która stacja radiowa wypełnia prawidłowo swoje dane i w przypadku braku tytułu nie wyświetlam nic.

3. Odtwarzanie filmów

Sytuacja dosyć ciekawa, ponieważ mało inteligentny playbin sam dobiera sobie za pomocą priorytetów wtyczek elementy potrzebne do odtworzenia konkretnego materiału.
Już myślałem, że nic z tego nie będzie, ponieważ mając zainstalowaną wtyczkę gstreamer1.0-libav playbin odtwarzał mi video bez akceleracji sprzętowej (bez omxh264dec). Trzeba to wyrzucić (sudo apt-get purge gstreamer1.0-libav). Trzeba również wyrzucić gstreamer1.0-vaapi i po problemie. Playbin powinien odtwarzać h264 za pomocą wtyczki omxh264dec. Osadzenie video w QMLu to już banalna sprawa:

Video { anchors.fill: parent id: video width : 800 height : 450 fillMode: VideoOutput.Stretch visible: true ....

4. Youtube

Dużo by pisać, więc będzie w skrócie.

Użyłem klawiatury ekranowej z Qt (import QtQuick.VirtualKeyboard 2.1). Zapytania do Youtube'a wysyłam za pomocą Youtube Data API v3, czy jak to tam się nazywa => https://developers.google.com/youtube/v3/

onAccepted: { request('https://www.googleapis.com/youtube/v3/search?part=snippet&q=' + text + '&maxResults=10&type=video&key=TWÓJ KLUCZ DO API', function (o) { //console.log("text: " + text); // log the json response if (o.responseText.length >= 0) { listVideos.model.clear() jsonModel1.query = "$.items[*]" jsonModel1.json = o.responseText jsonModel1.updateJSONModel() console.log(o.responseText); } }); }

a w odpowiedzi otrzymuję JSON'a, którego należy sobie sparsować i wrzucić do kontrolki ListView. Odpowiedź dla zapytania "Abc" wygląda tak (na filmie użyłem tego przykładu):

{ "kind": "youtube#searchListResponse", "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/Dx5Bc6s3ApegoIShHqIxhKtArjc\"", "nextPageToken": "CAoQAA", "regionCode": "PL", "pageInfo": { "totalResults": 1000000, "resultsPerPage": 10 }, "items": [ { "kind": "youtube#searchResult", "etag": "\"gMxXHe-zinKdE9lTnzKu8vjcmDI/93TOo770hWgptbMI_yPH_ahckgM\"", "id": { "kind": "youtube#video", "videoId": "_UR-l3QI2nE" }, "snippet": { "publishedAt": "2014-05-01T11:12:58.000Z", "channelId": "UCbCmjCuTUZos6Inko4u57UQ", "title": "ABC SONG | ABC Songs for Children - 13 Alphabet Songs & 26 Videos", "description": "ABC Song and Alphabet Song Ultimate kids songs and baby songs Collection with 13 entertaining \"English abcd songs\" and 26 a to z fun Alphabet episodes, ...", "thumbnails": { "default": { "url": "https://i.ytimg.com/vi/_UR-l3QI2nE/default.jpg", "width": 120, "height": 90 }, "medium": { "url": "https://i.ytimg.com/vi/_UR-l3QI2nE/mqdefault.jpg", "width": 320, "height": 180 }, "high": { "url": "https://i.ytimg.com/vi/_UR-l3QI2nE/hqdefault.jpg", "width": 480, "height": 360 } }, "channelTitle": "ABCkidTV - Nursery Rhymes", "liveBroadcastContent": "none" } },

Mamy tutaj tytuł, opis, datę publikacji i thumbnailsy do filmików. W zasadzie to wystarczy.

Po naciśnięciu na obrazek filmu, po prawej stronie pokazuje się ten obrazek, a pod nim tytuł filmu. Jeszcze tylko kliknąć na ten obrazek i odtwarzamy video z Youtube'a !

Do wyświetlenia Youtube'a użyłem dosyć świeżego pomysłu developerów Qt, mianowicie kontrolki WebEngineView, która potrafi być czasem niestabilna i ciężko ją skompilować z ffmpeg, który by to dawał sprzętowe wsparcie dekodowania h264 w HTML5. Cóż, przy takiej rozdzielczości, jak wyświetlacz sterownika (800x480) nie potrzebuję ani 1080p, ani 4K ;) (ale nie ukrywam, pracuję nad tym.. ;)

WebEngineView { id: webView anchors.fill: parent opacity: 0 url: "" onLoadingChanged: { switch (loadRequest.status) { case WebEngineView.LoadSucceededStatus: animationWebLoading.visible = false webView.visible = true return case WebEngineView.LoadStartedStatus: webView.visible = false animationWebLoading.visible = true break case WebEngineView.LoadStoppedStatus: break case WebEngineView.LoadFailedStatus: break } } onFullScreenRequested: { if (request.toggleOn) { webView.state = "FullScreen" } else { webView.state = "" } request.accept() } }

5. Przeglądarka internetowa

Jest to również funkcjonalność oparta na kontrolce WebEngineView i bawię się tym i traktuję raczej jako ciekawostkę, ponieważ jak już wcześniej wspominałem, jest to element nieco niedopracowany, dodatkowo moc obliczeniowa RPi2 nie pozwala na płynne przeglądanie stron internetowych.

Inne

Projekt jest, jak sami widzicie w fazie rozwojowej. To, czego przede wszystkim nie widać na ekranie to logika oprogramowania zaszyta w kodzie. Podpinanie pendrive'a do usb, wysyłanie współrzędnych na serwer, czytanie parametrów z OBD2 samochodu, obsługa modemu (siła sygnału, sieć, do której się karta sim zarejestrowała) i wiele, wiele innych.

Dużo problemów sprawiają elementy opensource'owe, bo tylko z takich korzystam i niejednokrotnie były potrzebne pewne modyfikacje kodu, aby coś zaczęło działać.

Brakuje jeszcze odtwarzania muzyki z pendrive'a, wizualizacji OBD2 i panelu z ustawieniami, ale kto wie, co przyniesie 2017 rok, być może więcej czasu ;)

Do tego wszystkiego dochodzi obudowa na wyświetlacz, przetwornica 12V/5V do zasilenia urządzeń i koncepcja, jak to wszystko umieścić w samochodzie.

Jeśli coś wydało Ci się niejasne, jeśli masz jakieś pytania, zadawaj je śmiało w komentarzach. Z pewnością coś pominąłem, z pewnością nie wszystko do końca opisałem. Również, jeśli wydaje Ci się, że się w czymś pomyliłem i coś przekręciłem, napisz.

Pozdrawiam i dziękuję za poświęcony na przeczytanie tego wpisu czas !

A poniżej filmik z prezentacją systemu ;)

 

linux programowanie urządzenia mobilne

Komentarze

0 nowych
Waka   10 #1 20.12.2016 09:34

O popatrz... a wczoraj rozmyślałem nad tym jak najlepiej skręcić własnego carputera :P Także dzięki kumplu, sporo mi ułatwiłeś. A... jeśli myslałeś o zamontowaniu sprzętu w 2DIN to pewnie przydałaby się ładna obudowa, znalazłem coś takiego:
https://www.mo-co-so.com/Replacement-Housing-Lilliput-669GL-p/mcs-lil-669-rfh.htm
Myślałem też o Malince z przeportowanym Androidem, ale wygodny i ładny OS ma swoją cenę, jest ciężko konfigurowalny.
Edit: Niby jest Android Things, ale z tego co widzę to nie do końca działa to tak jakbym chciał :/

Autor edytował komentarz w dniu: 20.12.2016 09:57
zoolek   3 #2 20.12.2016 10:16

@Waka: Myślałem o zamontowaniu w 2DIN, jednak koncepcja mi się trochę zmieniła, ponieważ ostatnio zmieniłem samochód z meganki na mazdę 3, a tam już nie ma gdzie tego wszystkiego umieścić i potrzebny jest uchwyt na szybę. Co do obudowy, kupiłem w piekarzu takie coś, wyciąłem otwór na lcd i w środku będe umieszczał kilka bebechów => https://1drv.ms/f/s!AsKOECY0S1BibDjr7af5fbc_hzo

a link do sklepu z obudową: http://www.piekarz.pl/pl/?item=40118

Waka   10 #3 20.12.2016 12:01

@zoolek: Ach, już rozumiem ;) Fajny pomysł i w sumie takie podejście znacznie upraszcza. Przy 2DIN jest niestety więcej zabawy. Gotowe obudowy są absurdalnie drogie (przykładowo ta od iCarusa kosztuje... 340 złotych, czyli więcej niż Malinka z wyświetlaczem), a półprodukty trzeba dostosowywać :P

Swoją drogą co z przyciskami? Włącznik mimo wszystko, by się przydał ;)

Co do mojego pomysłu z Androidem to wygląda na to, że jednak jest nadzieja. Podobno zewnętrzne lokalizatory na USB działają z tym systemem na zasadzie Plug&Play, a dynksy z modemami LTE podobno da się obsłużyć przez USB jeśli się zrootuje sprzęt. To znacznie ułatwiałoby mi ewentualną zabawę ;)

zoolek   3 #4 20.12.2016 12:28

@Waka: Przyciski do sterowania jasnością i kontrastem lcd będą z przodu obudowy, na osobnej płytce. Co do powera, również o tym pomyślałem.

Jeśli chodzi o Twój projekt na Androidzie.. Cóż, nie jestem fanem tego systemu, a tym bardziej przeraża mnie Java, chyba, że planujesz Qt/QML.

Zewnętrzne moduły GPS nie różnią się wiele od tych wbudowanych np. w telefon. Najczęściej taki GPS jest widziany w systemie jako /dev/ttyUSB* i dają na wyjściu standardowy protokół NMEA. Możesz wtedy sobie to sparsować albo skorzystać z gotowej biblioteki http://www.catb.org/gpsd/libgps.html po uprzednim skonfigurowaniu demona gpsd.

Co do modemów na USB - nie wiem, jak to jest w kernelu androidowym, ale pewnie podobnie jak na zwykłym linuxowym jajku. Są drivery - przeważnie działa i udostępnia jakiś ttyUSB do komunikacji za pomocą komend AT. Wtedy pobranie siły sygnału i w ogóle komunikacja z takim modemem to już kwestia czasu i chęci.

Waka   10 #5 20.12.2016 15:14

@zoolek: Co do Androida to powiem tak, łączy mnie z tym systemem szorstka przyjaźń. Jeśli chodzi o względy użytkowe to jest fajny, ale jak chce się coś zaawansowanego, nie daj Bóg programistycznego, to przestaje być miło. Przykładowo nasłuchiwanie BT wymaga okodowania wszystkiego od socketów na adapterach kończąc, jak w starym, dobrym C++ ;)

Javy też nie lubię, w sumie to chyba nikt za nią nie przepada. Osobiście jestem zwolennikiem jej młodszego kuzyna, C#, ale myk polega na tym, że jak się uda sparować Androida z GPS-em i modemem to już nic więcej nie byłoby trzeba, bo system sam z siebie przystosowany do użytku "radiowego". Znalazłem na Allegro modemy, które rzekomo współpracują z Androidem, ale nie wiem na ile to realne.
http://allegro.pl/modem-3g-hspa-media-tech-mt4210-3-6-mbps-android-i6377843089.html

Waka   10 #6 20.12.2016 15:41

Hmm... wygląda na to, że od Marshmallowa Android sam z siebie powinien ogarnąć Internet wciśnięty przez USB. Jeśli to prawda to sprawa ogranicza się do złożenia wszystkiego w jedną całość... no i dogrania Car Launchera ;)

  #7 20.12.2016 20:21

Hmm drogo, za 100Eu kupiłem lusterko z wyświetlaczem 7 cali i mam wszystko w komlecie + 10Eu elm327 v 1.5 z wyłącznikiem i WIFI (wada jest taka że lusterko po bluetooth czyta tylko telefony)
(to nie jest chamska nakładka na lusterko)
http://aliexpress.com/store/product/Junsun-7-Touch-Special-Car-DVR-Camera-Mirror...

Rosjanie to oczywiście pierwsi rozpracowali są custom romy ,przeróbki itd.
http://4pda.ru/forum/index.php?showtopic=743305

Tak to wygląda
https://www.youtube.com/watch?v=WvbvpiGGu84


Rosyjski "Redpower AMD65" to to samo ma lepszy rom ale ponad 2x droższy
https://www.youtube.com/watch?v=I0fu2FnprPM

  #8 21.12.2016 09:56

@janex66 (niezalogowany)

Polskie Janusze biznesu też mają lusterka tylko że poprzedniej generacji które u chińczyka można wyrwać w promo po 60-70EU uny mają po 400Eu
http://orllo.pl/rejestrator-wideo-nawigacja-w-lusterku-lx-400gts-pro.html
Reklama: Oszczędź nawet 5357zł !!! :)

Takie bezramkowe jak w autach Tesla i z 3G pewnie będą mieć za 3 lata w cenie 700Eu :), kiedy one na dniach do 140EU stanieją.
https://www.aliexpress.com/store/product/Junsun-7-3G-Touch-Special-Car-DVR-Camer...

Waka   10 #9 26.12.2016 15:27

@janex66 (niezalogowany): Android w lusterku? Tylko Rosjanie mogli na coś takiego wpaść :P Acz biorąc pod uwagę co oferuje to nawet niedrogo wychodzi, oczywiście na Ali, bo w Polsce ceny są mistrzowsko przyjanuszowane... co zresztą widać na pokazanym przez Ciebie przykładzie. 2dinowe radyjka z Androidem zaczynają się na Allegro od 800zł i to bez bajerów typu WiFi, BT czy GPS (a wbudowanego modemu to chyba żaden nie ma), a jakby samemu chciało się takie coś złożyć to zamknęłoby się w 500zł i to po cenach sklepowych (150zł Malinka, 150zł wyświetlacz, 200zł na akcesoria). Dlatego powoli korci mnie do zbudowania takiego zestawu samodzielnie :P

Gratulacje!

znalezione maszynki:

Twój czas:

Ogól Naczelnego!
Znalazłeś(aś) 10 maszynek Wilkinson Sword
oraz ogoliłaś naszego naczelnego!
Przejdź do rankingu
Podpowiedź: Przyciśnij lewy przycisk myszki i poruszaj nią, aby ogolić brodę.