Jak napisać testy jednostkowe robotów (i innych urządzeń mechanicznych)?

22

Jestem członkiem klubu robotyki w mojej szkole średniej i jestem odpowiedzialny za programowanie robota. Jedną z sugestii, które wciąż słyszę od różnych dorosłych, jest to, że powinienem pisać testy jednostkowe, aby pomóc w sprawdzeniu poprawności mojego kodu. Baza kodu staje się trochę duża i zgadzam się, że testy jednostkowe byłyby bardzo pomocne w szybszym wykrywaniu błędów.

Nie jestem jednak do końca pewien, jak to osiągnąć. Według mojej najlepszej wiedzy, testowanie jednostkowe odbywa się poprzez pobranie funkcji (lub podsystemu kodu) i dostarczenie jej zestawu danych wejściowych, aby upewnić się, że za każdym razem wychodzi z tym samym wyjściem. Kod, który obecnie posiadam, nie powoduje poważnych awarii danych, a raczej bezpośrednio manipuluje elementami sprzętowymi robota. Większość złożoności wynika z upewnienia się, że elektronika jest sprawna, że ​​kod w tej chwili odpowiada rzeczywistemu sprzętowi robota itp. Często widzę tylko problem z załadowaniem kodu do samego robota, i próba uruchomienia.

Jak można napisać testy jednostkowe kodu, który ma obsługiwać dowolne urządzenie mechaniczne? Wydaje mi się, że błędy można wychwycić tylko fizycznie obserwując działanie maszyny.

A może po prostu nie rozumiem, jak powinny działać testy jednostkowe?

( Jeśli to ma znaczenie, oto kod , jest napisany w C ++, a ja uczestniczę we FRC )

Michael0x2a
źródło

Odpowiedzi:

21

Będziesz musiał wyśmiewać warstwę sprzętową, aby wykonać to testowanie. Chodzi o to, że zamiast kodu rozmawiającego z rzeczywistym sprzętem, rozmawiasz z fałszywą wersją sprzętu, którą możesz kontrolować, a następnie używasz do sprawdzenia, czy kod działa poprawnie.

Niestety musisz rozwiązać niektóre problemy:

  • Wyśmiewanie rzeczy w językach stosunkowo niskiego poziomu jest trudniejsze (a tym samym znacznie więcej pracy)
  • Wyśmiewanie rzeczy na poziomie sprzętowym jest trudniejsze (a tym samym dużo więcej pracy)

Ponadto większość wartości zautomatyzowanych testów jednostkowych wynika z możliwości uruchomienia testów w dowolnym momencie w celu wykrycia błędów regresji przez długi czas po napisaniu oryginalnego kodu. W tego rodzaju konkursach Twój kod nie będzie w ogóle używany po zakończeniu konkursu, więc tak naprawdę nie uzyskasz większości wartości z testów. Biorąc pod uwagę, jak trudno byłoby dodać testy do konkretnego przypadku, lepiej byłoby poświęcić czas na wykonanie testów ręcznych i skupienie się na funkcjach konkursu.

Oleksi
źródło
1
Niezła odpowiedź. Zwłaszcza o tym, że kod nie będzie używany po zawodach i że ogromna korzyść z automatycznych testów jednostkowych przychodzi dużo po napisaniu testów. Możesz rozważyć zautomatyzowanie niektórych testów w przypadku, gdy wielokrotnie przeprowadzasz ten sam test; ale dopóki tak się nie stanie, nie ma większego sensu.
Dawood mówi, że przywróć Monikę
W ogóle nie trzeba kpić ze sprzętu. Jeśli robot ma logowanie, uruchom program testowy i obserwuj dzienniki. Ostatni test wymaga obserwacji „skręć w lewo” w dzienniku powinien odpowiadać tpo skrętu w lewo robota. Będziesz musiał napisać testową uprząż, aby wyśmiewać urządzenia wejściowe - podpiąć kod urządzenia wejściowego jak najbliżej warstwy sprzętowej
mattnz
4
@DavidWallace Trochę do namysłu, gdy używa się TDD / BDD, korzyści z testów jednostkowych pojawiają się natychmiast. Po pierwsze, zezwalając na natychmiastową pewną refaktoryzację kodu, a po drugie, zachęcając do ograniczania implementacji do minimalnej implementacji wymaganej do spełnienia testów.
S.Robins,
4
@mattnz zły pomysł i wiem z doświadczenia. Co jeśli testowany kod zawiedzie bardzo, bardzo mocno, a ramię robota rozbije się o ścianę, niszcząc kawałek sprzętu xxxx $ ???
stijn
2
@mattnz: Nasze roboty mają około 2 stopy na 3 stopy na 4 stopy i ważą około 150 funtów. Zestaw / rejestracja kosztuje 5 tysięcy dolarów rocznie i zwykle zbieramy kolejne 5 do 10 tysięcy na zakup dodatkowych części. Najgorszy scenariusz prawdopodobnie kosztowałby ponad 10 USD;)
Michael0x2a
10

Mogę wymyślić kilka rzeczy, które musisz rozważyć. Pierwszym z nich jest uczynienie warstwy dostępu sprzętowego tak cienką, jak to tylko możliwe, nawet jeśli oznacza to utworzenie dla niej podstawowej warstwy otoki. Daje to kilka zalet. Pierwszy polega na tym, że pozwala on odizolować specyficzne dla sprzętu zachowania twojego kodu od samego dostępu do sprzętu, co oznacza, że ​​możesz przetestować wszystko aż do samego dołu sprzętu bez konieczności uzyskiwania dostępu do samego sprzętu.

Na przykład, jeśli musisz zaprojektować protokół sygnalizacyjny oparty na I2C, możesz przetestować, czy Twój kod generuje poprawne sygnały I2C bez konieczności podłączania sprzętu do swoich testów.

W przypadku połączeń z rzeczywistym sprzętem możesz sprawdzić, czy zachowują się poprawnie, wyśmiewając warstwę sprzętową, i właśnie w tym przypadku opłaca się utrzymanie bardzo cienkiej warstwy sprzętowej, ponieważ możesz zredukować próbę do konieczności obsługi tylko minimalnych funkcji wymaganych do faktycznie adresują sprzęt, ale niekoniecznie musisz testować poszczególne sygnały, ponieważ wszystkie sygnały powinny być testowane na wyższym poziomie. Oznacza to, że używasz swojej makiety, aby sprawdzić, czy połączenia są wykonywane z wykorzystaniem określonych metod sprzętowych, które powodują wysyłanie sygnałów do sprzętu. Jeśli potrzebujesz sondować swój sprzęt, twoja próbka musi być w stanie wywoływać zdarzenia lub metody tylko w kodzie, ponieważ ponownie, sygnał zwrotny powinien być obsługiwany na wyższej warstwie.

Zasadniczo pasuje to do tego, co powiedział Oleksi w swojej odpowiedzi , ponieważ zwykle jest więcej pracy, aby wyśmiewać rzeczy na poziomie sprzętowym, jednak nie jest to takie trudne, jeśli trzymasz się możliwie najcieńszej warstwy minimalnego kodu / wywołania, którą możesz zrobić dla sprzęt komputerowy.

Jeśli masz kod, który przejdzie wszystkie testy, nadal będziesz musiał przeprowadzić serię testów ręcznych, aby upewnić się, że wszystko poprawnie skonfigurowałeś w warstwie sprzętowej.

Inną rzeczą, która przychodzi mi na myśl oprócz kpiny i nawarstwiania się, jest zastosowanie praktyki rozwoju w pierwszej kolejności. Zasadniczo kodujesz swoje wymagania jako kryteria testowe i opierasz swoją implementację na testach. Pomoże to zapewnić utrzymanie kodu implementacji na minimalnym poziomie, a jednocześnie upewnić się, że wszystkie przypadki testowe napędzają wysiłki programistyczne. Nie marnując zbyt wiele czasu na inny potencjalnie niekrytyczny kod, który może Cię kusić „tylko dlatego, że”, test najpierw pomaga zachować koncentrację i ułatwi zmianę kodu podczas debugowania, podobnie jak użycie swoich testów jednostkowych i próbnych. Debugowanie błędów oprogramowania przez sprzęt jest niezwykle skomplikowane i pochłania dużą ilość czasu, który lepiej byłoby poświęcić na inne zadania.

S.Robins
źródło
2

Mogę powiedzieć, jak to robią w symulatorach lotu

Po pierwsze, dostaniesz tylko połowę odpowiedzi, jeśli zadasz to pytanie tylko programistom, więc prawdopodobnie powinieneś zamieścić to na http://electronics.stackexchange.com, gdy jesteś przy nim.

Nie robiłem żadnej roboty z robotami, ale spędziłem 5 lat na tworzeniu sprzętu na symulatorach lotu, dzięki czemu mogę powiedzieć, jak działa ich architektura.

Warstwa sprzętowa jest głupia

Zawiera podstawowy interfejs, w którym można regulować proste wartości wejściowe / wyjściowe i ustawiać punkty przerwania interpolacji dla sygnałów analogowych. Kiedy pracujesz ze „świeżym” sprzętem, wszystko będzie działało zgodnie z oczekiwaniami, z niewielką lub żadną kalibracją, ale z czasem części ulegną zużyciu mechanicznemu i będą musiały zostać wyregulowane.

Kalibracja jest prostą tabelą zawierającą przekroje w zakresie od wartości min / maks. Aby zmierzyć na nich wejście, zwykle stosuje się serwo (np. Potencjometr liniowy, przetwornik, akcelerometry itp.). Lub w przypadku oprzyrządowania, po prostu wizualnie oceniasz dokładność i dostosowujesz do momentu skalibrowania.

Warstwa oprogramowania jest odwrotna

Wszystko jest złożone i powiązane ze sobą, dlatego ważne jest, aby wyodrębnić niektóre zmienne w celu przetestowania funkcjonalności. Wymyślanie scenariuszy związanych z bólem głowy nie jest konieczne, ponieważ o wiele łatwiej jest uruchomić realistyczne scenariusze, w których można gromadzić dane. Po uruchomieniu testów zasadniczo mierzysz przechowywane dane w porównaniu z bieżącym wyjściem.

W symulatorze lotów jest to określane jako QTG (Przewodnik po testach kwalifikacyjnych). U ich podstaw wykreślane są dane na siatce 2D, gdzie jeden wymiar to czas, a drugi to wynik.

Wierzcie lub nie, to esencja tego, jak opracowują modele. Prawdziwy samolot jest wyposażony w masę czujników i lata się wokół niego, wykonując kontrolowane scenariusze. Ponieważ wszystkie elementy sterujące mogą być sterowane bez interakcji człowieka, testy są uruchamiane (tzn. Sama karta leci) przez komputer i dane są porównywane.

Mimo że robotyka jest tworzona na znacznie inną skalę, zasady są takie same. Tradycyjne podejście polega na całkowitym oddzieleniu warstw sprzętowych i programowych, aby można je było przetestować osobno. Dane sprzętowe są gromadzone przez serwomechanizmy i ustawiane przez niezależny interfejs. Wejście oprogramowania można ustawić / odczytać, niezależnie mierząc i porównując sygnalizację, która w innym przypadku trafiłaby do sprzętu i wykreślając ją względem znanych „dobrych” danych.

Same testy niekoniecznie muszą być skomplikowane, o ile wyniki są przewidywalne, mierzalne i odtwarzalne.

Evan Plaice
źródło
1

Jak już wspomniano, wykpij i wytrzyj części sprzętowe. Na przykład, jeśli masz interfejs do robota, możesz dziedziczyć z tego interfejsu, a następnie wykonać proste jego implementacje. Następnie możesz przetestować, czy implementacja kodu pośredniczącego została wywołana zgodnie z oczekiwaniami. Jeśli jest to oczekiwane funkcje lub oczekiwane parametry.

martiert
źródło