W ostatnich tygodniach nieco więcej skupiłem się na pisaniu postów na bloga niż na samym projekcie, nie znaczy to jednak że go odłożyłem. Ponieważ udało mi się kilka tygodni temu podgonić trochę tematy związane z komunikacją, nadal z grubsza biorąc mieszczę się w założonych ramach czasowych.
Gotowe jest już większość kodu Arduino (poza częścią związaną z autonomią poruszania się robota) i w zasadzie w większości mam gotową aplikację desktopową WPF do komunikacji i sterowania robotem. Zdecydowałem się prototypować i testować pewne rozwiązania w technologii, którą dobrze znam (WPF), aby nie prowadzić research-u na zbyt wielu rzeczach na raz w momencie przygotowywania aplikacji Xamarin.
Aplikację testowałem z nodemcu wypiętym z płytki prototypowej. Odpowiedzi na komendy po jego stronie obserwowałem za pomocą monitora portu szeregowego.
Kolejnym etapem będzie oczywiście (na reszcie 🙂 ) zmontowanie całości robota i testowanie sterowania ręcznego, już na zmontowanym prototypie, właśnie z aplikacji desktopowej.
Wykorzystałem trzy biblioteki:
ZeroConf – opisywaną już we wcześniejszych postach, która pozwala mi na wykrycie robota w sieci i pozyskanie jego adresu IP, lub na wykrycie że znajduje się on w trybie Access Point.
Mahapps.metro – która pozwala mi łatwo stylizować kontrolki WPF właśnie na styl Metro. Zawsze to troszkę ładniej wygląda niż klasyczne przyciski i okienka 🙂
Xunit.net – tę bibliotekę wykorzystałem do testów. Nie miałem z nią żadnego doświadczenie do tej pory, zawsze korzystałem z NUnit. Pomyślałem, że przy okazji konkursu warto spróbować czegoś innego. Póki co nie widzę jakichś wyraźnych zalet czy różnic w stosunku do NUnit. Inna sprawa, że ze względu na małą złożoność projektu testy nie są zbyt ambitne.
Zainteresowanych kodem zapraszam oczywiście na github.
Skorzystałem z interaction triggers, przypisując do przycisków wymagane zdarzenia (wciśnięcie przycisku myszki, puszczenie przycisku myszki) łącząc je z odpowiednimi komendami:
<i:Interaction.Triggers> <i:EventTrigger EventName="PreviewMouseLeftButtonDown"> <i:InvokeCommandAction Command="{Binding CForwardStart}" /> </i:EventTrigger> <i:EventTrigger EventName="PreviewMouseLeftButtonUp"> <i:InvokeCommandAction Command="{Binding CForwardStop}" /> </i:EventTrigger> </i:Interaction.Triggers>
W ViewModel używam takiego trochę brzydkiego rozwiązania. Wciśnięcie przycisku ustawia odpowiednią zmienną bool na true i wysyła asynchronicznie komunikat UDP do momentu ustawienia tej zmiennej na false. Może to rozwiązanie nie jest zbyt piękne. Ale na chwilę obecną jest good enough :).
Tak to wygląda w ViewModelu:
private async void CForwadStartExecute() { if (!_isConnected) return; _isForward = true; var uco = new UdpCommOperations(_robotIp); while (_isForward) await Task.Run(() => uco.SendCommand(UdpRobotCommand.Forward)); } private void CForwadStopExecute() { _isForward = false; }
Poniżej gif, prezentujący działającą komunikację pomiędzy aplikacją a nodemcu. (lepsza jakość po kliknięciu w obrazek).
Gif-a wykonałem za pomocą świetnej darmowej aplikacji ScreenToGif – polecam.